BufferProvider: implement heuristic to trigger pool clean-up

This commit is contained in:
Fischlurch 2026-05-25 20:24:25 +02:00
parent 08fef0c64c
commit 5a7cfb613f
3 changed files with 255 additions and 13 deletions

View file

@ -100,6 +100,7 @@ namespace mem {
using std::move;
using std::forward;
using std::invocable;
using util::max;
using util::unConst;
using util::isLimited;
using std::this_thread::sleep_for;
@ -147,6 +148,7 @@ namespace mem {
BlockList blocks_;
int32_t maxScore_{1};
int32_t turnover_{0};
std::function<void(LocalMemPool&)> shutdownHook_{};
@ -201,6 +203,13 @@ namespace mem {
return bool(anyFree (sizRequest));
}
/** turnover-based trigger for heuristic pool clean-up */
bool
shouldCleanup (float sharpen =1.0f) const
{
return turnover_ * float(MATCH_SCORE) <= maxScore_ * sharpen;
}
/**
* Determine to what extent the indicated allocation request
* could be handled, given the current memory available in the pool.
@ -252,6 +261,8 @@ namespace mem {
{
Alloc alloc{mem,siz};
AllocReceiver::supply (alloc);
if (alloc.mem)
++turnover_;
}
/**
@ -264,7 +275,10 @@ namespace mem {
supplyImmediately (Alloc alloc)
{
if (alloc.mem)
blocks_.emplace_front (move(alloc));
{
blocks_.emplace_front (move(alloc));
++turnover_;
}
// otherwise: allocation not serviced, do not add anything
}
@ -285,6 +299,7 @@ namespace mem {
throw err::Logic{"returning known allocation that is not marked as used"};
block->used = false;
ENSURE (not block->resd);
--turnover_;
}
/**
@ -325,7 +340,11 @@ namespace mem {
yield (uint cnt, size_t siz, FUN&& consumer)
{
ingest();
if (blocks_.empty())
return 0;
uint remain{0};
uint removed{0};
int32_t newMax{0};
for (auto pos = blocks_.begin()
; pos != blocks_.end()
; )
@ -341,8 +360,16 @@ namespace mem {
--cnt;
}
else
++pos;
{
newMax = max (newMax, pos->score);
++remain;
++pos;
}
// recalibrate proportionally
uint prevSiz{removed+remain};
ENSURE (0 < prevSiz);
turnover_ *= float(remain)/prevSiz;
maxScore_ = max (newMax,1);
return removed;
}
@ -359,6 +386,7 @@ namespace mem {
cleanup (double degree, FUN&& consumer)
{
ingest();
uint remain{0};
uint removed{0};
int32_t killLevel = degree * maxScore_;
for (auto pos = blocks_.begin()
@ -373,12 +401,14 @@ namespace mem {
}
else
{
++remain;
pos->score -= killLevel;
++pos;
}
// recalibrate all score levels
maxScore_ -= killLevel;
maxScore_ = util::max (maxScore_, 1);
maxScore_ = max (maxScore_, 1);
turnover_ = remain;
return removed;
}
@ -545,6 +575,18 @@ namespace mem {
REQUIRE (entry, "Test refers to entry unknown in pool");
return entry->score;
}
int32_t
getMaxScore()
{
return memPool_.maxScore_;
}
int32_t
getTurnover()
{
return memPool_.turnover_;
}
};

View file

@ -379,36 +379,205 @@ namespace test {
SHOW_EXPR(show(globalPool));
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
supply(3);
SHOW_EXPR("supply")
SHOW_EXPR(show(globalPool));
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
reserve(2);
SHOW_EXPR("reserve")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).cntResd())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
claim(3);
SHOW_EXPR("claim")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).cntResd())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(usedBuff));
free(3);
SHOW_EXPR("free")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).cntResd())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(usedBuff));
SHOW_EXPR(pool.shouldCleanup())
pool.yield (3, SIZ, pushMem);
uint removed = pool.cleanup(0.5, pushMem);
SHOW_EXPR(removed)
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(globalPool));
claim(1);
SHOW_EXPR("claim")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).cntResd())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
free(1);
SHOW_EXPR("free")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).cntResd())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(pool.shouldCleanup())
claim(1);
SHOW_EXPR("claim")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).cntResd())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
free(1);
SHOW_EXPR("free")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(pool.shouldCleanup())
removed = pool.cleanup(0.5, pushMem);
SHOW_EXPR(removed)
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(globalPool));
supply(4);
SHOW_EXPR("supply")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(globalPool));
claim(3);
SHOW_EXPR("claim")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).cntResd())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
free(2);
SHOW_EXPR("free")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).cntResd())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(pool.shouldCleanup())
claim(2);
SHOW_EXPR("claim")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).cntResd())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
supply(4);
SHOW_EXPR("supply")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(globalPool));
free(2);
SHOW_EXPR("free")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(usedBuff));
claim(1);
SHOW_EXPR("claim")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).cntResd())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
free(1);
SHOW_EXPR("free")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(usedBuff));
SHOW_EXPR(pool.shouldCleanup())
removed = pool.cleanup(0.5, pushMem);
SHOW_EXPR(removed)
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(globalPool));
claim(1);
SHOW_EXPR("claim")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).cntResd())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
free(2);
SHOW_EXPR("free")
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).cntFree())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(pool.shouldCleanup())
removed = pool.cleanup(0.5, pushMem);
SHOW_EXPR(removed)
SHOW_EXPR(watch(pool).size())
SHOW_EXPR(watch(pool).getMaxScore())
SHOW_EXPR(watch(pool).getTurnover())
SHOW_EXPR(show(globalPool));
}

View file

@ -145434,8 +145434,8 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</body>
</html></richcontent>
</node>
<node CREATED="1778947001639" ID="ID_78533321" MODIFIED="1779665464192" TEXT="Idee: &#xbb;turnover&#xab; &#x2014; jedem Block eine Chance geben">
<linktarget COLOR="#4f65bc" DESTINATION="ID_78533321" ENDARROW="Default" ENDINCLINATION="-548;697;" ID="Arrow_ID_1519732497" SOURCE="ID_1461846299" STARTARROW="Default" STARTINCLINATION="286;13;"/>
<node CREATED="1778947001639" ID="ID_78533321" MODIFIED="1779724531120" TEXT="Idee: &#xbb;turnover&#xab; &#x2014; jedem Block eine Chance geben">
<linktarget COLOR="#4f65bc" DESTINATION="ID_78533321" ENDARROW="Default" ENDINCLINATION="-548;697;" ID="Arrow_ID_1519732497" SOURCE="ID_1461846299" STARTARROW="Default" STARTINCLINATION="345;16;"/>
<icon BUILTIN="forward"/>
<node CREATED="1778947114570" ID="ID_914679223" MODIFIED="1778947126240" TEXT="ankommende Bl&#xf6;cke erh&#xf6;hen den Turnover"/>
<node CREATED="1778947127539" ID="ID_253931638" MODIFIED="1778947136630" TEXT="jede de-Allokation veringert den Turnover"/>
@ -145469,7 +145469,7 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</body>
</html></richcontent>
</node>
<node CREATED="1778948068575" ID="ID_855345858" MODIFIED="1778948159062" TEXT="verwende also MaxScore / MATCH_SCORE als Triggerschwelle gegen den Turnout"/>
<node CREATED="1778948068575" ID="ID_855345858" MODIFIED="1779725685738" TEXT="verwende also MaxScore / MATCH_SCORE als Triggerschwelle gegen den Turnover"/>
<node CREATED="1778948224807" ID="ID_1282800052" MODIFIED="1778948275175" TEXT="zus&#xe4;tzlicher Gewichtsfaktor um die Sch&#xe4;rfe der &#xdc;berpr&#xfc;fung zu regulieren"/>
</node>
</node>
@ -146874,14 +146874,33 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<node CREATED="1777164514849" ID="ID_489761092" MODIFIED="1777164525297" TEXT="und gew&#xe4;hlt wird nach maximalem selectionScore"/>
<node CREATED="1777164528024" ID="ID_1047876896" MODIFIED="1777164541639" TEXT="dieser gew&#xe4;hlte Buffer bekommt dann einen Score-Update"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1779664650625" ID="ID_1141255727" MODIFIED="1779664857110" TEXT="Dazu einen 2.Layer &#x27f9; Heuristik zum Triggern">
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1779664650625" ID="ID_1141255727" MODIFIED="1779729238478" TEXT="Dazu einen 2.Layer &#x27f9; Heuristik zum Triggern">
<linktarget COLOR="#4d5f6c" DESTINATION="ID_1141255727" ENDARROW="Default" ENDINCLINATION="-376;22;" ID="Arrow_ID_514664149" SOURCE="ID_1129342480" STARTARROW="None" STARTINCLINATION="-76;-210;"/>
<icon BUILTIN="flag-yellow"/>
<node CREATED="1779664722365" ID="ID_1461846299" MODIFIED="1779665464192" TEXT="im Kontext vom LocalBufferStore : erweiterte Heuristik skizziert">
<arrowlink COLOR="#4f65bc" DESTINATION="ID_78533321" ENDARROW="Default" ENDINCLINATION="-548;697;" ID="Arrow_ID_1519732497" STARTARROW="Default" STARTINCLINATION="286;13;"/>
<icon BUILTIN="pencil"/>
<node CREATED="1779664722365" ID="ID_1461846299" MODIFIED="1779724531120" TEXT="im Kontext vom LocalBufferStore : erweiterte Heuristik skizziert">
<arrowlink COLOR="#4f65bc" DESTINATION="ID_78533321" ENDARROW="Default" ENDINCLINATION="-548;697;" ID="Arrow_ID_1519732497" STARTARROW="Default" STARTINCLINATION="345;16;"/>
<font NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="idea"/>
</node>
<node COLOR="#338800" CREATED="1779678327953" ID="ID_1985264283" MODIFIED="1779724920127" TEXT="turnover-Variable einf&#xfc;hren">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1779678344575" ID="ID_1954145577" MODIFIED="1779726996289" TEXT="turnover mit aktualisieren">
<icon BUILTIN="button_ok"/>
<node CREATED="1779678355221" ID="ID_877262822" MODIFIED="1779678368820" TEXT="beim supply (neue Allokation bereitstellen)"/>
<node CREATED="1779678382051" ID="ID_466975997" MODIFIED="1779678394545" TEXT="beim retrieve (Allokation verwenden)"/>
<node CREATED="1779678403727" ID="ID_838943223" MODIFIED="1779678413410" TEXT="beim reSupply (Allokation zur&#xfc;ckgeben)"/>
<node COLOR="#338800" CREATED="1779678418733" ID="ID_763664892" MODIFIED="1779729233065" TEXT="re-Initialisieren nach clean-Up">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1779678431787" ID="ID_1226724466" MODIFIED="1779733305968" TEXT="Accessor: Trigger-Status abfragen">
<icon BUILTIN="button_ok"/>
<node CREATED="1779678456264" ID="ID_1362166348" MODIFIED="1779678461993" TEXT="das ist eine pure function">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1779678463307" ID="ID_542497413" MODIFIED="1779678482680" TEXT="&quot;w&#xe4;re aktuell ein heuristisches clean-up gerechtfertigt?&quot;"/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1777206625753" ID="ID_1782953860" MODIFIED="1777245252573" TEXT="Vor-Reservierung implementieren">
@ -147007,8 +147026,20 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#435e98" CREATED="1779678269323" ID="ID_1821389812" MODIFIED="1779733357622" TEXT="Szenario-1">
<node CREATED="1779678286438" ID="ID_1816083165" MODIFIED="1779678297036" TEXT="3 gleichzeitig allozieren"/>
</node>
<node COLOR="#435e98" CREATED="1779733314454" ID="ID_284062895" MODIFIED="1779733357623" TEXT="Szenario-2">
<node CREATED="1779733320086" ID="ID_1528731299" MODIFIED="1779733324664" TEXT="nur einen verwenden"/>
</node>
<node COLOR="#435e98" CREATED="1779733330072" ID="ID_582928434" MODIFIED="1779733357623" TEXT="Szenario-3">
<node CREATED="1779733339598" ID="ID_1362814231" MODIFIED="1779733343707" TEXT="zwischendurch nachf&#xfc;llen"/>
<node CREATED="1779733348313" ID="ID_1867741071" MODIFIED="1779733353992" TEXT="wechselnd partiell verwenden"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1778979252922" ID="ID_155080806" MODIFIED="1779733388847" TEXT="Verhalten sollte deterministisch sein und Erwartung entsprechen">
<icon BUILTIN="pencil"/>
</node>
<node CREATED="1778979252922" ID="ID_155080806" MODIFIED="1778979264429" TEXT="Verhalten sollte deterministisch vorhersagbar sein"/>
</node>
</node>
</node>