61 if (
"quick" != firstTok (arg))
75 auto do_nothing = []{ };
76 auto mersenne64 = []{
return rani(); };
77 auto legacy_gen = []{
return rand(); };
78 std::random_device entropySource{
"/dev/urandom"};
79 auto rly_random = [&]{
return entropySource(); };
81 _Fmt resultDisplay{
"µ-bench(%s)%|45T.| %5.3f µs"};
84 cout << resultDisplay %
"(empty call)" % d1 <<endl;
87 cout << resultDisplay %
"Mersenne-64" % d2 <<endl;
90 cout << resultDisplay %
"std::rand()" % d3 <<endl;
93 cout << resultDisplay %
"/dev/urandom" % d4 <<endl;
95 CHECK (d3 < d2 and d2 < d4);
113 template<
typename GEN, u
int threads>
117 deque<tuple<double,uint>> results;
120 recordRun (
double err, uint fails)
123 results.emplace_back (err, fails);
130 : generator{move (fun)}
135 using ResVal =
typename GEN::result_type;
136 ResVal expect = (GEN::max() - GEN::min()) / 2;
139 double percentGlitches{0.0};
140 double percentTilted {0.0};
141 bool isFailure {
false};
147 auto drawRandom = [&]()
151 for (uint i=0; i<N; ++i)
153 auto r = generator();
154 if (r < GEN::min() or r > GEN::max())
158 auto error = avg/expect - 1;
159 recordRun (
error, fail);
162 threadBenchmark<threads> (drawRandom, REPEATS);
164 uint cases{0}, lows{0}, glitches{0};
165 _Fmt resultLine{
"%6.3f ‰ : %d %s"};
166 for (
auto [err,fails] : results)
168 bool isGlitch = fails or fabs(err) > 3 * 1/sqrt(N);
169 cout << resultLine % (err*1000)
171 % (fails?
"FAIL": isGlitch?
" !! ":
"") << endl;
174 if (isGlitch) ++glitches;
177 percentGlitches = 100.0 * glitches/cases;
178 percentTilted = 100.0 * fabs(
double(lows)/cases - 0.5)*2;
179 isFailure = glitches or percentTilted > 30;
180 cout <<
_Fmt{
"++-------------++ %s\n" 181 " Glitches: %5.1f %%\n" 182 " Tilted: %5.1f %%\n" 183 "++-------------++\n"}
184 % (isFailure?
"FAIL":
"(ok)")
202 using Mersenne64 = std::mt19937_64;
203 using Mersenne32 = std::mt19937;
212 concurr_mers32.perform();
213 concurr_mers64.perform();
214 concCap_mers32.perform();
216 CHECK (not single_mers32.isFailure,
"ALARM : single-threaded Mersenne-Twister 32bit produces skewed distribution");
217 CHECK ( concurr_mers32.isFailure,
"SURPRISE : Mersenne-Twister 32bit encountered NO glitches under concurrent pressure");
218 CHECK ( concurr_mers64.isFailure,
"SURPRISE : Mersenne-Twister 64bit encountered NO glitches under concurrent pressure");
Facility for monitor object based locking.
const uint NUM_THREADS
for concurrent probes
void investigate_concurrentAccess()
const uint NUM_SAMPLES
overall number measurement runs
void perform()
run the experiment series
int rani(uint bound=_iBOUND())
scoped guard to control the actual locking.
Functions to perform (multithreaded) timing measurement on a given functor.
Helpers typically used while writing tests.
A front-end for using printf-style formatting.
void benchmark_random_gen()
Implementation namespace for support and library code.
auto microBenchmark(FUN const &testSubject, const size_t repeatCnt=DEFAULT_RUNS)
perform a simple looped microbenchmark.
Managing a collection of non-copyable polymorphic objects in compact storage.
Object Monitor based synchronisation.
Simplistic test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Research setup to investigate concurrent access to a random generator.
Convenience front-end to simplify and codify basic thread handling.
Generating (pseudo) random numbers with controlled seed.
Adapter to protect against data corruption caused by concurrent access.
double uni()
random double drawn from interval [0.0 ... 1.0[
const uint NUM_INVOKES
invocations of the target per measurment
Random defaultGen
a global default RandomSequencer for mundane purposes
A N-fold synchronisation latch using yield-wait until fulfilment.