From 37fc78b0272d7653b604cf36c5d8ca850e5d6d62 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 24 May 2026 23:38:37 +0200 Subject: [PATCH] BufferProvider: test setup to verify heuristic clean-up This test should confirm that such a clean-up happened, which is not yet implemented (I have a concept draft in mind) --- tests/vault/mem/local-buffer-store-test.cpp | 91 ++++++++++++++++++--- tests/vault/mem/local-mem-pool-test.cpp | 17 +++- wiki/thinkPad.ichthyo.mm | 51 ++++++++++-- 3 files changed, 139 insertions(+), 20 deletions(-) diff --git a/tests/vault/mem/local-buffer-store-test.cpp b/tests/vault/mem/local-buffer-store-test.cpp index 8a5d6b64a..fbfaa60ee 100644 --- a/tests/vault/mem/local-buffer-store-test.cpp +++ b/tests/vault/mem/local-buffer-store-test.cpp @@ -75,7 +75,6 @@ namespace test { verify_announce(); verify_allocate(); verify_release(); - verify_heuristic(); } @@ -370,20 +369,90 @@ namespace test { - /** @test + /** @test heuristic clean-up after releasing several allocations + * - at first, a de-allocated block remains available in the local pool + * - after a number of usages, defined as _turnover_, clean-up is triggered + * - this test scenario requests 3 buffers, but repeatedly uses only one + * - after the third round with this usage pattern, the local pool is reduced */ void verify_release() { - } - - - - /** @test - */ - void - verify_heuristic() - { + // »central BufferPool« (transient instance for this test) + lib::DependInject::Local globalPool; + + // *test subject* + LocalBufferStore localStore; + BufferProviderSetup::Store& storeAPI = localStore; + + const size_t BUFFSIZ = 1024; + const HashVal TYPEID = 12345; + + // coordination of test steps + std::atomic_uint step{1}; + + Thread testWorker{[&] /* === Scenario: test subject requests allocation immediately === */ + { + // Step-1 : first round + uint avail = storeAPI.prepareBuffers(TYPEID, 3, BUFFSIZ); + CHECK (0 == avail); + CHECK (watch(localStore).isEmpty()); + + BuffAlloc slot1 = storeAPI.provideBuffer (TYPEID, BUFFSIZ, 0,0); + auto& [storage,buffSiz,_] = slot1; + CHECK (storage); + + storeAPI.detachBuffer (TYPEID, slot1); + // Result: got three allocations and all three are in the local pool + CHECK (watch(localStore).size() == 3); + CHECK (watch(localStore).cntFree() == 3); + + ++step; + // Step-2 : repeat same pattern + BuffAlloc slot2 = storeAPI.provideBuffer (TYPEID, BUFFSIZ, 0,0); + CHECK (slot2 == slot1); + CHECK (watch(localStore).size() == 3); + CHECK (watch(localStore).cntFree() == 2); + + storeAPI.detachBuffer (TYPEID, slot1); + CHECK (watch(localStore).size() == 3); + CHECK (watch(localStore).cntFree() == 3); + + ++step; + // Step-3 : repeat for a third time + BuffAlloc slot3 = storeAPI.provideBuffer (TYPEID, BUFFSIZ, 0,0); + CHECK (slot3 == slot1); + CHECK (watch(localStore).size() == 3); + CHECK (watch(localStore).cntFree() == 2); + + storeAPI.detachBuffer (TYPEID, slot1); + // this completed a "turnover" of three buffers + SHOW_EXPR(watch(localStore).size()); + + ++step; + // main thread will now see the partial clean-up + + }}; // block automatically sent back after thread end + + + /* === Main thread: observe effects in the global pool === */ + + // wait until Step-2 + while (step < 2) + sleep_for(1ms); + CHECK (watch(*globalPool).numAllocs() == 3); + + // re-check after Step-2 + while (step <= 2) + sleep_for(1ms); + // nothing changed; local pool operates independently + CHECK (watch(*globalPool).numAllocs() == 3); + + // re-check after Step-3 + while (step <= 3) + sleep_for(1ms); + globalPool->processPendingRequests(); + SHOW_EXPR(watch(*globalPool).numAllocs()) } }; diff --git a/tests/vault/mem/local-mem-pool-test.cpp b/tests/vault/mem/local-mem-pool-test.cpp index e53d80a4e..fa435f8ae 100644 --- a/tests/vault/mem/local-mem-pool-test.cpp +++ b/tests/vault/mem/local-mem-pool-test.cpp @@ -76,6 +76,7 @@ namespace test { simpleUse(); verify_matchAlloc(); verify_selectAlloc(); + verify_turnoverTrigger(); } @@ -273,7 +274,7 @@ namespace test { // perform a rather aggressive clean-up cnt = pool.cleanup(0.7 ,returnAlloc); // max score is 15, so anything below 0.7*15 ≡ 10 will be expunged CHECK (cnt == 3); - CHECK (join(returned) == "12, 33, 32"_expect); // MEM12, MEM33 and MEM32 returned, since their score as <= 10 + CHECK (join(returned) == "12, 33, 32"_expect); // MEM12, MEM33 and MEM32 returned, since their score was <= 10 CHECK (watch(pool).cntFree() == 1); CHECK (watch(pool).size() == 2); @@ -297,6 +298,20 @@ namespace test { CHECK (join(returned) == "12, 33, 32, 31, 11"_expect); CHECK (pool.empty()); } + + + + /** @test heuristic trigger mechanism for pool clean-up + * - create abbreviated notation to play through various scenarios + * - watch how turnover and max-score are computed for each step + * - document the trigger points for heuristic clean-up. + */ + void + verify_turnoverTrigger() + { + + } + }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 43876fec9..88bf72296 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -108803,7 +108803,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -145434,7 +145434,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + @@ -145669,11 +145670,28 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + + + + + +

+ meine Idee der Heuristik umsetzen +

+

+ mit einzelnen Grenz-Szenarien durchspielen +

+ + +
+ + + + - - - - @@ -146750,7 +146768,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -146856,6 +146874,15 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + + + + + + @@ -146954,6 +146981,14 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + + + + + @@ -171129,7 +171164,7 @@ std::cout << tmpl.render({"what", "World"}) << s - +