hpx_emulation/emulation/
rand.rs1use std::{
2 cell::Cell,
3 collections::hash_map::RandomState,
4 hash::{BuildHasher, Hasher},
5 num::Wrapping,
6};
7
8use strum::VariantArray;
9
10use super::{Emulation, EmulationOS, EmulationOption};
11
12fn fast_random() -> u64 {
14 thread_local! {
15 static RNG: Cell<Wrapping<u64>> = Cell::new(Wrapping(seed()));
16 }
17
18 #[inline]
19 fn seed() -> u64 {
20 let seed = RandomState::new();
21
22 let mut out = 0;
23 let mut cnt = 0;
24 while out == 0 {
25 cnt += 1;
26 let mut hasher = seed.build_hasher();
27 hasher.write_usize(cnt);
28 out = hasher.finish();
29 }
30 out
31 }
32
33 RNG.with(|rng| {
34 let mut n = rng.get();
35 debug_assert_ne!(n.0, 0);
36 n ^= n >> 12;
37 n ^= n << 25;
38 n ^= n >> 27;
39 rng.set(n);
40 n.0.wrapping_mul(0x2545_f491_4f6c_dd1d)
41 })
42}
43
44impl Emulation {
45 #[inline]
65 pub fn random() -> EmulationOption {
66 let emulation = Emulation::VARIANTS;
67 let emulation_os = EmulationOS::VARIANTS;
68 let rand = fast_random() as usize;
69 EmulationOption::builder()
70 .emulation(emulation[rand % emulation.len()])
71 .emulation_os(emulation_os[rand % emulation_os.len()])
72 .build()
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use std::{sync::Arc, thread};
79
80 use parking_lot::Mutex;
81
82 use super::*;
83
84 #[test]
85 fn test_concurrent_get_random_emulation() {
86 const THREAD_COUNT: usize = 10;
87 const ITERATIONS: usize = 100;
88
89 let results = Arc::new(Mutex::new(Vec::new()));
90
91 let mut handles = vec![];
92
93 for _ in 0..THREAD_COUNT {
94 let results = Arc::clone(&results);
95 let handle = thread::spawn(move || {
96 for _ in 0..ITERATIONS {
97 let emulation = Emulation::random();
98 let mut results = results.lock();
99 results.push(emulation);
100 }
101 });
102 handles.push(handle);
103 }
104
105 for handle in handles {
106 handle.join().expect("worker thread panicked");
107 }
108
109 let results = results.lock();
110 println!("Total results: {}", results.len());
111 }
112}