8
8
#include < fstream>
9
9
#include < chrono>
10
10
11
- #include < boost/random.hpp>
12
- #include < boost/integer_traits.hpp>
13
11
14
12
#include < core/parallel/pthread_tools.hpp>
15
13
#include < core/parallel/atomic.hpp>
29
27
namespace turi {
30
28
namespace random {
31
29
32
- /* * Get as close to a true source of randomness as possible.
33
- *
34
- * nanoseconds clock from program start. This should be pretty good.
35
- *
36
- * In case subsequent calls on a platform that does not support nanosecond resolution
37
- * happen, also increment a base count to make sure that subsequent seeds
38
- * are never the same.
39
- *
40
- * hash all these together to get a final seed hash.
41
- */
42
- uint64_t pure_random_seed () {
43
- static auto base_start_time = std::chrono::high_resolution_clock::now ();
44
- static uint64_t base_seed = hash64 (time (NULL ));
45
- static atomic<uint64_t > base_count = 0 ;
46
-
47
-
48
- ++base_count;
49
-
50
- auto now = std::chrono::high_resolution_clock::now ();
51
-
52
- uint64_t cur_seed = std::chrono::duration_cast<std::chrono::nanoseconds>(now-base_start_time).count ();
53
-
54
- return hash64 (base_seed, hash64 (cur_seed, base_count));
55
- }
56
-
57
30
/* *
58
31
* A truely nondeterministic generator
59
32
*/
@@ -64,81 +37,33 @@ namespace turi {
64
37
return global_gen;
65
38
}
66
39
67
- typedef size_t result_type;
68
- BOOST_STATIC_CONSTANT (result_type, min_value =
69
- boost::integer_traits<result_type>::const_min);
70
- BOOST_STATIC_CONSTANT (result_type, max_value =
71
- boost::integer_traits<result_type>::const_max);
72
- result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return min_value; }
73
- result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return max_value; }
74
-
75
- nondet_generator () {
76
- #ifndef _WIN32
77
- rnd_dev.open (" /dev/urandom" , std::ios::binary | std::ios::in);
78
- ASSERT_TRUE (rnd_dev.good ());
79
- #else
80
- auto rnd_dev_ret = CryptAcquireContext (&rnd_dev,
81
- NULL ,
82
- NULL ,
83
- PROV_RSA_FULL,
84
- 0 );
85
- if (!rnd_dev_ret) {
86
- auto err_code = GetLastError ();
87
- if (err_code == NTE_BAD_KEYSET) {
88
- if (!CryptAcquireContext (&rnd_dev,
89
- NULL ,
90
- NULL ,
91
- PROV_RSA_FULL,
92
- CRYPT_NEWKEYSET)) {
93
- } else {
94
- err_code = GetLastError ();
95
- log_and_throw (get_last_err_str (err_code));
96
- }
97
- } else {
98
- log_and_throw (get_last_err_str (err_code));
99
- }
100
- }
101
- #endif
102
- }
103
- // Close the random number generator
104
- #ifndef _WIN32
105
- ~nondet_generator () { rnd_dev.close (); }
106
- #else
107
- ~nondet_generator () { CryptReleaseContext (rnd_dev, 0 ); }
108
- #endif
40
+ nondet_generator ()
41
+ : _random_devices(thread::cpu_count())
42
+ {}
43
+
44
+ typedef unsigned int result_type;
45
+
46
+ static constexpr result_type min () { return std::numeric_limits<unsigned int >::min (); }
47
+ static constexpr result_type max () { return std::numeric_limits<unsigned int >::max (); }
48
+
109
49
// read a size_t from the source
110
- result_type operator ()() {
111
- // read a machine word into result
112
- result_type result (0 );
113
- #ifndef _WIN32
114
- mut.lock ();
115
- ASSERT_TRUE (rnd_dev.good ());
116
- rnd_dev.read (reinterpret_cast <char *>(&result), sizeof (result_type));
117
- ASSERT_TRUE (rnd_dev.good ());
118
- mut.unlock ();
119
- // std::cerr << result << std::endl;
120
- return result;
121
- #else
122
- mut.lock ();
123
- ASSERT_TRUE (CryptGenRandom (rnd_dev,8 ,(BYTE *)&result));
124
- mut.unlock ();
125
- return result;
126
- #endif
50
+ inline result_type operator ()() {
51
+ int thread_id = thread::thread_id ();
52
+
53
+ return _random_devices.at (thread_id)();
127
54
}
128
- private:
129
- #ifndef _WIN32
130
- std::ifstream rnd_dev;
131
- #else
132
- HCRYPTPROV rnd_dev;
133
- #endif
134
- mutex mut;
55
+
56
+ std::vector<std::random_device> _random_devices;
135
57
};
136
58
// nondet_generator global_nondet_rng;
137
59
138
-
139
-
140
-
141
-
60
+ /* * Use the C++11 standard generato to get as close to a true source of randomness as possible.
61
+ *
62
+ * Returns a 64 bit truely random seed.
63
+ */
64
+ uint64_t pure_random_seed () {
65
+ return hash64_combine (hash64 (nondet_generator::global ()()), hash64 (nondet_generator::global ()()));
66
+ }
142
67
143
68
/* *
144
69
* This class represents a master registery of all active random
@@ -301,12 +226,10 @@ namespace turi {
301
226
// Get the global nondeterministic random number generator.
302
227
nondet_generator& nondet_rnd (nondet_generator::global ());
303
228
mut.lock ();
229
+
304
230
// std::cerr << "initializing real rng" << std::endl;
305
- real_rng.seed (static_cast <uint32_t >(nondet_rnd ()));
306
- // std::cerr << "initializing discrete rng" << std::endl;
307
- discrete_rng.seed (static_cast <uint32_t >(nondet_rnd ()));
308
- // std::cerr << "initializing fast discrete rng" << std::endl;
309
- fast_discrete_rng.seed (static_cast <uint32_t >(nondet_rnd ()));
231
+ m_rng.seed (static_cast <uint32_t >(nondet_rnd ()));
232
+
310
233
mut.unlock ();
311
234
}
312
235
0 commit comments