BufferProvider: implement a simulated worker load pattern
This is the meat of this test case... - generate a ''random walk'' with buffer allocation requests - attempt to make the load pattern nasty, since the goal of this test is to verify correctness of the complex interplay between local pools and central allocator. ''correct pattern was verified single-threaded, with print statements''
This commit is contained in:
parent
f868a7462a
commit
56561c8f78
5 changed files with 282 additions and 83 deletions
|
|
@ -107,19 +107,15 @@ namespace mem {
|
|||
* various kinds of buffers (e.g. of differing size), which are
|
||||
* distinguished by _the type embodied into_ the BuffDescr.
|
||||
* @return maximum number of simultaneously usable buffers of this type,
|
||||
* to be retrieved later through calls to #lockBuffer.
|
||||
* @throw error::State when no buffer of this kind can be provided
|
||||
* guaranteed to be retrieved later through calls to #lockBuffer.
|
||||
* @note the returned count may differ from the requested count.
|
||||
*/
|
||||
uint
|
||||
BufferProvider::announce (uint cnt, BuffDescr const& type)
|
||||
{
|
||||
size_t buffSiz = getBufferSize (type);
|
||||
uint actually_possible = bufferStore_->prepareBuffers (type, cnt, buffSiz);
|
||||
if (!actually_possible)
|
||||
throw err::State ("unable to fulfil request for buffers"
|
||||
,LUMIERA_ERROR_BUFFER_MANAGEMENT);
|
||||
return actually_possible;
|
||||
uint immediately_possible = bufferStore_->prepareBuffers (type, cnt, buffSiz);
|
||||
return immediately_possible;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -904,7 +904,7 @@ namespace test {
|
|||
CHECK (micros < 1100);
|
||||
micros = cpuLoad.invoke(5);
|
||||
CHECK (micros > 4600);
|
||||
CHECK (micros > 5400); // usually quite precise, less than 1% off
|
||||
CHECK (micros < 5400); // usually quite precise, less than 1% off
|
||||
micros = cpuLoad.invoke(10);
|
||||
CHECK (micros > 9500);
|
||||
micros = cpuLoad.invoke(100);
|
||||
|
|
|
|||
|
|
@ -1390,9 +1390,6 @@ namespace test {
|
|||
{
|
||||
auto cnt = roundsNeeded(scaleStep);
|
||||
auto siz = max (scaleStep * sizeBase, 2u);
|
||||
auto rep = max (cnt/siz, 1u);
|
||||
// increase size to fit
|
||||
siz = cnt / rep;
|
||||
return make_pair (siz,cnt);
|
||||
}
|
||||
|
||||
|
|
@ -1417,19 +1414,19 @@ namespace test {
|
|||
: memBlock.allocate (siz);
|
||||
Sink sink;
|
||||
*mem = sink+1;
|
||||
for ( ; 0 < cnt; --cnt)
|
||||
for (uint c=0; c < cnt; ++c)
|
||||
{
|
||||
size_t i = cnt % (siz-1);
|
||||
size_t i = c % (siz-1);
|
||||
mem[i+1] += mem[i];
|
||||
}
|
||||
sink = mem[siz-1];
|
||||
sink = mem[1 + (cnt-1) % (siz-1)];
|
||||
sink = sink + 1;
|
||||
}
|
||||
|
||||
double
|
||||
determineSpeed()
|
||||
{
|
||||
uint step4gauge = 10;
|
||||
uint step4gauge = 1;
|
||||
double micros = benchmark (step4gauge);
|
||||
auto stepsDone = roundsNeeded (step4gauge);
|
||||
return stepsDone / micros;
|
||||
|
|
|
|||
|
|
@ -26,23 +26,23 @@
|
|||
#include "vault/gear/test-chain-load.hpp"
|
||||
#include "lib/scoped-collection.hpp"
|
||||
#include "lib/depend-inject.hpp"
|
||||
#include "lib/iter-explorer.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/symbol.hpp"
|
||||
#include "lib/random.hpp"
|
||||
#include "test/diagnostic-output.hpp"////////////TODO
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
//#include <algorithm>
|
||||
//#include <string>
|
||||
#include <array>
|
||||
|
||||
using lib::explore;
|
||||
//using lib::explore;
|
||||
using lib::Depend;
|
||||
using lib::DependInject;
|
||||
using lib::Random;
|
||||
using lib::Literal;
|
||||
//using lib::Literal;
|
||||
using lib::Thread;
|
||||
using lib::SyncBarrier;
|
||||
using lib::ScopedCollection;
|
||||
|
|
@ -57,19 +57,26 @@ namespace vault {
|
|||
namespace mem {
|
||||
namespace test {
|
||||
|
||||
namespace { // Test parameters......
|
||||
const size_t NUM_THREADS = 100; ///< press concurrently
|
||||
namespace { // ========== Test Setup ==========
|
||||
|
||||
const size_t MAX_SCALE = 5; ///< maximum scale step for randomised resources
|
||||
const size_t NUM_THREADS = 100; ///< press concurrently
|
||||
const size_t MAX_SCALE = 5; ///< maximum scale step for randomised buffer types
|
||||
|
||||
|
||||
/** seed a per-thread random generator */
|
||||
inline Random
|
||||
makeRandGen()
|
||||
chainedRandGen()
|
||||
{
|
||||
return Random{lib::seedFromDefaultGen()};
|
||||
}
|
||||
|
||||
/**
|
||||
* BufferProvider implementation
|
||||
* configured similarly to the real Render Engine.
|
||||
* Using a distinct BufferStage and BufferStore (local pool)
|
||||
* for each new thread, together with the global EngineBufferMetadata
|
||||
* and EngineBufferManager, accessed through lib::Depend.
|
||||
*/
|
||||
class MultithreadBufferSetup
|
||||
: public BufferProviderSetup
|
||||
{
|
||||
|
|
@ -83,11 +90,18 @@ namespace test {
|
|||
};
|
||||
|
||||
|
||||
/** use a common selection of pre-configured buffer sizes */
|
||||
using BuffTypes = ScopedCollection<BuffDescr>;
|
||||
|
||||
/**
|
||||
/**************************************************//**
|
||||
* Mock dependency injection context
|
||||
* to emulate a Render Engine setup
|
||||
* @remarks
|
||||
* - MultithreadedBufferSetup is only used for this test
|
||||
* and creates per-thread implementation backend instances
|
||||
* - during the lifetime of such a Ctx instance in the local scope,
|
||||
* the global EngineBufferMetadata- and EngineBufferManager-Singletons
|
||||
* are shadowed by pristine new instances created temporarily
|
||||
*/
|
||||
struct Ctx
|
||||
{
|
||||
|
|
@ -97,7 +111,6 @@ namespace test {
|
|||
// install mock instances for the relevant services
|
||||
DependInject<EngineBufferMetadata>::Local<EngineBufferMetadata> metaHub;
|
||||
DependInject<EngineBufferManager>::Local<EngineBufferManager> globalPool;
|
||||
DependInject<BufferProvider>::Local<MultithreadBufferSetup> frontEnd;
|
||||
};
|
||||
|
||||
// static storage for the mock-engine entrance point
|
||||
|
|
@ -108,84 +121,174 @@ namespace test {
|
|||
|
||||
|
||||
|
||||
/* ============= Simulated Worker Load ============= */
|
||||
|
||||
struct WorkSetup
|
||||
{
|
||||
static constexpr uint NUM_JOBS = 10;
|
||||
static constexpr size_t BASE_BUFFSIZ = 100_KiB;
|
||||
static constexpr uint NUM_JOBS = 10; ///< number of work-jobs to perform in this thread
|
||||
static constexpr uint JOB_STEPS = 10; ///< number of processing steps in a single job
|
||||
static constexpr uint STEP_SPREAD = 4; ///< max random spread of allocations / deallocations
|
||||
static constexpr uint LOAD_SPREAD = 5; ///< max spread of »buffer types« to pick
|
||||
static constexpr uint MAX_DELAY = 1000; ///< maximum delay in µs between jobs
|
||||
|
||||
/// local random generator per thread
|
||||
Random rand_;
|
||||
ComputationalLoad load_;
|
||||
|
||||
WorkSetup()
|
||||
: rand_{makeRandGen()}
|
||||
{
|
||||
load_.timeBase = 1ms;
|
||||
load_.sizeBase = BASE_BUFFSIZ;
|
||||
load_.useAllocation = true;
|
||||
}
|
||||
static constexpr size_t BASE_BUFFSIZ = 100_KiB; ///< @note scaled by sizeof(size_t) * LOAD_SPREAD
|
||||
};
|
||||
|
||||
/**
|
||||
* Emulation of the load produced by a worker thread
|
||||
* Simulation of the load produced by a worker thread.
|
||||
* Performs a sequence of work actions, requesting
|
||||
* buffer memory an causing computational load.
|
||||
*/
|
||||
template<class CONF = WorkSetup>
|
||||
class DummyWorkerThread
|
||||
: CONF
|
||||
, SyncBarrier
|
||||
, public Thread
|
||||
{
|
||||
ComputationalLoad load_;
|
||||
/// local random generator per thread
|
||||
Random rand_;
|
||||
|
||||
|
||||
/**********//**
|
||||
* Thread-Main
|
||||
*/
|
||||
void
|
||||
workActivity()
|
||||
{
|
||||
SyncBarrier::sync();
|
||||
|
||||
for (uint i=0; i<CONF::NUM_JOBS; ++i)
|
||||
{
|
||||
uint delay = CONF::rand_.i(1000);
|
||||
SHOW_EXPR(delay)
|
||||
uint delay = rand_.i (CONF::MAX_DELAY);
|
||||
sleep_for (microseconds(delay));
|
||||
|
||||
jobActivity();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulated calculation job.
|
||||
* A random-walk like memory load pattern is generated
|
||||
* by claiming and releasing a random number of buffers, picking one
|
||||
* of the preconfigured »buffer types« (size) randomly. The corresponding
|
||||
* BuffHandle(s) are passed through a queue; the head element from that queue
|
||||
* is used to generate a combined CPU and memory load in each step.
|
||||
* Deliberately, the pre-announced capacity does not exactly fit the generated
|
||||
* load, so that constant rebalancing between local and global pool is provoked.
|
||||
*/
|
||||
void
|
||||
jobActivity()
|
||||
{
|
||||
///////OOO Idea : use an IterQueue of BuffHandles, fill these by a random-walk
|
||||
static uint ivo{0};
|
||||
SHOW_EXPR(++ivo)
|
||||
lib::IterQueue<BuffHandle> buffers;
|
||||
|
||||
auto randomAlloc = [&]{
|
||||
uint t = rand_.i (CONF::LOAD_SPREAD);
|
||||
uint c = rand_.i (CONF::STEP_SPREAD);
|
||||
for ( ; c>0; --c)
|
||||
buffers.feed (Ctx::buffType_[t].lockBuffer());
|
||||
};
|
||||
auto randomFree = [&]{
|
||||
uint c = rand_.i (CONF::STEP_SPREAD);
|
||||
for ( ; c>0; --c)
|
||||
if (buffers)
|
||||
{
|
||||
buffers->release();
|
||||
++buffers;
|
||||
}
|
||||
};
|
||||
auto randomWork = [&]{
|
||||
ENSURE (buffers);
|
||||
size_t availSpace = buffers->size() / sizeof(size_t);
|
||||
uint scaleStep = availSpace / CONF::BASE_BUFFSIZ;
|
||||
ENSURE (availSpace*sizeof(size_t) >= load_.requiredBuffSiz(scaleStep));
|
||||
load_.externalBuff = & buffers->accessAs<size_t>();
|
||||
|
||||
// repeatedly add contents of buffer to produce computational load
|
||||
load_.invoke (scaleStep);
|
||||
};
|
||||
|
||||
|
||||
//---Announce-guess-of-average-required-capacity-----------
|
||||
for (BuffDescr& buffType : Ctx::buffType_)
|
||||
buffType.announce (util::ceilDiv (CONF::STEP_SPREAD, 2u));
|
||||
|
||||
//---Process-sequence-of-work-steps-----
|
||||
for (uint i=0; i<CONF::JOB_STEPS; ++i)
|
||||
{
|
||||
do randomAlloc();
|
||||
while (buffers.empty());
|
||||
randomWork();
|
||||
randomFree();
|
||||
}
|
||||
//---Free-up-remaining-buffers--
|
||||
while (buffers)
|
||||
{
|
||||
buffers->release();
|
||||
++buffers;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** one-time static pre-configuration of buffer types, shared by all threads.
|
||||
* @remark this emulates a similar behaviour of the Render Node graph, where
|
||||
* embedded BuffDescr instances are established by the Builder for each node.
|
||||
* Furthermore, ComputationalLoad is calibrated here, so that at scaleStep≡1
|
||||
* the imposed delay turns out close to the configured timeBase of 1ms.
|
||||
* As a special twist, this test will use the allocated buffer memory
|
||||
* to perform the computation to generate the load -- similar to what
|
||||
* happens with a real CPU based media computation in memory.
|
||||
*/
|
||||
void
|
||||
registerBufferTypes()
|
||||
{
|
||||
if (Ctx::buffType_.empty()
|
||||
or Ctx::buffType_[0].buffSize() != CONF::BASE_BUFFSIZ )
|
||||
{
|
||||
load_.calibrate();
|
||||
Ctx::buffType_.clear();
|
||||
Ctx::buffType_.populate_by(
|
||||
BuffTypes::invoke(
|
||||
[&, i=0]() mutable
|
||||
{
|
||||
return Ctx::bufferProvider().getDescriptorFor (++i * CONF::BASE_BUFFSIZ);
|
||||
{ // preconfigure »buffer types« with suitable size
|
||||
// as required by the Mem-method of ComputationalLoad
|
||||
size_t siz = load_.requiredBuffSiz (++i);
|
||||
return Ctx::bufferProvider().getDescriptorFor (siz);
|
||||
}));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DummyWorkerThread()
|
||||
DummyWorkerThread() ///< @note this constructor runs in the main thread
|
||||
: Thread{"Load-Test-Worker"
|
||||
,[this]{ workActivity(); }}
|
||||
,[this]{ workActivity(); }
|
||||
}
|
||||
, rand_{chainedRandGen()}
|
||||
{
|
||||
REQUIRE (CONF::LOAD_SPREAD <= MAX_SCALE);
|
||||
|
||||
load_.timeBase = 1ms;
|
||||
load_.sizeBase = CONF::BASE_BUFFSIZ;
|
||||
load_.useAllocation = true;
|
||||
registerBufferTypes();
|
||||
|
||||
SyncBarrier::sync(); // allow the workActivity() to commence now...
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************//**
|
||||
* @test Show how the central buffer manager of the Render Engine can be accessed.
|
||||
|
||||
/**************************************************************************//**
|
||||
* @test Integration test of the Render Engine buffer management subsystem.
|
||||
* - this test uses a setup and wiring of components similar to the
|
||||
* actual Render Engine, with thread-local memory pools for each
|
||||
* worker, and a central buffer allocator and metadata hub.
|
||||
* - a load pattern similar to the actual render workers is generated
|
||||
* by the DummyWorkerThread instances, exhibiting a randomly fluctuating
|
||||
* demand of buffer memory, while keeping the CPU(s) busy with a load
|
||||
* of memory access and simple computations.
|
||||
* - the prime goal is to demonstrate correctness, balancing memory demand
|
||||
* mostly through lock-free queues, without loosing any allocation.
|
||||
*/
|
||||
class BufferProviderLoad_test : public Test
|
||||
{
|
||||
|
|
@ -193,6 +296,8 @@ SHOW_EXPR(++ivo)
|
|||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
seedRand();
|
||||
|
||||
demonstrate_EngineSetup();
|
||||
verify_massiveOverload();
|
||||
verify_controlledLoad();
|
||||
|
|
@ -216,7 +321,27 @@ SHOW_EXPR(++ivo)
|
|||
SHOW_EXPR("hurgha")
|
||||
SHOW_EXPR(bool(mockEngine.globalPool))
|
||||
SHOW_EXPR(bool(mockEngine.metaHub))
|
||||
SHOW_EXPR(bool(mockEngine.frontEnd))
|
||||
// the central services were indeed requested / created
|
||||
CHECK (mockEngine.globalPool);
|
||||
CHECK (mockEngine.globalPool);
|
||||
|
||||
SHOW_EXPR(mockEngine.metaHub->cntEntries())
|
||||
// 5 distinct buffer types registered
|
||||
CHECK (5 == mockEngine.metaHub->cntEntries());
|
||||
|
||||
sleep_for (500us); // additional delay for the local pool's destructor
|
||||
// (which is invoked after the thread has terminated)
|
||||
|
||||
SHOW_EXPR(watch(*mockEngine.globalPool).numAllocs())
|
||||
// there must be some allocations, still sitting in the return queue
|
||||
CHECK (0 < watch(*mockEngine.globalPool).numAllocs());
|
||||
|
||||
// process and close remaining allocations
|
||||
// sent back by the local pool's destructor...
|
||||
mockEngine.globalPool->processPendingRequests();
|
||||
// now there should be no memory leaks.......
|
||||
SHOW_EXPR(watch(*mockEngine.globalPool).bytesLeased());
|
||||
CHECK (0 == watch(*mockEngine.globalPool).bytesLeased());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -148357,7 +148357,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1779807848109" ID="ID_1050489006" MODIFIED="1779807854472" TEXT="Zusammenspiel aller Komponenten">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1779807848109" ID="ID_1050489006" MODIFIED="1780020337157" TEXT="Zusammenspiel aller Komponenten">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1779811658144" ID="ID_48160877" MODIFIED="1779811912507" TEXT="Beschluß: einen Lasttest machen...">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
|
|
@ -148377,18 +148378,34 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1779812597453" ID="ID_1461978332" MODIFIED="1779812658974" TEXT="totale Überlasung mit 100 Threads muß sich ohne Crash und Speicherlecks abwickeln"/>
|
||||
<node CREATED="1779812665915" ID="ID_1570498180" MODIFIED="1779812704696" TEXT="eine kontrollierte Laststrecke mit 4 Threads und aktiver Rechentätigkeit"/>
|
||||
</node>
|
||||
<node CREATED="1779839209247" ID="ID_1239324318" MODIFIED="1779839217338" TEXT="Setup">
|
||||
<node CREATED="1779839235941" ID="ID_900522759" MODIFIED="1779839247697" TEXT="Mocks injizieren in die globalen Services">
|
||||
<node BACKGROUND_COLOR="#b4e5ba" COLOR="#338800" CREATED="1779839209247" ID="ID_1239324318" MODIFIED="1780020652972" TEXT="Setup">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1779839235941" ID="ID_900522759" MODIFIED="1780020668585" TEXT="Mocks injizieren in die globalen Services">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1779839249783" ID="ID_780673785" MODIFIED="1779839254539" TEXT="EngineMetadata"/>
|
||||
<node CREATED="1779839255479" ID="ID_606279257" MODIFIED="1779839259938" TEXT="EngineBufferManager"/>
|
||||
</node>
|
||||
<node CREATED="1779839285981" ID="ID_1007589165" MODIFIED="1779839299365" TEXT="einen BufferProvider als front-End bereitstellen">
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1779839304513" ID="ID_1391142931" MODIFIED="1779839316211" TEXT="muß der speziell konfiguriert sein?">
|
||||
<icon BUILTIN="help"/>
|
||||
<node COLOR="#435e98" CREATED="1779839285981" ID="ID_1007589165" MODIFIED="1780020664746" TEXT="einen BufferProvider als front-End bereitstellen">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1779839318919" ID="ID_951862013" MODIFIED="1779839332190" TEXT="fest steht: er muß auf die globalen Services zugreifen"/>
|
||||
<node CREATED="1780020425809" ID="ID_707581100" MODIFIED="1780020588194" TEXT="verwende nur für diesen Test eine direkt zusammengestellte Konfiguration">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...obwohl das mutmaßlich <i>fast komplett</i> genauso sein wird, wie für die echte Engine; jedoch wird damit das Test-Setup klarer verständlich, und ich kann ein lib::Depend-Singleton allein für diesen Test hier verwenden, ohne mir weiter Gedanken machen zu müssen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1780020591596" ID="ID_1773118167" MODIFIED="1780020626325" TEXT="die Konfiguration ist offensichtlich">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1780020615804" MODIFIED="1780020615804" TEXT="LocalBufferStage"/>
|
||||
<node CREATED="1780020620527" MODIFIED="1780020620527" TEXT="LocalBufferStore"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1779839354828" ID="ID_518513597" MODIFIED="1779839358931" TEXT="Test-Worker">
|
||||
<node COLOR="#338800" CREATED="1779839354828" ID="ID_518513597" MODIFIED="1780020400282" TEXT="Test-Worker">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1779839360162" ID="ID_328313949" MODIFIED="1779839367916" TEXT="muß sich in einem Thread betreiben lassen">
|
||||
<node CREATED="1779839374568" ID="ID_583136761" MODIFIED="1779839386715" TEXT="idealerweise default-konstruiert"/>
|
||||
<node CREATED="1779839387637" ID="ID_15747866" MODIFIED="1779839400817" TEXT="muß eine eigene RandomGen-Instanz verwenden"/>
|
||||
|
|
@ -148539,7 +148556,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1779896309364" ID="ID_585456943" MODIFIED="1779896313401" TEXT="Implementierung">
|
||||
<node COLOR="#338800" CREATED="1779896309364" ID="ID_585456943" MODIFIED="1780020269167" TEXT="Implementierung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1779896314395" ID="ID_808195038" MODIFIED="1779896326428" TEXT="Policy-based Design mit einem Setup-Record">
|
||||
<node CREATED="1779896334691" ID="ID_830197460" MODIFIED="1779896350540" TEXT="vor allem damit die Parameter im Test selber klar benannt sind"/>
|
||||
<node CREATED="1779896352004" ID="ID_1821768303" MODIFIED="1779896368857" TEXT="und man kann dann trotzdem die Worker ohne Konstruktur-Argumente starten"/>
|
||||
|
|
@ -148566,8 +148584,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
<node CREATED="1779896398730" ID="ID_1701977765" MODIFIED="1779896412644" TEXT="diese Aufruf-Ordnung erfolgt im Main-Thread und ist deterministisch"/>
|
||||
</node>
|
||||
<node CREATED="1779928653980" ID="ID_1873622866" MODIFIED="1779928665410" TEXT="Computational Load bereitstellen">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1779928667696" ID="ID_810730410" MODIFIED="1779934031018" TEXT="Problem: Granularität der Allokation">
|
||||
<node COLOR="#338800" CREATED="1779928653980" ID="ID_1873622866" MODIFIED="1780020263915" TEXT="Computational Load bereitstellen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1779928667696" FOLDED="true" ID="ID_810730410" MODIFIED="1780020261250" TEXT="Problem: Granularität der Allokation">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1779928677225" ID="ID_788067473" MODIFIED="1779928857525" TEXT="hatte bisher noch nie mit so großen Buffern gearbeitet">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -148681,7 +148700,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1779934311947" ID="ID_1732540765" MODIFIED="1779934323768" TEXT="dann muß man halt vom DefaultSetup erben..."/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1779938087924" ID="ID_1781248338" MODIFIED="1779938093985" TEXT="Service-Zugriff">
|
||||
<node COLOR="#338800" CREATED="1779938087924" ID="ID_1781248338" MODIFIED="1780020254469" TEXT="Service-Zugriff">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1779938411204" ID="ID_1370099969" MODIFIED="1779938428022" TEXT="sollte sich an der Verwendung in der Engine orientieren..."/>
|
||||
<node CREATED="1779938428956" ID="ID_1626444519" MODIFIED="1779938438163" TEXT="also in der Vorbereitungsphase">
|
||||
<node CREATED="1779938470147" ID="ID_1823680981" MODIFIED="1779938483599" TEXT="konkret: im Worker-Init"/>
|
||||
|
|
@ -148695,23 +148715,20 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1779938502773" ID="ID_794046860" MODIFIED="1779938532040" TEXT="von diesem die Typ-Deskriptoren geben lassen"/>
|
||||
<node CREATED="1779938532878" ID="ID_17738" MODIFIED="1779938548302" TEXT="passiert effektiv sequenziert im Main-Thread"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1779938554185" ID="ID_609113292" MODIFIED="1779982844157" TEXT="⟹ muß daher lib::Depend instrumentieren...">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1779982847525" ID="ID_1455958640" MODIFIED="1779982879491" TEXT="eine produktiv-Konfiguration des BufferProviders">
|
||||
<icon BUILTIN="flag-pink"/>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1779938554185" ID="ID_609113292" MODIFIED="1780019714522" TEXT="⟹ muß daher lib::Depend instrumentieren...">
|
||||
<node COLOR="#338800" CREATED="1779982847525" ID="ID_1455958640" MODIFIED="1780019704219" TEXT="eine produktiv-Konfiguration des BufferProviders">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1779938787106" ID="ID_1927878895" MODIFIED="1779938806832" TEXT="EngineMetadata instrumentieren">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1779938787106" ID="ID_1927878895" MODIFIED="1780019707248" TEXT="EngineMetadata instrumentieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1779938794505" ID="ID_1022659388" MODIFIED="1779938806833" TEXT="EngineBufferManager instrumentieren">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1779938794505" ID="ID_1022659388" MODIFIED="1780019705828" TEXT="EngineBufferManager instrumentieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1779938827316" ID="ID_1745334491" MODIFIED="1779982883437" TEXT="der Service-Zugriff allerdings erfolgt »kanonisch« (ohne Rücksicht auf die Instrumentierung)">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#510f69" CREATED="1779938827316" ID="ID_1745334491" MODIFIED="1780019724248" TEXT="der Service-Zugriff allerdings erfolgt »kanonisch« (ohne Rücksicht auf die Instrumentierung)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...das ist sogar wichtig, damit wir uns ähnlich wie in der echten Engine verhalten, incl. Zugriff über double-checked locking;
|
||||
|
|
@ -148737,7 +148754,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1779937246315" ID="ID_863725806" MODIFIED="1779937253926" TEXT="Job-Laststruktur erzeugen">
|
||||
<node COLOR="#338800" CREATED="1779937246315" ID="ID_863725806" MODIFIED="1780020023969" TEXT="Job-Laststruktur erzeugen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1779937260262" ID="ID_26328925" MODIFIED="1779937450294" TEXT="wird doch etwas knifflig, denn es müssen Buffer-Descriptor verwendet werden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
|
|
@ -148751,15 +148769,24 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1779937503899" ID="ID_218274015" MODIFIED="1779937532885" TEXT="möglichst genau den Job nachahmen? oder möglichst ekelhaft verhalten?">
|
||||
<node COLOR="#435e98" CREATED="1779937503899" ID="ID_218274015" MODIFIED="1780020009132" TEXT="möglichst genau den Job nachahmen? oder möglichst ekelhaft verhalten?">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1779937552129" ID="ID_1891072198" MODIFIED="1779937568594" TEXT="Stichwort Prüftiefe ⟹ ekelhaft sein"/>
|
||||
<node CREATED="1779937552129" ID="ID_1891072198" MODIFIED="1780020015085">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Stichwort Prüftiefe ⟹ <b>ekelhaft sein</b>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1779937612588" ID="ID_550476336" MODIFIED="1779937616381" TEXT="sollte also...">
|
||||
<node CREATED="1779937617810" ID="ID_1911718150" MODIFIED="1779937626435" TEXT="zu viel / zu wenig vorankündigen"/>
|
||||
<node CREATED="1779937699488" ID="ID_1099572142" MODIFIED="1779937722990" TEXT="möglichst ungleichmäßiges Lastmuster erzeugen"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1779937868805" ID="ID_1953212519" MODIFIED="1779938059317" TEXT="Idee: eine IterQueue aus BuffHandles">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#320099" CREATED="1779937868805" ID="ID_1953212519" MODIFIED="1780019993187" TEXT="Idee: eine IterQueue aus BuffHandles">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1779938019165" ID="ID_1440286343" MODIFIED="1779938045270" TEXT="vorher: den statistischen Erwartungswert ankündigen"/>
|
||||
<node CREATED="1779937951794" ID="ID_1893409501" MODIFIED="1779937956478" TEXT="in jedem Schritt...">
|
||||
|
|
@ -148767,20 +148794,74 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1779937968726" ID="ID_197485272" MODIFIED="1779937985130" TEXT="das Head-Element per ComputationalLoad bespielen"/>
|
||||
<node CREATED="1779937985991" ID="ID_1688041238" MODIFIED="1779937998684" TEXT="M entnehmen und de-allozieren"/>
|
||||
</node>
|
||||
<node CREATED="1780019748856" ID="ID_72052970" MODIFIED="1780019983249" TEXT="dimensioniere die ComputatoinalLoad(scaleStep) anhand des vorgefundenen Buffers">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
habe dazu die Mem-Methode so angepaßt, daß nun einfach direkt die konfigurierte sizeBase · scaleStep verwendet wird; da hatte ich bisher ziemlich (viel zu) raffinierten Code, da ich in der ersten Implementierung mit einer doppelt verschachtelten Schleife gearbeitet habe. Das war ungeschickt, und hat zu ungenauen Timings geführt. Mit dem Umbau hier nun verwenden wir einen Modulus, um die Load-Loop auf den Speicher herunterzubrechen; man kann nun einfach die konfigurierte Größe direkt verwenden. Damit kann ich relativ sicher einen vorhandenen Buffer verwenden (muß nur den scaleStep per Integer-Division herausfinden).
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#3e3869" CREATED="1780020025841" ID="ID_741681228" MODIFIED="1780020308319" TEXT="mit Print-Statements beobachtet">
|
||||
<linktarget COLOR="#2413bd" DESTINATION="ID_741681228" ENDARROW="Default" ENDINCLINATION="-43;77;" ID="Arrow_ID_1505722901" SOURCE="ID_1223809546" STARTARROW="None" STARTINCLINATION="166;11;"/>
|
||||
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="forward"/>
|
||||
<node CREATED="1780020034608" ID="ID_744344400" MODIFIED="1780020051216" TEXT="es entsteht tatsächlich ein Random-Walk"/>
|
||||
<node CREATED="1780020055716" ID="ID_47131556" MODIFIED="1780020063599" TEXT="auch die Queue-Size variiert erheblich"/>
|
||||
<node CREATED="1780020064732" ID="ID_879414103" MODIFIED="1780020178561">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
durch den effektiv ermittelten <font face="Monospaced">scaleStep</font> zeigt sich,
|
||||
</p>
|
||||
<p>
|
||||
daß regelmäßig erheblich größere Buffer bereitgestellt werden.
|
||||
</p>
|
||||
<p>
|
||||
In einem Fall konnte ich sogar sehen, daß wohl der Pool geschrumpft
|
||||
</p>
|
||||
<p>
|
||||
worden war, denn eine Folge von Einzel-Anforderungen wurde stets
|
||||
</p>
|
||||
<p>
|
||||
mit dem viel zu großen Buffer bedient
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1780020190666" ID="ID_1069430425" MODIFIED="1780020206395" TEXT="sehe am Ende wild verschiedene Anzahl an noch offenen Allokationen"/>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1780020207863" ID="ID_1259481638" MODIFIED="1780020221205" TEXT="aber nach dem letzten Clean-up ist alles sauber">
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1780020283668" ID="ID_475125993" MODIFIED="1780020384893" TEXT="Testfälle">
|
||||
<linktarget COLOR="#4587d6" DESTINATION="ID_475125993" ENDARROW="Default" ENDINCLINATION="-174;35;" ID="Arrow_ID_1000436933" SOURCE="ID_200114754" STARTARROW="None" STARTINCLINATION="93;10;"/>
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1780020287468" ID="ID_1223809546" MODIFIED="1780020317672" TEXT="Test-Worker single-threaded beobachtet">
|
||||
<arrowlink COLOR="#2413bd" DESTINATION="ID_741681228" ENDARROW="Default" ENDINCLINATION="-43;77;" ID="Arrow_ID_1505722901" STARTARROW="None" STARTINCLINATION="166;11;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1779806981481" ID="ID_339298449" MODIFIED="1779807068096" TEXT="Integration und Tests">
|
||||
<icon BUILTIN="hourglass"/>
|
||||
<node CREATED="1779811803748" ID="ID_1356647567" MODIFIED="1779811814407" TEXT="Tests">
|
||||
<node CREATED="1779811854629" ID="ID_200114754" MODIFIED="1779811912507" TEXT="BufferProviderLoad_test">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1779811854629" ID="ID_200114754" MODIFIED="1780020384893" TEXT="BufferProviderLoad_test">
|
||||
<arrowlink COLOR="#4587d6" DESTINATION="ID_475125993" ENDARROW="Default" ENDINCLINATION="-174;35;" ID="Arrow_ID_1000436933" STARTARROW="None" STARTINCLINATION="93;10;"/>
|
||||
<linktarget COLOR="#6b414a" DESTINATION="ID_200114754" ENDARROW="Default" ENDINCLINATION="74;-150;" ID="Arrow_ID_961812501" SOURCE="ID_48160877" STARTARROW="Default" STARTINCLINATION="-330;-11;"/>
|
||||
<icon BUILTIN="pencil"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue