BufferProvider: more testing and refinements of the heuristic
Seems to work now roughly as expected, so that the next layers of functionality can be built on top. It seems impossible to determine the viability of this whole approach without taking the full buffer memory management into use with a real-world load scenario.
This commit is contained in:
parent
077ef891ca
commit
76dbb980b5
3 changed files with 208 additions and 116 deletions
|
|
@ -36,8 +36,31 @@
|
|||
** can be found locally, new memory must be acquired right away, since
|
||||
** render jobs are assumed to run through without blocking waits.
|
||||
**
|
||||
** # Allocation selection heuristic
|
||||
**
|
||||
** To avoid the hazard of the pool accumulating an increasing number of surplus
|
||||
** allocations over time, less frequently used blocks are culled using a heuristic.
|
||||
** allocations over time, less frequently used blocks are culled using a heuristic.
|
||||
** - The memory block to use for a given allocation request is selected foremost
|
||||
** based on the _match quality_, so that the amount of wasted excess memory
|
||||
** is ideally rather small.
|
||||
** - Furthermore, more frequently used blocks are preferred
|
||||
** - Whenever a block can be used, its score is increased, yet when some
|
||||
** block is to small to satisfy a given request, it is penalised
|
||||
** - less successful blocks can be culled by heuristic partial clean-up
|
||||
** - the hard-coded tuning parameters allow to adjust the weight assigned
|
||||
** to the quality of the match and the usage score.
|
||||
**
|
||||
** In addition, currently unused blocks can be [reserved](\ref reserve),
|
||||
** yet only if their size is reasonably close to the requested size. Using
|
||||
** this feature at the beginning of a render job allows to probe which buffer
|
||||
** allocations could be satisfied from memory already associated to the current
|
||||
** worker thread; any further memory can be requested from the central allocator,
|
||||
** to be sent asynchronously to the local pool. However, since there is always the
|
||||
** possibility that some allocation request can not be satisfied immediately, using
|
||||
** only the blocks in the local pool, an additional mechanism should be provided
|
||||
** to allocate the missing memory directly, and in a blocking way, since the
|
||||
** requests to BufferProvider happen from within the Render Node pull()
|
||||
** and are expected to be immediately successful.
|
||||
**
|
||||
** @see local-mem-pool-test.cpp
|
||||
** @see local-buffer-store.hpp
|
||||
|
|
@ -51,17 +74,9 @@
|
|||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
//#include "vault/mem/buffer-provider-setup.hpp"
|
||||
//#include "vault/mem/engine-buffer-metadata.hpp"
|
||||
//#include "vault/mem/buffer-metadata.hpp"
|
||||
#include "vault/mem/buffhandle.hpp" //////////////TODO
|
||||
//#include "lib/local-slice.hpp"
|
||||
//#include "lib/depend.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/format-string.hpp"
|
||||
#include "lib/util.hpp"
|
||||
#include "vault/mem/buffhandle.hpp"
|
||||
#include "lib/nocopy.hpp"
|
||||
#include "lib/meta/trait.hpp"//////////////TODO
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <boost/lockfree/queue.hpp>
|
||||
#include <algorithm>
|
||||
|
|
@ -78,7 +93,7 @@ namespace mem {
|
|||
|
||||
const size_t INQUEUE_SIZ = 30; ///< initial size of the lock-free provision queue
|
||||
|
||||
const uint MATCH_SCORE = 10; ///< score to add when a buffer can be used to satisfy a request
|
||||
const uint MATCH_SCORE = 10; ///< score to add when a buffer can be used to satisfy a request
|
||||
const uint MISFIT_PENALTY = 2; ///< reduce score whenever a buffer is too small to be useful
|
||||
const double USAGE_WEIGHT = 0.9; ///< degree to which very frequent usage counteracts waste of memory
|
||||
const double CLOSE_MATCH = 0.2; ///< fraction of wasted memory that still counts as /good match/
|
||||
|
|
@ -95,6 +110,20 @@ namespace mem {
|
|||
|
||||
/**
|
||||
* Low-level Building block for Render Engine memory management.
|
||||
* A pool of buffer memory blocks can be maintained, reserved
|
||||
* and used to satisfy allocation requests relying on a best
|
||||
* match heuristic. Each usage of an allocation is scored,
|
||||
* so that frequently used and well matching blocks are
|
||||
* preferred and less useful blocks can be expunged.
|
||||
* @note uses a `boost::lockfree::queue` as input channel
|
||||
* to receive new allocations from a central manager,
|
||||
* while unused allocations are passed into a consumer
|
||||
* functor on clean-up.
|
||||
* @remark the intention is to use a thread-local instance
|
||||
* of LocalMemPool, connected to the EngineBufferManger
|
||||
* thorough lock-free queues. This setup allows to
|
||||
* implement the BufferProvider::BufferStore interface
|
||||
* for use in a massive multithreaded environment.
|
||||
*/
|
||||
class LocalMemPool
|
||||
{
|
||||
|
|
@ -103,7 +132,6 @@ namespace mem {
|
|||
Buff* mem;
|
||||
size_t siz;
|
||||
};
|
||||
static_assert (std::is_trivially_copy_assignable_v<Alloc>);
|
||||
|
||||
struct Block
|
||||
{
|
||||
|
|
@ -117,7 +145,6 @@ namespace mem {
|
|||
: alloc{move(alloc)}
|
||||
{ }
|
||||
};
|
||||
static_assert (std::is_trivially_copy_assignable_v<Block>);
|
||||
|
||||
using InQueue = boost::lockfree::queue<Alloc>;
|
||||
using BlockList = std::list<Block>;
|
||||
|
|
@ -224,7 +251,7 @@ namespace mem {
|
|||
reAdd (Buff* mem)
|
||||
{
|
||||
ingest();
|
||||
Block* block = UN_CONST (anyMatch (mem));
|
||||
Block* block = UN_CONST (find (mem));
|
||||
if (not block)
|
||||
throw err::Logic{"returning unknown allocation to LocalMemPool"};
|
||||
if (not block->used)
|
||||
|
|
@ -324,6 +351,7 @@ namespace mem {
|
|||
}
|
||||
// recalibrate all score levels
|
||||
maxScore_ -= killLevel;
|
||||
maxScore_ = util::max (maxScore_, 1);
|
||||
return removed;
|
||||
}
|
||||
|
||||
|
|
@ -358,7 +386,7 @@ namespace mem {
|
|||
}
|
||||
|
||||
Block const*
|
||||
anyMatch (Buff* mem) const
|
||||
find (Buff* mem) const
|
||||
{
|
||||
return findMatch ([mem](Block const& b){ return mem == b.alloc.mem; });
|
||||
}
|
||||
|
|
@ -374,10 +402,10 @@ namespace mem {
|
|||
if (sizRequest > block.alloc.siz)
|
||||
block.score -= MISFIT_PENALTY;
|
||||
else
|
||||
{
|
||||
{ // compute heuristic selector for best match
|
||||
double wasted = block.alloc.siz - sizRequest;
|
||||
double wasteScore = wasted / block.alloc.siz;
|
||||
double usageFact = block.score / maxScore_;
|
||||
double usageFact = block.score / maxScore_;
|
||||
double selector = 1.0 - wasteScore * (1.0 - usageFact * USAGE_WEIGHT);
|
||||
if (selector > bestSelector)
|
||||
{
|
||||
|
|
@ -387,29 +415,31 @@ namespace mem {
|
|||
}
|
||||
}
|
||||
if (match)
|
||||
{
|
||||
{ // increase score of the winning block
|
||||
ENSURE (match->alloc.siz >= sizRequest);
|
||||
match->score += int(MATCH_SCORE * double(sizRequest) / match->alloc.siz);
|
||||
if (match->score > maxScore_) // reduce score by waste factor as malus
|
||||
if (match->score > maxScore_) // reduce score by waste factor as penalty
|
||||
maxScore_ = match->score;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
/** a »backdoor« for unit testing */
|
||||
friend class PoolDiagnostic;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** wrapper to inspect internals from a unit test */
|
||||
class PoolDiagnostic
|
||||
: util::MoveOnly
|
||||
{
|
||||
using Block = LocalMemPool::Block;
|
||||
|
||||
LocalMemPool& memPool_;
|
||||
LocalMemPool const& memPool_;
|
||||
public:
|
||||
PoolDiagnostic (LocalMemPool& lmp)
|
||||
PoolDiagnostic (LocalMemPool const& lmp)
|
||||
: memPool_{lmp}
|
||||
{ }
|
||||
|
||||
|
|
@ -439,18 +469,27 @@ namespace mem {
|
|||
,[](Block const& b){ return not b.used; });
|
||||
}
|
||||
|
||||
auto
|
||||
allScores()
|
||||
bool
|
||||
isFree (Buff* mem)
|
||||
{
|
||||
return lib::explore (memPool_.blocks_)
|
||||
.transform([](Block const& b){ return std::string{util::_Fmt{"%d:%02d"} % b.alloc.siz % b.score}; })
|
||||
.effuse();
|
||||
Block const* entry = memPool_.find (mem);
|
||||
REQUIRE (entry, "Test refers to entry unknown in pool");
|
||||
return not entry->used;
|
||||
}
|
||||
|
||||
int32_t
|
||||
getScore (Buff* mem)
|
||||
{
|
||||
Block const* entry = memPool_.find (mem);
|
||||
REQUIRE (entry, "Test refers to entry unknown in pool");
|
||||
return entry->score;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** entrance point to inspection for test */
|
||||
inline PoolDiagnostic
|
||||
watch (LocalMemPool& lmp)
|
||||
watch (LocalMemPool const& lmp)
|
||||
{
|
||||
return PoolDiagnostic{lmp};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,28 +18,17 @@
|
|||
|
||||
#include "test/run.hpp"
|
||||
#include "test/test-helper.hpp"
|
||||
//#include "vault/mem/engine-buffer-metadata.hpp"
|
||||
#include "vault/mem/local-mem-pool.hpp"
|
||||
#include "lib/iter-stack.hpp"
|
||||
//#include "lib/depend-inject.hpp"
|
||||
//#include "lib/thread.hpp"
|
||||
//#include "lib/error.hpp"
|
||||
#include "lib/format-util.hpp"
|
||||
#include "test/diagnostic-output.hpp"
|
||||
|
||||
|
||||
//using std::this_thread::yield;
|
||||
//using lib::Thread;
|
||||
using util::join;
|
||||
|
||||
namespace vault {
|
||||
namespace mem {
|
||||
namespace test {
|
||||
|
||||
// using LERR_(LOGIC);
|
||||
// using LERR_(LIFECYCLE);
|
||||
|
||||
|
||||
namespace { // Test helper
|
||||
|
||||
inline constexpr Buff*
|
||||
|
|
@ -72,6 +61,11 @@ namespace test {
|
|||
|
||||
/**********************************************************************//**
|
||||
* @test verify handling of prospective buffer allocations in a local pool.
|
||||
* - demonstrate usage of the API
|
||||
* - show how allocations are selected and discarded
|
||||
* @remark this covers the mechanics how allocation entries are
|
||||
* managed in the pool, without any infrastructure and
|
||||
* notably without the connection to a global manager.
|
||||
*/
|
||||
class LocalMemPool_test : public Test
|
||||
{
|
||||
|
|
@ -79,12 +73,9 @@ namespace test {
|
|||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
seedRand();
|
||||
|
||||
simpleUse();
|
||||
verify_matchAlloc();
|
||||
verify_selectAlloc();
|
||||
verify_pruneAlloc();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -195,7 +186,17 @@ namespace test {
|
|||
|
||||
|
||||
|
||||
/** @test the pool picks allocations heuristically
|
||||
/** @test the pool picks and discards allocations heuristically:
|
||||
* - allocations are only marked as reserved when they are
|
||||
* pretty close above the requested amount of memory
|
||||
* - however, all allocations in the pool are used
|
||||
* to handle requests, irrespective of reservation status
|
||||
* - the prime criterion to select an entry is the match quality
|
||||
* - yet frequently used blocks are preferred for a rather poor match
|
||||
* - each usage adds to the score, but better matches score higher
|
||||
* - but when an entry is too small to be used, it is marked with a penalty
|
||||
* - entries with low score are cleaned and returned first, while
|
||||
* successful entries with high score are retained
|
||||
*/
|
||||
void
|
||||
verify_selectAlloc()
|
||||
|
|
@ -217,9 +218,9 @@ namespace test {
|
|||
auto [m2,s2] = pool.retrieve (SIZ10);
|
||||
auto [m3,s3] = pool.retrieve (SIZ10);
|
||||
auto [m4,s4] = pool.retrieve (SIZ20+SIZ20); // this one can certainly not be satisfied
|
||||
CHECK (MEM11 == m1); // the first request gets the good match
|
||||
CHECK (MEM33 == m2); // the following ones are satisfied with an over-allocation
|
||||
CHECK (MEM32 == m3);
|
||||
CHECK (m1 == MEM11); // the first request gets the good match
|
||||
CHECK (m2 == MEM33); // the following ones are satisfied with an over-allocation
|
||||
CHECK (m3 == MEM32);
|
||||
CHECK (not m4);
|
||||
CHECK (watch(pool).cntFree() == 1);
|
||||
CHECK (watch(pool).size() == 4);
|
||||
|
|
@ -232,16 +233,69 @@ namespace test {
|
|||
VERIFY_FAIL ("unknown allocation", pool.reAdd (fake_Buffer(12345)))
|
||||
VERIFY_FAIL ("not marked as used", pool.reAdd (MEM31))
|
||||
CHECK (watch(pool).cntFree() == 4);
|
||||
SHOW_EXPR(join(watch(pool).allScores()))
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test
|
||||
*/
|
||||
void
|
||||
verify_pruneAlloc()
|
||||
{
|
||||
|
||||
// all entries in the pool were scored....
|
||||
CHECK (watch(pool).getScore(MEM31) == -2); // never used and -2 penalty for being once to small to be useful (for SIZ20+SIZ20)
|
||||
CHECK (watch(pool).getScore(MEM32) == 3); // these were used once, but as over-allocation using only 1/3 of their size SIZ30
|
||||
CHECK (watch(pool).getScore(MEM33) == 3);
|
||||
CHECK (watch(pool).getScore(MEM11) == 10); // this one was used as a perfect match and thus got the full score
|
||||
|
||||
// this score determines how they are used further....
|
||||
pool.add (MEM12, SIZ10);
|
||||
auto [m5,s5] = pool.retrieve (SIZ10-5);
|
||||
auto [m6,s6] = pool.retrieve (SIZ10);
|
||||
auto [m7,s7] = pool.retrieve (SIZ10);
|
||||
auto [m8,s8] = pool.retrieve (SIZ20);
|
||||
auto [m9,s9] = pool.retrieve (SIZ20);
|
||||
CHECK (m5 == MEM11); // used first because it matches and has the best score
|
||||
CHECK (m6 == MEM12); // used next because it's a perfect match
|
||||
CHECK (m7 == MEM33); // this is a bad match, but it's the one left with the largest score
|
||||
CHECK (m8 == MEM32); // the next best score is used to satisfy this request for SIZ20
|
||||
CHECK (m9 == MEM31); // only one left (which has the worst score because it was never used yet)
|
||||
CHECK (watch(pool).cntFree() == 0);
|
||||
CHECK (watch(pool).size() == 5);
|
||||
|
||||
pool.reAdd (m8);
|
||||
pool.reAdd (m7);
|
||||
pool.reAdd (m6);
|
||||
pool.reAdd (m5);
|
||||
CHECK (watch(pool).cntFree() == 4);
|
||||
CHECK (watch(pool).getScore(MEM11) == 15); // got +5 score because the match quality was only 50% (SIZ10 but only 5 needed)
|
||||
CHECK (watch(pool).getScore(MEM12) == 10); // this one was new, but got a +10 score due to the perfect match
|
||||
CHECK (watch(pool).getScore(MEM31) == 4); // this had -1 score but got +6 due to 60% match quality (SIZ30 but SIZ20 requested)
|
||||
CHECK (watch(pool).getScore(MEM32) == 9); // previous score was +3 and it likewise got +6
|
||||
CHECK (watch(pool).getScore(MEM33) == 6); // this had also +3 and was first in the list, but got only +3 (SIZ30 used to satisfy SIZ10)
|
||||
|
||||
// entries removed from pool...
|
||||
lib::IterQueue<size_t> returned;
|
||||
auto returnAlloc = [&](Buff* mem, size_t){ returned.feed (size_t(mem)); };
|
||||
|
||||
// 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 (watch(pool).cntFree() == 1);
|
||||
CHECK (watch(pool).size() == 2);
|
||||
|
||||
CHECK (not watch(pool).isFree(MEM31)); // Note: MEM31 is still in use and thus remains in pool, even with that low score of 4
|
||||
|
||||
CHECK (watch(pool).getScore(MEM11) == 5); // Scores were reduced accordingly, cutting away a the »kill level« of +10
|
||||
CHECK (watch(pool).getScore(MEM31) == -6);
|
||||
|
||||
pool.reAdd (MEM31);
|
||||
auto [mX,sX] = pool.retrieve (SIZ20);
|
||||
CHECK (mX == MEM31);
|
||||
CHECK (sX == SIZ30);
|
||||
pool.reAdd (MEM31);
|
||||
CHECK (watch(pool).cntFree() == 2);
|
||||
CHECK (watch(pool).getScore(MEM11) == 3); // was penalised with -2 since MEM11 was too small to satisfy a SIZ20 request
|
||||
CHECK (watch(pool).getScore(MEM31) == 0); // while MEM31 got a score of +6 for a usage with 60% match quality (SIZ30 used for SIZ20)
|
||||
|
||||
// shut down the pool...
|
||||
cnt = pool.cleanup(1.0 ,returnAlloc);
|
||||
CHECK (cnt == 2);
|
||||
CHECK (join(returned) == "12, 33, 32, 31, 11"_expect);
|
||||
CHECK (pool.empty());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -145442,7 +145442,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1776817873864" ID="ID_1964767554" MODIFIED="1776993703346" TEXT="Diskussion und Abwägung">
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1776817873864" ID="ID_1964767554" MODIFIED="1777317537379" TEXT="Diskussion und Abwägung">
|
||||
<node CREATED="1776817881283" ID="ID_1958629364" MODIFIED="1776817923320" TEXT="tatsächlich liegen die Modelle gar nicht so weit auseinander....">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
|
|
@ -145489,27 +145489,28 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node COLOR="#5b280f" CREATED="1776818311073" ID="ID_52317148" MODIFIED="1776993715217" TEXT="Ich halte es für gerechtfertigt, mein bestehendes Design weiterzuverfolgen">
|
||||
<font NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1776993849979" ID="ID_553679429" MODIFIED="1776993858232" TEXT="was muß ich dafür tun....?">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776818387320" ID="ID_1007099106" MODIFIED="1776993904981" TEXT="BufferMetadata braucht ein Interface für das Umhängen von Typen">
|
||||
<node COLOR="#5b280f" CREATED="1776993849979" FOLDED="true" ID="ID_553679429" MODIFIED="1777317428449" TEXT="was muß ich dafür tun....?">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1776818387320" ID="ID_1007099106" MODIFIED="1777317376634" TEXT="BufferMetadata braucht ein Interface für das Umhängen von Typen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1776823231012" ID="ID_523327146" MODIFIED="1776823243844" TEXT="vielleicht auch nur einen internen Mechanismus hierfür"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776819030129" ID="ID_1481123783" MODIFIED="1776819064832" TEXT="den Lebenszyklus um einen Zustand RESERVED erweitern oder FREE anders definieren">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1776819030129" ID="ID_1481123783" MODIFIED="1777317376633" TEXT="den Lebenszyklus um einen Zustand RESERVED erweitern oder FREE anders definieren">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776818439396" ID="ID_1036425192" MODIFIED="1776818855873" TEXT="außerdem: das API zum Anlegen von metadata::Entry überarbeiten">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1776818439396" ID="ID_1036425192" MODIFIED="1777317376633" TEXT="außerdem: das API zum Anlegen von metadata::Entry überarbeiten">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776818867061" ID="ID_250531323" MODIFIED="1776818976504" TEXT="die Konsistenz-Bedingungen überdenken">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1776818867061" ID="ID_250531323" MODIFIED="1777317376632" TEXT="die Konsistenz-Bedingungen überdenken">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1776818879574" ID="ID_864292841" MODIFIED="1776818967738" TEXT="Fragestellung: wann muß ein Entry überhaupt systematisch gefunden werden?">
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776878313251" ID="ID_1989720923" MODIFIED="1776878399322" TEXT="erweitern auf einen Metadaten-Payload-Typ (Template)">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1776878313251" ID="ID_1989720923" MODIFIED="1777317376633" TEXT="erweitern auf einen Metadaten-Payload-Typ (Template)">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1776818400486" ID="ID_1741215998" MODIFIED="1776993941373" TEXT="zu untersuchen: läßt sich das sogar in das interne Protokoll von BufferProvider integrieren?">
|
||||
<node BACKGROUND_COLOR="#f3d4b2" COLOR="#990033" CREATED="1776818400486" ID="ID_1741215998" MODIFIED="1777317413665" TEXT="zu untersuchen: läßt sich das sogar in das interne Protokoll von BufferProvider integrieren?">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
|
|
@ -145525,7 +145526,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1776819486115" ID="ID_754896437" MODIFIED="1776819515209" TEXT="nur provideBuffer() muß die »Inbox« lesen"/>
|
||||
<node CREATED="1776819565318" ID="ID_1485868221" MODIFIED="1776819582499" TEXT="die Entscheidung über discard() vom BufferStore treffen lassen"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776819614915" ID="ID_1631834937" MODIFIED="1776819673460" TEXT="demnach müßte mark_locked() intelligenter werden">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1776819614915" ID="ID_1631834937" MODIFIED="1777317376632" TEXT="demnach müßte mark_locked() intelligenter werden">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1776819766367" ID="ID_1983111074" MODIFIED="1776819782225" TEXT="müßte automatisch nach einem bestehenden Entry suchen"/>
|
||||
</node>
|
||||
|
|
@ -145700,7 +145701,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1776993954400" ID="ID_864271040" MODIFIED="1776993961225" TEXT="nochmal nachdenken!">
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1776993954400" ID="ID_864271040" MODIFIED="1777317529563" TEXT="nochmal nachdenken!">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1776993967934" ID="ID_1550862400" MODIFIED="1776993981224" TEXT="ich sehe jetzt drei mögliche Lösungen">
|
||||
<node CREATED="1776993982660" ID="ID_1304666636" MODIFIED="1776994204836" TEXT="alles neu implementieren">
|
||||
|
|
@ -145826,11 +145827,21 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1776818369490" ID="ID_1521404080" MODIFIED="1776819977482" TEXT="Konsequenzen und Aufgaben">
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1777317444445" ID="ID_361235105" MODIFIED="1777317455959" TEXT="Entscheidung">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1777317458007" ID="ID_850656820" MODIFIED="1777317465421" TEXT="die Trennung akzeptieren"/>
|
||||
<node CREATED="1777317466489" ID="ID_1271076546" MODIFIED="1777317484091" TEXT="die Heuristik als eine isolierte Komponente implementieren"/>
|
||||
<node CREATED="1777317485167" ID="ID_613094753" MODIFIED="1777317500153" TEXT="überall die sinnvoll-einfache Variante wählen"/>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1777317501238" ID="ID_1322641585" MODIFIED="1777317522894" TEXT="Empirische Verbessungen auf später vertagen">
|
||||
<icon BUILTIN="hourglass"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1776818369490" ID="ID_1521404080" MODIFIED="1777317328349" TEXT="Konsequenzen und Aufgaben">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776818377985" ID="ID_892319469" MODIFIED="1776819082287" TEXT="BufferMetadata">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1777024713120" ID="ID_24309556" MODIFIED="1777024728172" TEXT="eigentlich keine Anpassung notwendig">
|
||||
|
|
@ -145841,7 +145852,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1777024772191" ID="ID_645148091" MODIFIED="1777024802721" TEXT="erneute Allokation mit gleicher Adresse aus FREE-State zulassen"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1777050407430" ID="ID_1385383632" MODIFIED="1777050418990" TEXT="LocalMemPool">
|
||||
<node COLOR="#435e98" CREATED="1777050407430" ID="ID_1385383632" MODIFIED="1777317323338" TEXT="LocalMemPool">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1777050440887" ID="ID_1006627416" MODIFIED="1777066692859" TEXT="Verhalten spezifizieren">
|
||||
<icon BUILTIN="yes"/>
|
||||
|
|
@ -145874,8 +145885,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1777050453251" ID="ID_1529547535" MODIFIED="1777066700207" TEXT="Implementieren">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1777050453251" ID="ID_1529547535" MODIFIED="1777317280989" TEXT="Implementieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1777052048904" ID="ID_1403107789" MODIFIED="1777084853433" TEXT="die Eingangs-Queue wird komplett (transparent) integriert">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1777078419796" ID="ID_1966959598" MODIFIED="1777084265167" TEXT="verwende boost::lockfree::queue"/>
|
||||
|
|
@ -145927,23 +145938,20 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
<node CREATED="1777074521660" ID="ID_1763982951" MODIFIED="1777074532534" TEXT="grundsätzlich: gehe von einer kleinen Anzahl an Einträgen aus"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1777159795008" ID="ID_851031995" MODIFIED="1777168836233" TEXT="Heuristik zum Aufräumen schaffen">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1777159795008" ID="ID_851031995" MODIFIED="1777317278947" TEXT="Heuristik zum Aufräumen schaffen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1777160636295" ID="ID_1174478817" MODIFIED="1777160642510" TEXT="gewünschter Effekt">
|
||||
<node CREATED="1777160710978" ID="ID_393248452" MODIFIED="1777160729106" TEXT="möglichst wenige und möglichst gut passende Buffer lokal halten"/>
|
||||
<node CREATED="1777162022979" ID="ID_763110420" MODIFIED="1777162035764" TEXT="Prio-1 ist stets den am besten passenden Buffer zu verwenden"/>
|
||||
<node CREATED="1777162072416" ID="ID_133387683" MODIFIED="1777162520272" TEXT="allerdings soll unter einem gewissen »misfit«-Level dann MRU wichtiger werden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
denn sonst hält nach einiger Zeit jeder Pool eine Menge selten genutzter Buffer, obwohl man mit einem Bruchteil davon auch über die Runden kommen könnte
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1777162521383" ID="ID_215039061" MODIFIED="1777162527306" TEXT="Ansatz">
|
||||
|
|
@ -145954,16 +145962,13 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1777162712892" ID="ID_1388888751" MODIFIED="1777162719520" TEXT="die nicht reserviert oder belegt sind"/>
|
||||
<node CREATED="1777162720405" ID="ID_718342875" MODIFIED="1777162812203" TEXT="deren Score prozentual unterhalb dem Max-Score liegen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
wobei dieser Prozentsatz aus dem <font face="Monospaced" color="#683d3d">degree</font> - Parameter abgeleittet wird (mit umgekehrter Orientierung)
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1777162841060" ID="ID_1652390427" MODIFIED="1777162844852" TEXT="Punktsätze">
|
||||
|
|
@ -145973,7 +145978,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1777162914715" ID="ID_577486589" MODIFIED="1777162923685" TEXT="Score kann nicht negativ werden"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1777162988481" ID="ID_1170538606" MODIFIED="1777162995671" TEXT="Implementierung">
|
||||
<node COLOR="#338800" CREATED="1777162988481" ID="ID_1170538606" MODIFIED="1777317307630" TEXT="Implementierung">
|
||||
<arrowlink COLOR="#eafdb6" DESTINATION="ID_1192169892" ENDARROW="Default" ENDINCLINATION="168;-26;" ID="Arrow_ID_1362515070" STARTARROW="None" STARTINCLINATION="15;61;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1777162997152" ID="ID_833672862" MODIFIED="1777163012266" TEXT="berechne für jeden Buffer einen waste-Score (0..9)"/>
|
||||
<node CREATED="1777163103258" ID="ID_1723954782" MODIFIED="1777163118028" TEXT="oder besser: eine matchQuality 1..10"/>
|
||||
<node CREATED="1777164416380" ID="ID_740262476" MODIFIED="1777164435189" TEXT="auf diese wende ich den allgemeinen Score graduell an">
|
||||
|
|
@ -145989,40 +145996,31 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1777206637762" ID="ID_1447848991" MODIFIED="1777206704359" TEXT="Problem hier: wir sollten gute Matches bevorzugen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
sonst besteht die Gefahr, sehr große Blöcke für kleine Anforderungen zu verschwenden und dann nachfolgend größere Allokationen anforern zu müssen, obwohl eigentlich genügend Storage lokal schon da wäre
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1777206710869" ID="ID_1181820372" MODIFIED="1777230701643">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Schwierige Entscheidung: <b>Laufzeit-Trend ist nicht bekannt</b>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Insofern weiß man nicht einmal, ob der Aufwand hier bedeutsam ist, oder man einfach einen Vector sortieren könnte
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1777206798288" ID="ID_226587276" MODIFIED="1777230690484" TEXT="mögliche Ansätze">
|
||||
|
|
@ -146031,29 +146029,23 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1777206894812" ID="ID_1484542373" MODIFIED="1777206896343" TEXT="Pass-1 gute Matches"/>
|
||||
<node CREATED="1777206897340" ID="ID_623647353" MODIFIED="1777207043059" TEXT="dann Pass-2 erst mal Kandidaten in einen Vector sammeln">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Das Problem hierbei ist, daß wir dafür bereits Aufwand treiben müssen, der u.U den Aufwand für das Sortieren übersteigt
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1777206924680" ID="ID_849247711" MODIFIED="1777207115135" TEXT="oder bei kleiner Zahl fehlender Allokationen diese einfach nicht reservieren">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Da wir letztlich sowiso einen Pool-Allokator haben, kann es durchaus sinnvoll sein, neue Allokationen zu holen, und die unpassenden alten Allokationen zeitnah aber asynchron zum Pool zurückzuschicken
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1777207118494" ID="ID_979090781" MODIFIED="1777207124089" TEXT="Hybrid-Lösung">
|
||||
<node CREATED="1777207132147" ID="ID_229232835" MODIFIED="1777207150800" TEXT="sofort ein kleines Array auf dem Stack bereitlegen"/>
|
||||
|
|
@ -146070,8 +146062,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1777050457640" ID="ID_55967690" MODIFIED="1777084249904" TEXT="Dokumentieren per Test">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1777050457640" ID="ID_55967690" MODIFIED="1777315081840" TEXT="Dokumentieren per Test">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1777050471715" ID="ID_694034532" MODIFIED="1777250236591" STYLE="fork" TEXT="LocalMemPool_test">
|
||||
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="info"/>
|
||||
|
|
@ -146082,14 +146074,21 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node COLOR="#338800" CREATED="1777052647931" ID="ID_1721020388" MODIFIED="1777252434731" TEXT="verify_matchAlloc">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1777052660303" ID="ID_1192169892" MODIFIED="1777255538360" TEXT="verify_selectAlloc">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1777052660303" FOLDED="true" ID="ID_1192169892" MODIFIED="1777317299301" TEXT="verify_selectAlloc">
|
||||
<linktarget COLOR="#eafdb6" DESTINATION="ID_1192169892" ENDARROW="Default" ENDINCLINATION="168;-26;" ID="Arrow_ID_1362515070" SOURCE="ID_1170538606" STARTARROW="None" STARTINCLINATION="15;61;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1777255542851" ID="ID_1123855450" MODIFIED="1777255577205" TEXT="hier gezielt einen Mismatch provozieren"/>
|
||||
<node CREATED="1777255578550" ID="ID_912741988" MODIFIED="1777255590015" TEXT="zeigen daß dieser nicht für Reservierung herangezogen wird..."/>
|
||||
<node CREATED="1777255590787" ID="ID_1143192408" MODIFIED="1777255607747" TEXT="jedoch stets versucht wird, alle Allokations-Requests direkt zu befriedigen"/>
|
||||
<node CREATED="1777255608745" ID="ID_832626969" MODIFIED="1777255619923" TEXT="dann aber auch die Scores anschauen..."/>
|
||||
<node CREATED="1777315047141" ID="ID_1195705832" MODIFIED="1777315071055" TEXT="sinnvollerweise hier auch gleich das Aufräumen mit testen">
|
||||
<linktarget COLOR="#f2ddc1" DESTINATION="ID_1195705832" ENDARROW="Default" ENDINCLINATION="16;47;" ID="Arrow_ID_296050493" SOURCE="ID_924547131" STARTARROW="None" STARTINCLINATION="85;12;"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#5b280f" CREATED="1777052670304" ID="ID_924547131" MODIFIED="1777315077071" TEXT="verify_pruneAlloc">
|
||||
<arrowlink COLOR="#f2ddc1" DESTINATION="ID_1195705832" ENDARROW="Default" ENDINCLINATION="16;47;" ID="Arrow_ID_296050493" STARTARROW="None" STARTINCLINATION="85;12;"/>
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
</node>
|
||||
<node CREATED="1777052670304" ID="ID_924547131" MODIFIED="1777052674241" TEXT="verify_pruneAlloc"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776819109351" ID="ID_1998897998" MODIFIED="1776819155584" TEXT="EngineBufferManager">
|
||||
|
|
|
|||
Loading…
Reference in a new issue