diff --git a/tests/vault/mem/buffer-provider-load-test.cpp b/tests/vault/mem/buffer-provider-load-test.cpp index 9f1785885..da491e83e 100644 --- a/tests/vault/mem/buffer-provider-load-test.cpp +++ b/tests/vault/mem/buffer-provider-load-test.cpp @@ -18,25 +18,34 @@ #include "test/run.hpp" #include "test/test-helper.hpp" +#include "vault/mem/buffer-provider-setup.hpp" +#include "vault/mem/engine-buffer-metadata.hpp" #include "vault/mem/engine-buffer-manager.hpp" -#include "vault/mem/engine-buffer-allocator.hpp" +#include "vault/mem/local-buffer-stage.hpp" +#include "vault/mem/local-buffer-store.hpp" #include "vault/gear/test-chain-load.hpp" #include "lib/scoped-collection.hpp" +#include "lib/depend-inject.hpp" #include "lib/iter-explorer.hpp" #include "lib/sync-barrier.hpp" +#include "lib/iter-stack.hpp" #include "lib/thread.hpp" #include "lib/symbol.hpp" #include "lib/random.hpp" +#include "test/diagnostic-output.hpp"////////////TODO #include #include #include using lib::explore; +using lib::Depend; +using lib::DependInject; using lib::Random; using lib::Literal; using lib::Thread; using lib::SyncBarrier; +using lib::ScopedCollection; using vault::gear::test::ComputationalLoad; using std::this_thread::yield; using std::this_thread::sleep_for; @@ -49,13 +58,132 @@ namespace mem { namespace test { namespace { // Test parameters...... - const size_t ALLOC_REQ = 1024*1024; ///< use test-allocation request of 1 MiB size const size_t NUM_THREADS = 100; ///< press concurrently + + const size_t MAX_SCALE = 5; ///< maximum scale step for randomised resources + + + /** seed a per-thread random generator */ + inline Random + makeRandGen() + { + return Random{lib::seedFromDefaultGen()}; + } + + class MultithreadBufferSetup + : public BufferProviderSetup + { + public: + MultithreadBufferSetup() + : BufferProviderSetup{*this} + { } + + auto buildStage() { return std::make_unique("BufferProviderLoad_test"); } + auto buildStore() { return std::make_unique(); } + }; + + + using BuffTypes = ScopedCollection; + + /** + * Mock dependency injection context + * to emulate a Render Engine setup + */ + struct Ctx + { + static Depend bufferProvider; + static BuffTypes buffType_; + + // install mock instances for the relevant services + DependInject::Local metaHub; + DependInject::Local globalPool; + DependInject::Local frontEnd; + }; + + // static storage for the mock-engine entrance point + Depend Ctx::bufferProvider; + BuffTypes Ctx::buffType_{MAX_SCALE}; } + struct WorkSetup + { + static constexpr uint NUM_JOBS = 10; + static constexpr size_t BASE_BUFFSIZ = 100_KiB; + + /// local random generator per thread + Random rand_; + ComputationalLoad load_; + + WorkSetup() + : rand_{makeRandGen()} + { + load_.timeBase = 1ms; + load_.sizeBase = BASE_BUFFSIZ; + load_.useAllocation = true; + } + }; + + /** + * Emulation of the load produced by a worker thread + */ + template + class DummyWorkerThread + : CONF + , public Thread + { + + + void + workActivity() + { + for (uint i=0; i - class DummyWorkerThread - : CONF - , public Thread - { - - - void - workActivity() - { - for (uint i=0; i - + @@ -148526,8 +148526,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) konkret müssen giftige Situationen provoziert werden, um zu sehen daß der Code selbst dann nicht entgleist, wenn man ihn an die Grenzen treibt. Diese Grenzen sind jedoch ohne eine vertiefte Analyse nicht bekannt, und diese Analyse möchte ich (jetzt aus Zeitgründen) nicht machen. Daher der Ansatz, möglichst viel relevante Unregelmäßigkeiten reinzubringen

- - +
@@ -148563,8 +148562,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + @@ -148579,8 +148577,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) der default-Wert sind 1KiB — aber die zu erwartenden Repetitionen für 100µs sind bereits so ca 10k. Deshalb wird mit diesen Standard-Settings der Buffer x mal bespielt, und für etwas größere Last-Zeiten (1ms und mehr) fällt die Granularität des Buffers kaum noch ins Gewicht

- - +
@@ -148600,8 +148597,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Extrembeispiel: angenommen, die Kalibrierung ist nahe am default, also 100 Schritte pro µs, dann brauchen wir 10000 Schritte für 100µs. Wenn der Buffer aber 1 MiB groß ist, machen wir 1 Mio Schritte. Das bedeutet, egal was wir vorgeben, wir landen bei ~10ms. Die Kalibrierung wird sich zwar »auf den Kopf stellen«, aber das Aufrunden verhindert, das die Kalibrierung zum Tragen kommt.

- -
+
@@ -148622,8 +148618,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Aber nun lasse ich die Schleife stets bis zur kalibrierten Rundenzahl laufen, und lediglich die Schreib-Position rotiert, gesteuert durch einen modulus auf (size - 1), da wir ja eine zusätzliche Speicherzelle brauchen, um jeweils die summe mit dem Vorgänger reinzuschreiben.

- - +
@@ -148690,16 +148685,21 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + + + + + - + - - + + - @@ -148707,9 +148707,11 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + - + + +

...das ist sogar wichtig, damit wir uns ähnlich wie in der echten Engine verhalten, incl. Zugriff über double-checked locking; @@ -148721,9 +148723,19 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Für das korrekte Test-Setup ist es lediglich erforderlich, daß effektiv die instrumentierung stattfindet bevor der jeweilige Test-Worker gestartet wird.

-
+ +
+ + + + + + + + + @@ -153351,8 +153363,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - +