BufferProvider: integrate and verify heuristic trigger of clean-up

The mechanism is tuned now to engage rather quickly
whenever excess capacity builds up in a local allocator pool,
but when all buffers are used most of the time, they will be retained.

Can now demonstrate by integration test that capacity is sent back.
This commit is contained in:
Fischlurch 2026-05-26 04:39:41 +02:00
parent 5a7cfb613f
commit 7989e825b9
5 changed files with 236 additions and 209 deletions

View file

@ -51,6 +51,12 @@
namespace vault { namespace vault {
namespace mem { namespace mem {
namespace { // tuning parameters for clean-up heuristics
const double TRIGGER_SENSITIVIY = 1.0; ///< sensitivity of re-triggering based on max-score and turnover
const double HEURISTIC_CLEANUP = 0.5; ///< cut-off percentage of max-score; blocks with lower score will be sent back
}
using util::_Fmt; using util::_Fmt;
class LocalStoreDiagnostic; class LocalStoreDiagnostic;
@ -73,16 +79,28 @@ namespace mem {
* This implementation of the BufferProvider::BufferStore interface * This implementation of the BufferProvider::BufferStore interface
* deliberately skips further sanity checks, beyond what is enforced * deliberately skips further sanity checks, beyond what is enforced
* through the BufferMetadata lifecycle. Allocation requests are * through the BufferMetadata lifecycle. Allocation requests are
* passed to the LocalMemPool for the current thread. * delegated to the LocalMemPool for the current thread.
*
* The PoolSetup creates a connection to the EngineBufferManager,
* retrieved via lib::Depend, so each thread-local pool can unwind
* automatically at thread end and return all leased storage.
*/ */
class LocalBufferStore class LocalBufferStore
: public BufferProviderSetup::Store : public BufferProviderSetup::Store
{ {
struct SetupPool; struct PoolSetup;
using LocalPool = lib::LocalSlice<LocalMemPool, SetupPool>; using LocalPool = lib::LocalSlice<LocalMemPool, PoolSetup>;
using GlobalPool = lib::Depend<EngineBufferManager>; using GlobalPool = lib::Depend<EngineBufferManager>;
struct SetupPool static void
send_back2globalPool (Buff* mem, size_t siz)
{
Alloc alloc{mem,siz};
GlobalPool globalPool;
globalPool().supply(alloc);
}
struct PoolSetup
{ {
using Service = LocalMemPool; using Service = LocalMemPool;
@ -91,12 +109,7 @@ namespace mem {
{ {
return LocalMemPool{[](LocalMemPool& pool2close) return LocalMemPool{[](LocalMemPool& pool2close)
{ {
pool2close.purge([](Buff* mem, size_t siz) pool2close.purge (send_back2globalPool);
{
Alloc alloc{mem,siz};
GlobalPool globalPool;
globalPool().supply(alloc);
});
}}; }};
} }
}; };
@ -105,8 +118,7 @@ namespace mem {
GlobalPool globalPool_; GlobalPool globalPool_;
public: public:
LocalBufferStore() LocalBufferStore() { }
{ }
@ -191,15 +203,19 @@ namespace mem {
auto& [storage,buffSiz,specifics] = storageSlot; auto& [storage,buffSiz,specifics] = storageSlot;
REQUIRE (storage); REQUIRE (storage);
localPool_->reSupply (storage); localPool_->reSupply (storage);
/////////////////////////////////////////////////////OOO trigger heuristic clean-up here if (localPool_->shouldCleanup (TRIGGER_SENSITIVIY))
localPool_->cleanup (HEURISTIC_CLEANUP
,send_back2globalPool);
} }
private: private:
/** diagnostic access for unit testing */ /** diagnostic access for unit testing */
friend PoolDiagnostic watch (LocalBufferStore const&); friend PoolDiagnostic watch (LocalBufferStore const&);
}; };
/** entrance point to inspection for test */ /** entrance point to inspection for test */
inline PoolDiagnostic inline PoolDiagnostic
watch (LocalBufferStore const& lstor) watch (LocalBufferStore const& lstor)

View file

@ -205,9 +205,9 @@ namespace mem {
/** turnover-based trigger for heuristic pool clean-up */ /** turnover-based trigger for heuristic pool clean-up */
bool bool
shouldCleanup (float sharpen =1.0f) const shouldCleanup (double sharpen =1.0f) const
{ {
return turnover_ * float(MATCH_SCORE) <= maxScore_ * sharpen; return turnover_ * double(MATCH_SCORE) <= maxScore_ * sharpen;
} }
/** /**

View file

@ -24,7 +24,6 @@
#include "lib/depend-inject.hpp" #include "lib/depend-inject.hpp"
#include "lib/thread.hpp" #include "lib/thread.hpp"
#include "lib/util.hpp" #include "lib/util.hpp"
#include "test/diagnostic-output.hpp"///////////////////////TODO
#include <algorithm> #include <algorithm>
#include <atomic> #include <atomic>
@ -40,28 +39,11 @@ namespace vault {
namespace mem { namespace mem {
namespace test { namespace test {
// using LERR_(LOGIC);
// using LERR_(LIFECYCLE);
namespace { // Test helper /*********************************************//**
* @test verify memory handling in worker
// template<typename X> * that relies on a thread-local allocation pool.
// Buff*
// mark_as_Buffer(X& something)
// {
// return reinterpret_cast<Buff*> (std::addressof(something));
// }
//
}
/**************************************************************************//**
* @test verify worker memory handling that relies on a thread-local allocator.
*/ */
class LocalBufferStore_test : public Test class LocalBufferStore_test : public Test
{ {
@ -69,8 +51,6 @@ namespace test {
virtual void virtual void
run (Arg) run (Arg)
{ {
// seedRand();
verify_API(); verify_API();
verify_announce(); verify_announce();
verify_allocate(); verify_allocate();
@ -372,7 +352,7 @@ namespace test {
/** @test heuristic clean-up after releasing several allocations /** @test heuristic clean-up after releasing several allocations
* - at first, a de-allocated block remains available in the local pool * - at first, a de-allocated block remains available in the local pool
* - after a number of usages, defined as _turnover_, clean-up is triggered * - after a number of usages, defined as _turnover_, clean-up is triggered
* - this test scenario requests 3 buffers, but repeatedly uses only one * - this test scenario requests 5 buffers, but repeatedly uses only one
* - after the third round with this usage pattern, the local pool is reduced * - after the third round with this usage pattern, the local pool is reduced
*/ */
void void
@ -394,7 +374,7 @@ namespace test {
Thread testWorker{[&] /* === Scenario: test subject requests allocation immediately === */ Thread testWorker{[&] /* === Scenario: test subject requests allocation immediately === */
{ {
// Step-1 : first round // Step-1 : first round
uint avail = storeAPI.prepareBuffers(TYPEID, 3, BUFFSIZ); uint avail = storeAPI.prepareBuffers(TYPEID, 5, BUFFSIZ);
CHECK (0 == avail); CHECK (0 == avail);
CHECK (watch(localStore).isEmpty()); CHECK (watch(localStore).isEmpty());
@ -403,36 +383,40 @@ namespace test {
CHECK (storage); CHECK (storage);
storeAPI.detachBuffer (TYPEID, slot1); storeAPI.detachBuffer (TYPEID, slot1);
// Result: got three allocations and all three are in the local pool // Result: got five allocations and all are in the local pool
CHECK (watch(localStore).size() == 3); CHECK (watch(localStore).size() == 5);
CHECK (watch(localStore).cntFree() == 3); CHECK (watch(localStore).cntFree() == 5);
++step; ++step;
// Step-2 : repeat same pattern // Step-2 : repeat same pattern -- again only using one of the five buffers
BuffAlloc slot2 = storeAPI.provideBuffer (TYPEID, BUFFSIZ, 0,0); BuffAlloc slot2 = storeAPI.provideBuffer (TYPEID, BUFFSIZ, 0,0);
CHECK (slot2 == slot1); CHECK (slot2 == slot1);
CHECK (watch(localStore).size() == 3); CHECK (watch(localStore).size() == 5);
CHECK (watch(localStore).cntFree() == 2); CHECK (watch(localStore).cntFree() == 4);
storeAPI.detachBuffer (TYPEID, slot1); storeAPI.detachBuffer (TYPEID, slot1);
CHECK (watch(localStore).size() == 3); CHECK (watch(localStore).size() == 5);
CHECK (watch(localStore).cntFree() == 3); CHECK (watch(localStore).cntFree() == 5);
++step; ++step;
// Step-3 : repeat for a third time // Step-3 : repeat for a third time
BuffAlloc slot3 = storeAPI.provideBuffer (TYPEID, BUFFSIZ, 0,0); BuffAlloc slot3 = storeAPI.provideBuffer (TYPEID, BUFFSIZ, 0,0);
CHECK (slot3 == slot1); CHECK (slot3 == slot1);
CHECK (watch(localStore).size() == 3); CHECK (watch(localStore).size() == 5);
CHECK (watch(localStore).cntFree() == 2); CHECK (watch(localStore).cntFree() == 4);
storeAPI.detachBuffer (TYPEID, slot1); storeAPI.detachBuffer (TYPEID, slot1);
// this completed a "turnover" of three buffers // this triggered a clean-up and detected the unused capacity
SHOW_EXPR(watch(localStore).size()); CHECK (watch(localStore).size() == 1);
CHECK (watch(localStore).cntFree() == 1);
++step; ++step;
// main thread will now see the partial clean-up // main thread will now see the partial clean-up
}}; // block automatically sent back after thread end while (step == 4) // wait until main thread could investigate
sleep_for(1ms);
}}; // remaining buffer automatically sent back after thread end
/* === Main thread: observe effects in the global pool === */ /* === Main thread: observe effects in the global pool === */
@ -440,19 +424,31 @@ namespace test {
// wait until Step-2 // wait until Step-2
while (step < 2) while (step < 2)
sleep_for(1ms); sleep_for(1ms);
CHECK (watch(*globalPool).numAllocs() == 3); CHECK (watch(*globalPool).numAllocs() == 5);
// re-check after Step-2 // re-check after Step-2
while (step <= 2) while (step <= 2)
sleep_for(1ms); sleep_for(1ms);
// nothing changed; local pool operates independently // nothing changed; local pool operates independently
CHECK (watch(*globalPool).numAllocs() == 3); CHECK (watch(*globalPool).numAllocs() == 5);
CHECK (watch(*globalPool).bytesLeased() == 5*BUFFSIZ);
// re-check after Step-3 // re-check after Step-3
while (step <= 3) while (step <= 3)
sleep_for(1ms); sleep_for(1ms);
globalPool->processPendingRequests(); globalPool->processPendingRequests();
SHOW_EXPR(watch(*globalPool).numAllocs()) CHECK (watch(*globalPool).bytesLeased() == 1*BUFFSIZ);
// Note: local pool sent back excess capacity
++step; // allow the worker to terminate after that
while (testWorker)
sleep_for(1ms);
sleep_for(1ms); // additional wait for the dtor
globalPool->processPendingRequests();
CHECK (watch(*globalPool).bytesLeased() == 0);
// all capacity properly returned into global pool
} }
}; };

View file

@ -306,6 +306,7 @@ namespace test {
/** @test heuristic trigger mechanism for pool clean-up /** @test heuristic trigger mechanism for pool clean-up
* - use a setup where the global pool is just a queue of buffer pointers * - use a setup where the global pool is just a queue of buffer pointers
* - create abbreviated notation to play through various scenarios * - create abbreviated notation to play through various scenarios
@ -377,208 +378,199 @@ namespace test {
.feed(MEM32) .feed(MEM32)
.feed(MEM33); .feed(MEM33);
SHOW_EXPR(show(globalPool));
SHOW_EXPR(watch(pool).size()) CHECK (0 == watch(pool).size() );
SHOW_EXPR(watch(pool).getMaxScore()) CHECK (0 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getTurnover())
supply(3); supply(3);
SHOW_EXPR("supply")
SHOW_EXPR(show(globalPool));
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
reserve(2); reserve(2);
SHOW_EXPR("reserve") CHECK (3 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK (3 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (2 == watch(pool).cntResd() );
SHOW_EXPR(watch(pool).cntResd()) CHECK (1 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).getMaxScore()) CHECK (3 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getTurnover())
//------------ PATTERN-1 : use complete local capacity
claim(3); claim(3);
SHOW_EXPR("claim") CHECK ( 3 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 0 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK ( 0 == watch(pool).cntResd() );
SHOW_EXPR(watch(pool).cntResd()) CHECK (10 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).getMaxScore()) CHECK ( 3 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(usedBuff));
free(3); free(3);
SHOW_EXPR("free") CHECK ( 3 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 3 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (10 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).cntResd()) CHECK ( 0 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(usedBuff));
SHOW_EXPR(pool.shouldCleanup()) // heuristic trigger fires at that point,
// since full capacity was »turned over« once
CHECK (pool.shouldCleanup() );
uint removed = pool.cleanup(0.5, pushMem); uint removed = pool.cleanup(0.5, pushMem);
SHOW_EXPR(removed) // However, nothing was removed, since all elements
// were used efficiently and are thus close to maxScore
CHECK (0 == removed);
CHECK (show(globalPool) == "21, 31, 32, 33"_expect);
SHOW_EXPR(watch(pool).size()) CHECK ( 3 == watch(pool).size() );
SHOW_EXPR(watch(pool).getMaxScore()) CHECK ( 5 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).getTurnover()) // turnover is re-set to current pool size
SHOW_EXPR(show(globalPool)); CHECK ( 3 == watch(pool).getTurnover() );
//------------ PATTERN-2 : use only one buffer a time (inefficient)
claim(1); claim(1);
SHOW_EXPR("claim") CHECK ( 3 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 2 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (15 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).cntResd()) CHECK ( 3 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
free(1); free(1);
SHOW_EXPR("free") CHECK ( 3 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 3 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (15 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).cntResd()) CHECK ( 2 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(pool.shouldCleanup()) // not yet hitting the trigger...
CHECK (not pool.shouldCleanup() );
claim(1); claim(1);
SHOW_EXPR("claim") CHECK ( 3 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 2 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (25 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).cntResd()) CHECK ( 2 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
free(1); free(1);
SHOW_EXPR("free") CHECK ( 3 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 3 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (25 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).getMaxScore()) CHECK ( 1 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(pool.shouldCleanup()) // maxScore did increase a lot,
// since effectively just a single buffer was used all the time
CHECK (pool.shouldCleanup() );
removed = pool.cleanup(0.5, pushMem); removed = pool.cleanup(0.5, pushMem);
SHOW_EXPR(removed) // Consequently the two superfluous buffers will be sent back
// (cutoff-score is at 12; maxScore will be lowered by that amount afterwards)
CHECK (2 == removed );
CHECK (show(globalPool) == "21, 31, 32, 33, 12, 11"_expect);
CHECK ( 1 == watch(pool).size() );
CHECK ( 1 == watch(pool).cntFree() );
CHECK (13 == watch(pool).getMaxScore() );
CHECK ( 1 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(globalPool));
//------------ PATTERN-3 : dynamic partially overlapping usage
supply(4); supply(4);
SHOW_EXPR("supply")
SHOW_EXPR(watch(pool).size()) CHECK ( 5 == watch(pool).size() );
SHOW_EXPR(watch(pool).getMaxScore()) CHECK ( 5 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).getTurnover()) CHECK (13 == watch(pool).getMaxScore() );
SHOW_EXPR(show(globalPool)); CHECK ( 5 == watch(pool).getTurnover() );
// turnover was bumped +4 due to increased supply
claim(3); claim(3);
SHOW_EXPR("claim") CHECK ( 5 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 2 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (13 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).cntResd()) CHECK ( 5 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
free(2); free(2);
SHOW_EXPR("free") CHECK ( 5 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 4 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (13 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).cntResd()) CHECK ( 3 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(pool.shouldCleanup()) CHECK (not pool.shouldCleanup() );
// no complete turnover cycle yet
claim(2); claim(2);
SHOW_EXPR("claim") CHECK ( 5 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 2 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (20 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).cntResd()) CHECK ( 3 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
supply(4); supply(4);
SHOW_EXPR("supply")
SHOW_EXPR(watch(pool).size()) CHECK ( 7 == watch(pool).size() );
SHOW_EXPR(watch(pool).getMaxScore()) CHECK ( 4 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).getTurnover()) CHECK (20 == watch(pool).getMaxScore() );
SHOW_EXPR(show(globalPool)); CHECK ( 5 == watch(pool).getTurnover() );
free(2); free(2);
SHOW_EXPR("free") CHECK ( 7 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 6 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (20 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).getMaxScore()) CHECK ( 3 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(usedBuff));
claim(1); claim(1);
SHOW_EXPR("claim") CHECK ( 7 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 5 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (20 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).cntResd()) CHECK ( 3 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
free(1); free(1);
SHOW_EXPR("free") CHECK ( 7 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 6 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (20 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).getMaxScore()) CHECK ( 2 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(usedBuff)); CHECK (pool.shouldCleanup());
// triggering now, since 20/MATCH_SCORE ≡ 2
SHOW_EXPR(pool.shouldCleanup())
removed = pool.cleanup(0.5, pushMem); removed = pool.cleanup(0.5, pushMem);
SHOW_EXPR(removed) CHECK (3 == removed);
CHECK (show(globalPool) == "11, 12, 21"_expect);
SHOW_EXPR(watch(pool).size()) CHECK ( 4 == watch(pool).size() );
SHOW_EXPR(watch(pool).getMaxScore()) CHECK ( 3 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).getTurnover()) CHECK (10 == watch(pool).getMaxScore() );
SHOW_EXPR(show(globalPool)); CHECK ( 4 == watch(pool).getTurnover() );
//------------ PATTERN-4 : decreasing the fraction used
claim(1); claim(1);
SHOW_EXPR("claim") CHECK ( 4 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 2 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (20 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).cntResd()) CHECK ( 4 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
free(2); free(2);
SHOW_EXPR("free") CHECK ( 4 == watch(pool).size() );
SHOW_EXPR(watch(pool).size()) CHECK ( 4 == watch(pool).cntFree() );
SHOW_EXPR(watch(pool).cntFree()) CHECK (20 == watch(pool).getMaxScore() );
SHOW_EXPR(watch(pool).getMaxScore()) CHECK ( 2 == watch(pool).getTurnover() );
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(pool.shouldCleanup()) CHECK (pool.shouldCleanup() );
removed = pool.cleanup(0.5, pushMem);
SHOW_EXPR(removed)
SHOW_EXPR(watch(pool).size()) removed = pool.cleanup(0.5, pushMem);
SHOW_EXPR(watch(pool).getMaxScore()) CHECK (3 == removed);
SHOW_EXPR(watch(pool).getTurnover()) CHECK (show(globalPool) == "11, 12, 21, 33, 31, 13"_expect);
SHOW_EXPR(show(globalPool));
CHECK ( 1 == watch(pool).size() );
CHECK (10 == watch(pool).getMaxScore() );
CHECK ( 1 == watch(pool).getTurnover() );
} }
}; };

View file

@ -145325,7 +145325,7 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</node> </node>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1778802491003" ID="ID_1880673250" MODIFIED="1778979225756" TEXT="brauche noch einen Trigger-Mechanismus f&#xfc;r das heuristische Clean-up"> <node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1778802491003" ID="ID_1880673250" MODIFIED="1779762406992" TEXT="brauche noch einen Trigger-Mechanismus f&#xfc;r das heuristische Clean-up">
<icon BUILTIN="yes"/> <icon BUILTIN="yes"/>
<node CREATED="1778805833301" ID="ID_493965127" MODIFIED="1778806330596" TEXT="man k&#xf6;nnte nach jeder de-Allokation einen partiellen clean-up machen"> <node CREATED="1778805833301" ID="ID_493965127" MODIFIED="1778806330596" TEXT="man k&#xf6;nnte nach jeder de-Allokation einen partiellen clean-up machen">
<node CREATED="1778805853860" ID="ID_1555068699" MODIFIED="1778806001396" TEXT="w&#xe4;re wirksam, da nur unterhalb der Schwelle aufger&#xe4;umt wird"> <node CREATED="1778805853860" ID="ID_1555068699" MODIFIED="1778806001396" TEXT="w&#xe4;re wirksam, da nur unterhalb der Schwelle aufger&#xe4;umt wird">
@ -145412,7 +145412,7 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<node CREATED="1778946963640" ID="ID_993736225" MODIFIED="1778946997115" TEXT="bei Leerlauf w&#xe4;chst der Score weniger Bl&#xf6;cke (und damit der Max-Score) &#xfc;berproportional"/> <node CREATED="1778946963640" ID="ID_993736225" MODIFIED="1778946997115" TEXT="bei Leerlauf w&#xe4;chst der Score weniger Bl&#xf6;cke (und damit der Max-Score) &#xfc;berproportional"/>
<node CREATED="1778807937581" ID="ID_1900765984" MODIFIED="1778807970854" TEXT="bei lokaler Knappheit werden viele Allokations-Anforderungen gesandt"/> <node CREATED="1778807937581" ID="ID_1900765984" MODIFIED="1778807970854" TEXT="bei lokaler Knappheit werden viele Allokations-Anforderungen gesandt"/>
</node> </node>
<node CREATED="1778945962154" ID="ID_535774391" MODIFIED="1778945972518" TEXT="daraus einen Mechanismus entwickeln"> <node COLOR="#435e98" CREATED="1778945962154" ID="ID_535774391" MODIFIED="1779762420870" TEXT="daraus einen Mechanismus entwickeln">
<icon BUILTIN="idea"/> <icon BUILTIN="idea"/>
<node CREATED="1778946005609" ID="ID_1483973980" MODIFIED="1778946757293" TEXT="Ansatz: die bereits implementierte Aufr&#xe4;um-Heuristik ist zielf&#xfc;hrend"> <node CREATED="1778946005609" ID="ID_1483973980" MODIFIED="1778946757293" TEXT="Ansatz: die bereits implementierte Aufr&#xe4;um-Heuristik ist zielf&#xfc;hrend">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
@ -145482,9 +145482,9 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</node> </node>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1778800559849" ID="ID_1776275235" MODIFIED="1778800646883" TEXT="LocalBufferStore_test"> <node COLOR="#338800" CREATED="1778800559849" ID="ID_1776275235" MODIFIED="1779762439896" TEXT="LocalBufferStore_test">
<icon BUILTIN="pencil"/> <icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1778800660632" ID="ID_864970874" MODIFIED="1778979160301" TEXT="Zweck"> <node COLOR="#435e98" CREATED="1778800660632" ID="ID_864970874" MODIFIED="1779762437163" TEXT="Zweck">
<icon BUILTIN="yes"/> <icon BUILTIN="yes"/>
<node CREATED="1778800664656" ID="ID_690903258" MODIFIED="1778800678906" TEXT="Aufbau der Implemenrierung treiben"/> <node CREATED="1778800664656" ID="ID_690903258" MODIFIED="1778800678906" TEXT="Aufbau der Implemenrierung treiben"/>
<node CREATED="1778800684264" ID="ID_1722512715" MODIFIED="1778800718145" TEXT="korrektes Verhalten auf API-Level zeigen"/> <node CREATED="1778800684264" ID="ID_1722512715" MODIFIED="1778800718145" TEXT="korrektes Verhalten auf API-Level zeigen"/>
@ -145668,9 +145668,13 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</node> </node>
</node> </node>
</node> </node>
<node CREATED="1778968918381" ID="ID_752345967" MODIFIED="1778968922655" TEXT="verify_release"> <node COLOR="#338800" CREATED="1778968918381" ID="ID_752345967" MODIFIED="1779762376165" TEXT="verify_release">
<icon BUILTIN="button_ok"/>
<node CREATED="1778969042432" ID="ID_1262962638" MODIFIED="1778969052166" TEXT="hier sollte auch ein clean-up provoziert werden"/> <node CREATED="1778969042432" ID="ID_1262962638" MODIFIED="1778969052166" TEXT="hier sollte auch ein clean-up provoziert werden"/>
<node CREATED="1779665675415" ID="ID_1685534215" MODIFIED="1779665691018" TEXT="zu zeigen ist da&#xdf; dieser Clean-up mit R&#xfc;cksendung stattfindet"/> <node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1779665675415" ID="ID_1685534215" MODIFIED="1779762386504" TEXT="zu zeigen ist da&#xdf; dieser Clean-up mit R&#xfc;cksendung stattfindet">
<linktarget COLOR="#1b26b8" DESTINATION="ID_1685534215" ENDARROW="Default" ENDINCLINATION="408;19;" ID="Arrow_ID_1702718350" SOURCE="ID_1035469430" STARTARROW="None" STARTINCLINATION="577;30;"/>
<icon BUILTIN="yes"/>
</node>
</node> </node>
<node COLOR="#5b280f" CREATED="1778969102656" ID="ID_249806133" MODIFIED="1779664543753" TEXT="verify_heuristic"> <node COLOR="#5b280f" CREATED="1778969102656" ID="ID_249806133" MODIFIED="1779664543753" TEXT="verify_heuristic">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
@ -145688,8 +145692,8 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</html> </html>
</richcontent> </richcontent>
<icon BUILTIN="button_cancel"/> <icon BUILTIN="button_cancel"/>
<node CREATED="1779664546343" HGAP="25" ID="ID_453821075" MODIFIED="1779665655342" TEXT="dieser Test geh&#xf6;rt zum LocalMemPool" VSHIFT="18"> <node CREATED="1779664546343" HGAP="25" ID="ID_453821075" MODIFIED="1779762367351" TEXT="dieser Test geh&#xf6;rt zum LocalMemPool" VSHIFT="18">
<arrowlink COLOR="#765294" DESTINATION="ID_1242239297" ENDARROW="Default" ENDINCLINATION="-1163;-399;" ID="Arrow_ID_1851213418" STARTARROW="None" STARTINCLINATION="-413;30;"/> <arrowlink COLOR="#333263" DESTINATION="ID_1242239297" ENDARROW="Default" ENDINCLINATION="-1163;-399;" ID="Arrow_ID_1851213418" STARTARROW="None" STARTINCLINATION="-413;30;"/>
<icon BUILTIN="yes"/> <icon BUILTIN="yes"/>
</node> </node>
</node> </node>
@ -145755,15 +145759,18 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</body> </body>
</html></richcontent> </html></richcontent>
</node> </node>
<node CREATED="1776605858192" ID="ID_563549971" MODIFIED="1776605951752" TEXT="bleibe aber bei dem Namen &#x2014; weil er klar ist"> <node CREATED="1776605858192" ID="ID_563549971" MODIFIED="1779762245934" TEXT="bleibe aber bei dem Namen &#x2014; weil er klar ist">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head/> <head>
</head>
<body> <body>
<p> <p>
das hier ist keine generische Library, sondern ein Application-Framework. Auch &#187;Vault&#171; ist inhaltlich genau auf Lumiera ausgerichtet, der Unterschied liegt nur im Grad der Integration mit Application-level Services das hier ist keine generische Library, sondern ein Application-Framework. Auch &#187;Vault&#171; ist inhaltlich genau auf Lumiera ausgerichtet, der Unterschied liegt nur im Grad der Integration mit Application-level Services
</p> </p>
</body> </body>
</html></richcontent> </html>
</richcontent>
</node> </node>
<node COLOR="#338800" CREATED="1776611511064" ID="ID_419155046" MODIFIED="1776639433744" TEXT="Mutex-Locking einf&#xfc;hren"> <node COLOR="#338800" CREATED="1776611511064" ID="ID_419155046" MODIFIED="1776639433744" TEXT="Mutex-Locking einf&#xfc;hren">
<linktarget COLOR="#4ff278" DESTINATION="ID_419155046" ENDARROW="Default" ENDINCLINATION="1269;0;" ID="Arrow_ID_703288918" SOURCE="ID_808614387" STARTARROW="None" STARTINCLINATION="1269;0;"/> <linktarget COLOR="#4ff278" DESTINATION="ID_419155046" ENDARROW="Default" ENDINCLINATION="1269;0;" ID="Arrow_ID_703288918" SOURCE="ID_808614387" STARTARROW="None" STARTINCLINATION="1269;0;"/>
@ -147000,8 +147007,9 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<arrowlink COLOR="#f2ddc1" DESTINATION="ID_1195705832" ENDARROW="Default" ENDINCLINATION="16;47;" ID="Arrow_ID_296050493" STARTARROW="None" STARTINCLINATION="85;12;"/> <arrowlink COLOR="#f2ddc1" DESTINATION="ID_1195705832" ENDARROW="Default" ENDINCLINATION="16;47;" ID="Arrow_ID_296050493" STARTARROW="None" STARTINCLINATION="85;12;"/>
<icon BUILTIN="button_cancel"/> <icon BUILTIN="button_cancel"/>
</node> </node>
<node CREATED="1778969102656" ID="ID_1242239297" MODIFIED="1779665655342" TEXT="verify_heuristic"> <node COLOR="#338800" CREATED="1778969102656" ID="ID_1242239297" MODIFIED="1779762145111" TEXT="verify_heuristic">
<linktarget COLOR="#765294" DESTINATION="ID_1242239297" ENDARROW="Default" ENDINCLINATION="-1163;-399;" ID="Arrow_ID_1851213418" SOURCE="ID_453821075" STARTARROW="None" STARTINCLINATION="-413;30;"/> <linktarget COLOR="#333263" DESTINATION="ID_1242239297" ENDARROW="Default" ENDINCLINATION="-1163;-399;" ID="Arrow_ID_1851213418" SOURCE="ID_453821075" STARTARROW="None" STARTINCLINATION="-413;30;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1778979230293" ID="ID_1129342480" MODIFIED="1779664866045" TEXT="meine Idee der Heuristik umsetzen"> <node CREATED="1778979230293" ID="ID_1129342480" MODIFIED="1779664866045" TEXT="meine Idee der Heuristik umsetzen">
<arrowlink COLOR="#4d5f6c" DESTINATION="ID_1141255727" ENDARROW="Default" ENDINCLINATION="-376;22;" ID="Arrow_ID_514664149" STARTARROW="None" STARTINCLINATION="-76;-210;"/> <arrowlink COLOR="#4d5f6c" DESTINATION="ID_1141255727" ENDARROW="Default" ENDINCLINATION="-376;22;" ID="Arrow_ID_514664149" STARTARROW="None" STARTINCLINATION="-76;-210;"/>
</node> </node>
@ -147037,8 +147045,23 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<node CREATED="1779733348313" ID="ID_1867741071" MODIFIED="1779733353992" TEXT="wechselnd partiell verwenden"/> <node CREATED="1779733348313" ID="ID_1867741071" MODIFIED="1779733353992" TEXT="wechselnd partiell verwenden"/>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1778979252922" ID="ID_155080806" MODIFIED="1779733388847" TEXT="Verhalten sollte deterministisch sein und Erwartung entsprechen"> <node COLOR="#338800" CREATED="1778979252922" ID="ID_155080806" MODIFIED="1779762143255" TEXT="Verhalten sollte deterministisch sein und Erwartung entsprechen">
<icon BUILTIN="pencil"/> <icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1779762175999" ID="ID_1035469430" MODIFIED="1779762350703" TEXT="Clean-up ist auch in globaler Kommunikation sichtbar">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Wenn man eine gr&#246;&#223;ere Kapazit&#228;t reserviert, aber dann wiederholt immer nur einzelne Buffer belegt und wieder freigibt, sollte relativ bald der lokale Pool getrimmt werden, und die freigegebenen Buffer an den globaeln Pool zur&#252;ckgessend
</p>
</body>
</html>
</richcontent>
<arrowlink COLOR="#1b26b8" DESTINATION="ID_1685534215" ENDARROW="Default" ENDINCLINATION="408;19;" ID="Arrow_ID_1702718350" STARTARROW="None" STARTINCLINATION="577;30;"/>
<icon BUILTIN="yes"/>
</node> </node>
</node> </node>
</node> </node>