88#include < fstream>
99#include < chrono>
1010
11- #include < boost/random.hpp>
12- #include < boost/integer_traits.hpp>
1311
1412#include < core/parallel/pthread_tools.hpp>
1513#include < core/parallel/atomic.hpp>
2927namespace turi {
3028 namespace random {
3129
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-
5730 /* *
5831 * A truely nondeterministic generator
5932 */
@@ -64,81 +37,33 @@ namespace turi {
6437 return global_gen;
6538 }
6639
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+
10949 // 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)();
12754 }
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;
13557 };
13658 // nondet_generator global_nondet_rng;
13759
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+ }
14267
14368 /* *
14469 * This class represents a master registery of all active random
@@ -301,12 +226,10 @@ namespace turi {
301226 // Get the global nondeterministic random number generator.
302227 nondet_generator& nondet_rnd (nondet_generator::global ());
303228 mut.lock ();
229+
304230 // 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+
310233 mut.unlock ();
311234 }
312235
0 commit comments