Library: investigate drawing random numbers concurrently
''In theory,'' the random number generators are in no way threadsafe, neither the old `rand()`, nor the mersenne twister of the C++ standard. However, since all we want is some arbitrarily diffused numbers, chances are that this issue can be safely ignored; because a random number computation broken by concurrency will most likely generate -- well, a garbled number or "randomly" corrupted internal state. Validating this reasoning by an empiric investigation seems advisable though.
This commit is contained in:
parent
606669aa1b
commit
a15006d11a
4 changed files with 136 additions and 6 deletions
|
|
@ -15,3 +15,8 @@ END
|
||||||
TEST "Random numbers and Seed" Random_test << END
|
TEST "Random numbers and Seed" Random_test << END
|
||||||
return: 0
|
return: 0
|
||||||
END
|
END
|
||||||
|
|
||||||
|
|
||||||
|
TEST "Concurrent PRNG access" RandomConcurrent_test << END
|
||||||
|
return: 0
|
||||||
|
END
|
||||||
|
|
|
||||||
110
tests/library/random-concurrent-test.cpp
Normal file
110
tests/library/random-concurrent-test.cpp
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
RandomConcurrent(Test) - investigate concurrent random number generation
|
||||||
|
|
||||||
|
Copyright (C) Lumiera.org
|
||||||
|
2024, Hermann Vosseler <Ichthyostega@web.de>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2 of
|
||||||
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
* *****************************************************/
|
||||||
|
|
||||||
|
/** @file random-concurrent-test.cpp
|
||||||
|
** unit test \ref RandomConcurrent_test
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "lib/test/run.hpp"
|
||||||
|
#include "lib/sync-barrier.hpp"
|
||||||
|
#include "lib/random.hpp"
|
||||||
|
#include "lib/thread.hpp"
|
||||||
|
#include "lib/sync.hpp"
|
||||||
|
#include "lib/util.hpp"
|
||||||
|
#include "lib/scoped-collection.hpp"
|
||||||
|
#include "lib/test/microbenchmark.hpp"
|
||||||
|
#include "lib/test/diagnostic-output.hpp"
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
//using util::isLimited;
|
||||||
|
|
||||||
|
namespace lib {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const uint NUM_THREADS = 8;
|
||||||
|
|
||||||
|
const uint NUM_INVOKE = 1'000'000;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************//**
|
||||||
|
* @test demonstrate simple access to random number generation,
|
||||||
|
* as well as the setup of controlled random number sequences.
|
||||||
|
* @see random.hpp
|
||||||
|
*/
|
||||||
|
class RandomConcurrent_test : public Test
|
||||||
|
{
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
run (Arg)
|
||||||
|
{
|
||||||
|
seedRand();
|
||||||
|
investigate_concurrentAccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @test examine behaviour of PRNG under concurrency stress */
|
||||||
|
void
|
||||||
|
investigate_concurrentAccess()
|
||||||
|
{
|
||||||
|
struct Results
|
||||||
|
: std::deque<double>
|
||||||
|
, Sync<>
|
||||||
|
{
|
||||||
|
void
|
||||||
|
post (double val)
|
||||||
|
{
|
||||||
|
Lock sync(this);
|
||||||
|
push_back (val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Results results;
|
||||||
|
|
||||||
|
const uint N = NUM_INVOKE;
|
||||||
|
auto expect = RAND_MAX / 2;
|
||||||
|
|
||||||
|
auto drawRandom = [&]()
|
||||||
|
{
|
||||||
|
double avg{0.0};
|
||||||
|
for (uint i=0; i<N; ++i)
|
||||||
|
avg += 1.0/N * rani();
|
||||||
|
auto error = avg/expect - 1;
|
||||||
|
results.post (error);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto [dur,sum] = threadBenchmark<NUM_THREADS> (drawRandom, 1);
|
||||||
|
for (auto res : results)
|
||||||
|
SHOW_EXPR(res);
|
||||||
|
SHOW_EXPR(sum)
|
||||||
|
SHOW_EXPR(dur/NUM_INVOKE)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LAUNCHER (RandomConcurrent_test, "unit common");
|
||||||
|
|
||||||
|
|
||||||
|
}} // namespace lib::test
|
||||||
|
|
@ -132,9 +132,9 @@ namespace test {
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
joinOnceOnly ()
|
joinOnceOnly()
|
||||||
{
|
{
|
||||||
ThreadJoinable theThread{"joining-4"
|
ThreadJoinable theThread{"test join-4"
|
||||||
,[]{ sleep_for (10ms); }};
|
,[]{ sleep_for (10ms); }};
|
||||||
theThread.join();
|
theThread.join();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57622,8 +57622,8 @@
|
||||||
<node CREATED="1731710016247" ID="ID_1116003187" MODIFIED="1731710023256" TEXT="nochmal im Einzelnen analysiert"/>
|
<node CREATED="1731710016247" ID="ID_1116003187" MODIFIED="1731710023256" TEXT="nochmal im Einzelnen analysiert"/>
|
||||||
<node CREATED="1731710023964" ID="ID_778217189" MODIFIED="1731710032544" TEXT="jede denkbare Lösung ist nicht-trivial"/>
|
<node CREATED="1731710023964" ID="ID_778217189" MODIFIED="1731710032544" TEXT="jede denkbare Lösung ist nicht-trivial"/>
|
||||||
<node COLOR="#435e98" CREATED="1731710053533" ID="ID_722076886" MODIFIED="1731713106542" TEXT="denkbar wäre zumindest ein Refactoring">
|
<node COLOR="#435e98" CREATED="1731710053533" ID="ID_722076886" MODIFIED="1731713106542" TEXT="denkbar wäre zumindest ein Refactoring">
|
||||||
<linktarget COLOR="#23b91f" DESTINATION="ID_722076886" ENDARROW="Default" ENDINCLINATION="1530;2127;" ID="Arrow_ID_1785760257" SOURCE="ID_872583288" STARTARROW="None" STARTINCLINATION="-1253;43;"/>
|
|
||||||
<linktarget COLOR="#7298c6" DESTINATION="ID_722076886" ENDARROW="Default" ENDINCLINATION="-173;13;" ID="Arrow_ID_1252004977" SOURCE="ID_778660910" STARTARROW="None" STARTINCLINATION="411;21;"/>
|
<linktarget COLOR="#7298c6" DESTINATION="ID_722076886" ENDARROW="Default" ENDINCLINATION="-173;13;" ID="Arrow_ID_1252004977" SOURCE="ID_778660910" STARTARROW="None" STARTINCLINATION="411;21;"/>
|
||||||
|
<linktarget COLOR="#23b91f" DESTINATION="ID_722076886" ENDARROW="Default" ENDINCLINATION="1530;2127;" ID="Arrow_ID_1785760257" SOURCE="ID_872583288" STARTARROW="None" STARTINCLINATION="-1253;43;"/>
|
||||||
<icon BUILTIN="idea"/>
|
<icon BUILTIN="idea"/>
|
||||||
<node COLOR="#338800" CREATED="1731710077230" ID="ID_1009222978" MODIFIED="1731712876022" TEXT="man könnte die Erkennung dieser Situation in eine Methode auf Layer-1 extrahieren">
|
<node COLOR="#338800" CREATED="1731710077230" ID="ID_1009222978" MODIFIED="1731712876022" TEXT="man könnte die Erkennung dieser Situation in eine Methode auf Layer-1 extrahieren">
|
||||||
<icon BUILTIN="button_ok"/>
|
<icon BUILTIN="button_ok"/>
|
||||||
|
|
@ -57714,8 +57714,7 @@
|
||||||
Hier wird zunächst »auf dem Trockenen« demonstriert, wie aus der Kapazitätsrechnung eine zu erwartende effektive concurrent-run-time abgeleitet wird. Am Ende wird ein tatsächlicher Scheduler-Lauf mit diesem (relativ locker dimensionierten) Schedule gestartet  — und <b>hier</b> überschreiten wir den <b>Timeout von 5 Sekunden</b>, was bedeutet, daß das Schedule komplett aus dem Ruder gelaufen sein muß (möglicherweise wurden sogar Job-Deadlines überfahren, in welchem Fall das Scheduler unvollständig hängen bleibt)
|
Hier wird zunächst »auf dem Trockenen« demonstriert, wie aus der Kapazitätsrechnung eine zu erwartende effektive concurrent-run-time abgeleitet wird. Am Ende wird ein tatsächlicher Scheduler-Lauf mit diesem (relativ locker dimensionierten) Schedule gestartet  — und <b>hier</b> überschreiten wir den <b>Timeout von 5 Sekunden</b>, was bedeutet, daß das Schedule komplett aus dem Ruder gelaufen sein muß (möglicherweise wurden sogar Job-Deadlines überfahren, in welchem Fall das Scheduler unvollständig hängen bleibt)
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html></richcontent>
|
||||||
</richcontent>
|
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
|
|
@ -58021,6 +58020,7 @@
|
||||||
</node>
|
</node>
|
||||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1731455444796" ID="ID_784243083" MODIFIED="1731455723202" TEXT="Concurrent Tests umstellen">
|
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1731455444796" ID="ID_784243083" MODIFIED="1731455723202" TEXT="Concurrent Tests umstellen">
|
||||||
<icon BUILTIN="bell"/>
|
<icon BUILTIN="bell"/>
|
||||||
|
<node CREATED="1731728363475" ID="ID_1473702684" MODIFIED="1731728367146" TEXT="problematisch">
|
||||||
<node CREATED="1731455475587" ID="ID_1622000187" MODIFIED="1731455475587" TEXT="CallQueue_test"/>
|
<node CREATED="1731455475587" ID="ID_1622000187" MODIFIED="1731455475587" TEXT="CallQueue_test"/>
|
||||||
<node CREATED="1731455716786" ID="ID_943344715" MODIFIED="1731455716786" TEXT="DiagnosticContext_test"/>
|
<node CREATED="1731455716786" ID="ID_943344715" MODIFIED="1731455716786" TEXT="DiagnosticContext_test"/>
|
||||||
<node CREATED="1731458234804" ID="ID_1185469440" MODIFIED="1731458234804" TEXT="SessionCommandFunction_test"/>
|
<node CREATED="1731458234804" ID="ID_1185469440" MODIFIED="1731458234804" TEXT="SessionCommandFunction_test"/>
|
||||||
|
|
@ -58047,7 +58047,22 @@
|
||||||
<node CREATED="1731464903922" ID="ID_349618800" MODIFIED="1731464903922" TEXT="ThreadWrapperJoin_test"/>
|
<node CREATED="1731464903922" ID="ID_349618800" MODIFIED="1731464903922" TEXT="ThreadWrapperJoin_test"/>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1731465663005" MODIFIED="1731465663005" TEXT="BusTerm_test"/>
|
<node CREATED="1731465663005" ID="ID_444907234" MODIFIED="1731465663005" TEXT="BusTerm_test"/>
|
||||||
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1731728379707" ID="ID_38959317" MODIFIED="1731728399492" TEXT="gibt es überhaupt ein Problem hier?">
|
||||||
|
<icon BUILTIN="help"/>
|
||||||
|
<node CREATED="1731728402020" ID="ID_216802866" MODIFIED="1731728433241" TEXT="theoretisch ist PRNG nicht thread-safe"/>
|
||||||
|
<node CREATED="1731728433837" ID="ID_975708385" MODIFIED="1731728441330" TEXT="aber ... was kann schon passieren??"/>
|
||||||
|
<node CREATED="1731728442361" ID="ID_444376696" MODIFIED="1731728582512" TEXT="schlimmstenfalls eine "zufällig" kaputte Zahl außerhalb des Definitionsbereichs..."/>
|
||||||
|
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1731728584572" ID="ID_1568853077" MODIFIED="1731728594906" TEXT="empirisch untersuchen">
|
||||||
|
<icon BUILTIN="yes"/>
|
||||||
|
<icon BUILTIN="pencil"/>
|
||||||
|
<node CREATED="1731728599474" ID="ID_1952720762" MODIFIED="1731728615563" TEXT="mit allen Cores parallel Zufallszahlen ziehen"/>
|
||||||
|
<node CREATED="1731728616535" ID="ID_59784960" MODIFIED="1731728640632" TEXT="einzelne Zahlen prüfen"/>
|
||||||
|
<node CREATED="1731728641175" ID="ID_177314578" MODIFIED="1731728668212" TEXT="MIttelwert prüfen (bias)"/>
|
||||||
|
<node CREATED="1731728672328" ID="ID_132879815" MODIFIED="1731728703703" TEXT="1. Test : 1 Million Aufrufe ⟹ sieht gut aus"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue