Library: clarify details of the low-level allocation

- rather accept hard-wired limits than making the implementation excessively generic
- by exploiting the layout, the administrative overhead can be reduced significantly
- the trick with the "virtual managment overlay" allows to hand-off most of the
  clean-up work to C++ destructor invocation
- it is important to verify these low-level arrangements explicitly by unit-test
This commit is contained in:
Fischlurch 2024-05-19 17:53:51 +02:00
parent 72aea53ac3
commit 13e22f315a
4 changed files with 230 additions and 150 deletions

View file

@ -33,8 +33,6 @@
#include "lib/linked-elements.hpp"
#include "lib/util.hpp"
#include <cstddef>
#include <memory>
using util::isnil;
@ -87,6 +85,7 @@ namespace lib {
using Destructors = lib::LinkedElements<Destructor>;
struct Extent
: util::NonCopyable
{
Extent* next;
Destructors dtors;
@ -116,13 +115,21 @@ namespace lib {
prependNextBlock();
}
void
discardAll()
{
closeCurrentBlock();
view_.extents.clear();
}
private:
void
closeCurrentBlock()
{
ASSERT (view_.storage.pos);
// relocate the pos-pointer to the start of the block
view_.storage.pos += view_.storage.rest - EXTENT_SIZ;
view_.storage.pos = static_cast<std::byte*>(view_.storage.pos)
+ view_.storage.rest - EXTENT_SIZ;
view_.storage.rest = 0;
}
@ -154,9 +161,8 @@ namespace lib {
AllocationCluster::~AllocationCluster() noexcept
try
{
TRACE (memory, "shutting down AllocationCluster");
StorageManager::access(*this).discardAll();
}
ERROR_LOG_AND_IGNORE (progress, "discarding AllocationCluster")
@ -185,6 +191,17 @@ namespace lib {
UNIMPLEMENTED ("size limits"); ///////////////////////////OOO enforce maximum size limits
}
size_t
AllocationCluster::numExtents() const
{
UNIMPLEMENTED ("Allocation management");
}
size_t
AllocationCluster::numBytes() const
{
UNIMPLEMENTED ("Allocation management");
}
} // namespace lib

View file

@ -45,12 +45,12 @@
#include "lib/error.hpp"
#include "lib/nocopy.hpp"
#include <utility> ///////////////////OOO woot?
#include <memory>
namespace lib {
namespace test { class AllocationCluster_test; } // declared friend for low-level-checks
/**
@ -104,6 +104,18 @@ namespace lib {
{
void* pos{nullptr};
size_t rest{0};
void*
allot (size_t bytes, size_t alignment)
{
void* loc = std::align (alignment, bytes, pos, rest);
if (loc)
{ // requested allocation indeed fits in space
pos = static_cast<std::byte*>(pos) + bytes;
rest -= bytes;
}
return loc;
}
};
Storage storage_;
@ -129,17 +141,8 @@ namespace lib {
/* === diagnostics === */
size_t
numExtents() const
{
UNIMPLEMENTED ("Allocation management");
}
size_t
numBytes() const
{
UNIMPLEMENTED ("Allocation management");
}
size_t numExtents() const;
size_t numBytes() const;
private:
@ -151,12 +154,10 @@ namespace lib {
allotMemory (size_t bytes, size_t alignment)
{
ENSURE (_is_within_limits (bytes, alignment));
void* loc = std::align (alignment, bytes, storage_.pos, storage_.rest);
if (loc)
return loc;
void* loc = storage_.allot(bytes, alignment);
if (loc) return loc;
expandStorage (bytes);
return allotMemory (bytes, alignment);
///////////////////////////////////////////////////////////OOO claim next macro block
}
template<typename X>
@ -168,6 +169,8 @@ namespace lib {
void expandStorage (size_t);
bool _is_within_limits (size_t,size_t);
friend class test::AllocationCluster_test;
};

View file

@ -49,6 +49,7 @@ using std::numeric_limits;
using std::function;
using std::vector;
using std::array;
using std::byte;
@ -61,6 +62,8 @@ namespace test {
const uint NUM_TYPES = 20;
const uint NUM_OBJECTS = 500;
const size_t BLOCKSIZ = 256; ///< @warning actually defined in allocation-cluster.cpp
long checksum = 0; // validate proper pairing of ctor/dtor calls
template<uint i>
@ -141,8 +144,10 @@ namespace test {
virtual void
run (Arg)
{
simpleUsage();
checkLifecycle();
// simpleUsage();
// checkLifecycle();
verifyInternals();
use_as_Allocator();
}
@ -163,8 +168,7 @@ namespace test {
CHECK (123==ref2.getID());
CHECK (45 ==ref3.getID());
CHECK (1 == clu.numExtents());
CHECK (66+77+77 == clu.numBytes());
CHECK (1 == clu.numExtents());
// now use objects and just let them go;
}
@ -182,6 +186,50 @@ namespace test {
}
CHECK (0==checksum);
}
/** @test cover some tricky aspects of the low-level allocator
* @remark due to the expected leverage of AllocationCluster,
* an optimised low-level approach was taken on various aspects of storage management;
* the additional metadata overhead is a power of two, exploiting contextual knowledge
* about layout; moreover, a special usage-mode allows to skip invocation of destructors.
* To document these machinations, change to internal data is explicitly verified here.
* @todo WIP 5/24 🔁 define implement
*/
void
verifyInternals()
{
CHECK (0==checksum);
{
AllocationCluster clu;
CHECK (0 == clu.numExtents());
CHECK (0 == clu.numBytes());
auto i1 = clu.create<uint16_t> (1 + uint16_t(rand()));
CHECK (i1 > 0);
CHECK (1 == clu.numExtents());
SHOW_EXPR(clu.numBytes())
SHOW_EXPR(clu.storage_.rest);
SHOW_EXPR(clu.storage_.pos);
byte* blk = static_cast<std::byte*>(clu.storage_.pos);
SHOW_EXPR(blk);
CHECK (blk);
blk += clu.storage_.rest - BLOCKSIZ;
SHOW_EXPR(blk);
SHOW_EXPR(blk[0]);
}
CHECK (0==checksum);
}
/** @test TODO demonstrate use as Standard-Allocator
* @todo WIP 5/24 🔁 define implement
*/
void
use_as_Allocator()
{
UNIMPLEMENTED ("Clusterfuck");
}
};
LAUNCHER (AllocationCluster_test, "unit common");

View file

@ -80686,9 +80686,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1715625311161" ID="ID_1762606958" MODIFIED="1715625461924" TEXT="der unterliegende Memory-Manager ist ungekl&#xe4;rt">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
An der Stelle habe ich nicht weiter analysiert, sondern einfach Heap-Allokationen gemacht; der Grund seinerzeit war, da&#223; Christian den &#187;Mempool&#171; &#252;berall einf&#252;hren wollte &#8212; ein Ansatz, den ich grunds&#228;tzlich unterst&#252;tzte, wenngleich auch seine Implementierung zu einfach war, und ich damit diesen use-Case nicht sauber realisieren konnte. Damit unterblieben aber weitere &#220;berlegungen zum Allocation-Trend
@ -80699,9 +80697,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715625485709" ID="ID_323773842" MODIFIED="1715625503477" TEXT="zu viel Locking &#x2014; und m&#xf6;glicherweise an der falschen Stelle"/>
<node CREATED="1715625511889" HGAP="39" ID="ID_1920622182" MODIFIED="1715625840520" TEXT="Effizienz der Familien-Pools erscheint fragw&#xfc;rdig" VSHIFT="-29">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
damals hatte ich als Vorbild den <i>small-objects pool allocator </i>von Alexandrescu im Kopf; deshalb habe ich auch &#187;Familien&#171; von Objekten vorgesehen &#8212; ohne jedoch zu kl&#228;ren, ob und wie sich daraus ein Amortisierungs-Effekt ergibt. Nach gr&#252;ndlicherer &#220;berlegung erscheint mir das als ein Widerspruch im Konzept, denn diese small-objects-Pools laufen ja auf ein Tiling mit fortlaufend stattfindedenden Allokationen hinaus; das ist exakt das Gegenteil von dem, was mir hier vorschwebt. Damit w&#252;rden die Einzelpools nur Administrations-Overhead verursachen, der seine Vorteile &#252;berhaupt nicht ausspielen kann; stattdessen sollte besser in Betracht gezogen werden, alles heterogen, so wie es kommt, in gr&#246;&#223;ere Bl&#246;cke zu packen. Das Tiling w&#252;rde damit auf einem gr&#246;&#223;eren Level stattfinden, und w&#228;re in den Basis-Allocator verlagert...
@ -80989,9 +80985,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715530949227" ID="ID_1291999667" MODIFIED="1715530962507" TEXT="der Storage-Typ soll u.U verborgen bleiben">
<node CREATED="1715532362924" ID="ID_737856207" MODIFIED="1715532421822">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
&#10233; Konsequenz: zus&#228;tzlicher Template-Parameter f&#252;r das<i>&#160;Spacing</i>
@ -81053,9 +81047,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715532986380" ID="ID_1926875856" MODIFIED="1715533015979" TEXT="damit sind essentielle Architektur-Freiheitsgrade ausgeschlossen"/>
<node CREATED="1715533016635" ID="ID_453024557" MODIFIED="1715533035171">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
oder man bekommt eine<i>&#160;implizite Runtime</i>
@ -81075,9 +81067,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715533228879" ID="ID_1909155403" MODIFIED="1715533251166" TEXT="der Destruktor mu&#xdf; wissen wie der Storage-Block freizugeben ist"/>
<node CREATED="1715533251792" ID="ID_1479555840" MODIFIED="1715533283445" TEXT="u.u. mu&#xdf; &#xfc;berhaupt keine Freigabe gemacht werden">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
wenn die Daten &#8222;woanders&#8220; liegen
@ -81087,9 +81077,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715533317000" ID="ID_252143573" MODIFIED="1715533493572">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
&#10233; das <b>Allocator-Problem</b>&#160;&#252;bertr&#228;gt sich <b>komplett</b>&#160; auf den Container selber
@ -81097,9 +81085,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
warum? weil man dann zwingend im Container selber einen &#187;Slot&#171; mit einem Functor oder Allocator-Pointer rumschleppt &#8212; oder doch wieder einen zus&#228;tzlichen Instanz-Typ-Tag
@ -81118,9 +81104,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<edge COLOR="#6a3645" STYLE="linear"/>
<node CREATED="1715618937215" ID="ID_975786159" MODIFIED="1715619229829" TEXT="Tag oder Allocator-Link in jeder Instanz">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Sorge:
@ -81141,9 +81125,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715618955861" ID="ID_189897298" MODIFIED="1715619378057" TEXT="dann halt doch blo&#xdf; Heap-Allokationen machen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Da der Heap-Allokator inzwischen ziemlich performant ist, k&#246;nnte man damit durchkommen...
@ -81165,9 +81147,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715620143727" ID="ID_828708828" MODIFIED="1715620159863" TEXT="Zugriff auf den Allocator per DI (statisch) oder Thread-local"/>
<node CREATED="1715620242056" ID="ID_427769562" MODIFIED="1715620649844" TEXT="Spezieller Allocator mit Block-de-Allocation">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...man verwendet <i>nur speziell im produktiven Einsatz im Node-Graph</i>&#160; einen besonderen Allocator, der zwar den Destruktor aufruf, aber den Speicher nicht freigibt; alloziert wird immer in einen kompakten Block hinein, der dann auf der Basis der Proze&#223;-Kenntnis als Ganzes verworfen und neu verwendet wird.
@ -81185,9 +81165,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715624604522" ID="ID_1995705427" MODIFIED="1715624613764" TEXT="analog zu std::vector"/>
<node CREATED="1715624614444" ID="ID_1920430377" MODIFIED="1715624773441" TEXT="direkt implementieren erscheint sinnvoll">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...weil std::vector zwar bereits alles bietet, aber eingebettet in sehr komplexen Code &#8212; im Besonderen d&#252;rfte es schwierig werden, das Thema on-demand-growth vs non-copyable zu umschiffen
@ -81203,9 +81181,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715625022874" ID="ID_158782942" MODIFIED="1715625045459" TEXT="Allocator externalisieren (wie in STDL-Containern)"/>
<node CREATED="1715627229164" ID="ID_1793700784" MODIFIED="1715627351601" TEXT="das Concept ist f&#xfc;r sp&#xe4;ter aufgehoben">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...das hei&#223;t, ich gehe mal davon aus, da&#223; ich mit einer einzigen, dedizierten Implementierung erst mal den aktuellen Bedarf decken kann; daraus k&#246;nnte allerdings sp&#228;ter immer noch ein Concept gemacht werden, welches dann alternativ auch durch ScopedCollection oder durch eine embedded-storage-L&#246;sung erf&#252;llt werden kann.
@ -81222,9 +81198,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#fd2206" DESTINATION="ID_741455291" ENDARROW="Default" ENDINCLINATION="371;-21;" ID="Arrow_ID_148841438" SOURCE="ID_748407633" STARTARROW="None" STARTINCLINATION="988;41;"/>
<node CREATED="1715625871491" ID="ID_1677812273" MODIFIED="1715626046458" TEXT="man kann das definitiv passender implementieren">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
heterogene Allokation in eine Sequenz gr&#246;&#223;erer Bl&#246;cke; keinerlei de-Allokation und kein Locking
@ -81234,9 +81208,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715625881800" ID="ID_1460908503" MODIFIED="1715626254822" TEXT="man k&#xf6;nnte aber die bestehende Impl. erst mal ungesehen verwenden">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...sie ist ja fertig und getestet, und wartet seit Jahren auf ihren Einsatz; allerdings w&#228;re ein solches Vorgehen erkl&#228;rungsbed&#252;rftig
@ -81260,9 +81232,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715625901869" ID="ID_460237769" MODIFIED="1715626344549" TEXT="oder aber gleich ganz liegen lassen und blo&#xdf; Heap-Allokationen machen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...<i>wenn man schon </i>die bestehenden Implementierung nutzt (wohl wissend, da&#223; ihre inh&#228;renten Probleme erst mal nicht relevant sind), dann kann man genausogut <i>ganz auf bl&#246;d </i>sich auf den KISS-Standpunkt stellen und einfach Heap-Allokationen machen, denn die sind heutzutage verdammt effizient geworden
@ -81272,9 +81242,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715625929114" ID="ID_704028431" MODIFIED="1715625953412">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
...und alles das l&#228;uft auf weitere <b>technische Schulden</b>&#160;hinaus
@ -81288,9 +81256,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715626414697" ID="ID_280677111" MODIFIED="1715626425820" TEXT="durch den Namen w&#xe4;re die Kontinuit&#xe4;t pro Forma gewahrt"/>
<node CREATED="1715626476945" ID="ID_1929954995" MODIFIED="1715626592916" TEXT="es gibt bisher nur minimale / vorbereitende Verwendungen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...die allesamt mit dem Model + Player zu tun haben; einzige externe Verkoppelung ist der LinkedElements_test, und auch dieser stellt explizit einen Vorgriff auf die Verwendung im low-level-Model dar.
@ -81300,9 +81266,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715626599088" ID="ID_1068758723" MODIFIED="1715626653670" TEXT="das API ist schmal und k&#xf6;nnte inkrementell umgestaltet werden">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...da der davon abh&#228;ngende Code <i>effektiv nur compilierbar ist, aber nicht lauff&#228;hig</i>
@ -81315,9 +81279,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715626731957" ID="ID_454366756" MODIFIED="1715626737099" TEXT="die Typ-Slots fallen weg"/>
<node CREATED="1715626755683" ID="ID_714015643" MODIFIED="1715626839992" TEXT="das &quot;commit&quot;-Konzept wird aufgegeben">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
let it crash &#8212; wenn tats&#228;chlich eine Exception fliegt, ist es ziemlich wahrscheinlich, da&#223; der ganze Cluster sowiso weggeworfen wird; wenn nicht, dann akzeptieren wir einfach toten Speicher.
@ -81327,9 +81289,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715626853846" ID="ID_540898270" MODIFIED="1715626985387">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
die Bedeutung ist <b>geringer geworden</b>
@ -81337,9 +81297,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
seinerzeit habe ich im AllocationCluster etwas gesehen, da&#223; pervasiv &#252;berall im Code verwendet wird, analog zum Mempool. Inzwischen stehe ich auf dem Standpunkt, da&#223; f&#252;r die meisten Allokationen der Standard-Heap-Allokator sowiso gut genug ist (oder man nutzt ohnehin den Stack oder eine statische Variable); spezielle Allokatoren sind nach meinem heutigen Verst&#228;ndnis nur noch sinnvoll, wenn sie extrem spezifisch sind
@ -81353,9 +81311,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="yes"/>
<node CREATED="1715627069918" ID="ID_1496924967" MODIFIED="1715627170299" TEXT="es k&#xf6;nnte n&#xe4;mlich eine Konvergenz geben">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...oder zumindest k&#246;nnte man ein limitiertes Teil-Konzept umsetzen; mir f&#228;llt auf, da&#223; diverse Methoden im Standard-Allocator inzwischen durch Traits ersetzt wurden.
@ -81699,9 +81655,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="flag-yellow"/>
<node CREATED="1715985108575" ID="ID_1415977694" MODIFIED="1715988173554" TEXT="das kann man der Standard-Lib &#xfc;berlassen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
alignof()-Operator und die Hilfsfunktion std::align()
@ -81728,6 +81682,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715819811133" ID="ID_1658998228" LINK="https://en.cppreference.com/w/cpp/memory/align" MODIFIED="1715819832631" TEXT="damit kann man die std::align()-Funktion verwenden">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1716118457030" ID="ID_727790432" MODIFIED="1716118471958" TEXT="die macht allerdings nur die halbe Arbeit (grrr)">
<icon BUILTIN="smiley-angry"/>
</node>
</node>
<node CREATED="1715819526899" ID="ID_53500032" MODIFIED="1715819535331" TEXT="am Anfang jeden Blocks">
<node CREATED="1715819536259" ID="ID_1810416594" MODIFIED="1715819553483" TEXT="pred* zum Vorg&#xe4;nger"/>
@ -81742,8 +81699,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715820259913" ID="ID_13842300" MODIFIED="1715820269104" TEXT="Check f&#xfc;r zu gro&#xdf;e Objekte">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715820289221" ID="ID_1541316374" MODIFIED="1715820300780" TEXT="&#xdc;berlauf: neuen Block belegen">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1715820289221" ID="ID_1541316374" MODIFIED="1716130701433" TEXT="&#xdc;berlauf: neuen Block belegen">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1715990297583" ID="ID_389684421" MODIFIED="1715990309548" TEXT="direkt per Standard-Allocator belegen">
<icon BUILTIN="button_ok"/>
</node>
@ -81751,9 +81708,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="idea"/>
<node CREATED="1715991737062" ID="ID_690246579" MODIFIED="1715991797332" TEXT="Zweck: absolutes Minimum an Overhead">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
auch: eine gradzahlige Anzahl an Overhead-Slots
@ -81764,9 +81719,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715991799166" ID="ID_1984378311" MODIFIED="1715991936313" TEXT="Trick: aktuellen Block-Start rekonstruieren">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...durch diesen Trick sparen wir uns einen zus&#228;tzlichen Pointer auf den aktuellen Block: da std::allign(pos,rest) den pos-Zeiger stets koh&#228;rent zusammen mit dem rest-cnt manipuliert, k&#246;nnen wir stets aus beiden zusammen wieder zum Anfang des Blocks zur&#252;ckfinden.
@ -81791,9 +81744,93 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="clanbomber"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1716130707355" ID="ID_596338208" MODIFIED="1716130715686" TEXT="Korrektheit verifizieren...">
<icon BUILTIN="flag-pink"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715820305436" ID="ID_1741026762" MODIFIED="1715820308396" TEXT="Clean-up">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1716129938550" ID="ID_1201172803" MODIFIED="1716129943077" TEXT="C++ Magie">
<icon BUILTIN="idea"/>
<node CREATED="1716129945797" ID="ID_582558526" MODIFIED="1716129956272" TEXT="die LinkedElements machen bereits die gesamte Arbeit"/>
<node CREATED="1716129960607" ID="ID_1980733813" MODIFIED="1716129976045" TEXT="das kaskadiert auf den Destruktor von StorageManager::Extent"/>
<node CREATED="1716129979176" ID="ID_350853857" MODIFIED="1716130098741" TEXT="auch der dtor von struct StorageManager::Destructor wird automatisch aufgerufen">
<arrowlink COLOR="#faf8b2" DESTINATION="ID_1028046936" ENDARROW="Default" ENDINCLINATION="102;3;" ID="Arrow_ID_1495010693" STARTARROW="None" STARTINCLINATION="118;4;"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716130029614" ID="ID_229036433" MODIFIED="1716130547847" TEXT="automatischer Destruktor-Aufruf">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1716130041704" ID="ID_1028046936" MODIFIED="1716130101251" TEXT="kann getriggert werden von StorageManager::Destructor">
<linktarget COLOR="#faf8b2" DESTINATION="ID_1028046936" ENDARROW="Default" ENDINCLINATION="102;3;" ID="Arrow_ID_1495010693" SOURCE="ID_350853857" STARTARROW="None" STARTINCLINATION="118;4;"/>
</node>
<node CREATED="1716130117046" ID="ID_709395607" MODIFIED="1716130132557" TEXT="brauche aber zwingend 2 Slots f&#xfc;r die Infos">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1716130135948" ID="ID_287898352" MODIFIED="1716130151093" TEXT="ein generischer Function-Pointer f&#xfc;r den Deleter pro Typ"/>
<node CREATED="1716130156393" ID="ID_1607777465" MODIFIED="1716130162416" TEXT="ein Pointer auf die Instanz"/>
<node CREATED="1716130163152" ID="ID_1665340987" MODIFIED="1716130423856" TEXT="das kann man nicht sinnvoll weiter reduzieren">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
wie man's auch dreht und wendet: irgendwo mu&#223; die Typ-Information explizit untergrebracht werden, da wir sie vom Allocation-Cluster selber entfernt haben (dieser ist nun generisch und kann einen beliebigen Mix von Objekten/Typen allozieren). Das einzige, was man machen k&#246;nnte, w&#228;re diese Info komprimiert abzuspeichern....
</p>
</body>
</html></richcontent>
</node>
</node>
<node CREATED="1716130427556" ID="ID_1706956114" MODIFIED="1716130452412" TEXT="besser explizit hier ausprogrammieren">
<icon BUILTIN="yes"/>
<node CREATED="1716130453905" ID="ID_1560112065" MODIFIED="1716130462700" TEXT="man k&#xf6;nnte auch unique_ptr verwenden"/>
<node CREATED="1716130463711" ID="ID_681909128" MODIFIED="1716130467289" TEXT="oder eine Hilfsklasse"/>
<node CREATED="1716130467903" ID="ID_48375961" MODIFIED="1716130545437" TEXT="aber letztlich ist in einer solchen low-Level-Impl die Offenbarkeit wichtiger">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...da man sich diesen Code ohnehin nur anschaut, wenn man mu&#223;, ist nichts mehr gewonnen, weitere Details nochmal durch eine Indirektion zu verbergen
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node CREATED="1716130557432" ID="ID_1302192320" MODIFIED="1716130574360" TEXT="Layout-Trick: der Destructor-Descriptor liegt direkt vor dem Objekt">
<icon BUILTIN="idea"/>
<node CREATED="1716130576094" ID="ID_729612624" MODIFIED="1716130606365" TEXT="damit ist eine der zwei notwendigen Infos implizit">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...n&#228;mlich die Speicheradresse der Instanz
</p>
</body>
</html></richcontent>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716130607500" ID="ID_641247354" MODIFIED="1716130643729" TEXT="brauche somit nur noch einen Trampolin-Pointer">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1716130724127" ID="ID_727448469" MODIFIED="1716133312180" TEXT="low-level-Test">
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1716130730820" ID="ID_539013579" MODIFIED="1716130744964" TEXT="ich mache hier gef&#xe4;hrliche Sachen">
<icon BUILTIN="clanbomber"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716130764415" ID="ID_966285930" MODIFIED="1716130831111" TEXT="explizit zu verifizieren">
<icon BUILTIN="yes"/>
<node CREATED="1716130773434" ID="ID_643589646" MODIFIED="1716130792420" TEXT="Destruktoren werden aufgerufen &#x27f9; Pr&#xfc;fsumme"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716130797235" ID="ID_532362151" MODIFIED="1716130811753" TEXT="Pointer und Gr&#xf6;&#xdf;e werden korrekt bewegt">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716130812393" ID="ID_136785264" MODIFIED="1716130824328" TEXT="Connectivity der virtuellen Management-Datenstruktur">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node COLOR="#338800" CREATED="1716130832134" ID="ID_1783945506" MODIFIED="1716133346231" TEXT="hierf&#xfc;r einen friend-Test schaffen">
<linktarget COLOR="#4173be" DESTINATION="ID_1783945506" ENDARROW="Default" ENDINCLINATION="204;17;" ID="Arrow_ID_1547348126" SOURCE="ID_253325898" STARTARROW="None" STARTINCLINATION="292;-22;"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
</node>
@ -81802,9 +81839,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="flag-yellow"/>
<node CREATED="1715790397014" ID="ID_14966020" MODIFIED="1715790537195" TEXT="Ergebnis einer Konfliktl&#xf6;sung">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
In diesem Konflikt stehen zwei gleicherma&#223;en bedeutsame Belange gegeneinander, ohne einen klaren Ansatz zur Entscheidung
@ -81829,9 +81864,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715790571755" ID="ID_1943399206" MODIFIED="1715790774444" TEXT="die Factory-Funktion(en) bieten eine direkte Wahlm&#xf6;glichkeit">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...somit kann auf Basis der einzelnen, konkreten Datenstruktur entschieden (und sp&#228;ter auch korrigiert) werden, ob ein expliziter clean-up-Aufruf notwendig ist; f&#252;r die einzelne Datenstruktur d&#252;rfte das lokal jeweils klar entscheidbar sein, und ich erwarte, da&#223; durch die Anbindung an den Allocation-Cluster diese Entscheidungsm&#246;glichkeit auch langfristig klar dokumentiert ist &#8212; und zwar sollte das von &#252;blichen C++ Praktiken abweichende Verhalten auch als der Spezialfall dargestellt sein (wenngleich auch erwartet wird, da&#223; die meisten Datenstrukturen von diesem Spezialfall gebrauch machen)
@ -81860,6 +81893,13 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715783068923" ID="ID_34296369" MODIFIED="1715783077530" TEXT="Tests f&#xfc;r Error-Handling zur&#xfc;ckbauen">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716130852555" ID="ID_1309770620" MODIFIED="1716130866602" TEXT="Test f&#xfc;r interne low-level-Mechanismen">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716130874040" ID="ID_253325898" MODIFIED="1716133346231" TEXT="verifyInternals">
<arrowlink COLOR="#4173be" DESTINATION="ID_1783945506" ENDARROW="Default" ENDINCLINATION="204;17;" ID="Arrow_ID_1547348126" STARTARROW="None" STARTINCLINATION="292;-22;"/>
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715782674401" ID="ID_1481008630" MODIFIED="1715782690591" TEXT="neue Tests f&#xfc;r Verwendung mit STL-Container">
<icon BUILTIN="flag-yellow"/>
</node>
@ -82043,9 +82083,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715786632528" ID="ID_1174378095" MODIFIED="1715786635293" TEXT="pro">
<node CREATED="1715786712311" ID="ID_343417643" MODIFIED="1715787719344" TEXT="t&#xfc;ckisches Wartungs-Risiko">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Kurzfristig erscheint das als eine naheliegende Optimierung, die einem praktisch &#187;in den Scho&#223; f&#228;llt&#171; (die Implementierung wird dadurch sogar drastisch einfacher). Aber l&#228;ngerfristig bef&#252;rchte ich eine heimt&#252;cksiche Gefahr, denn die hier genommene Abk&#252;rzung kann leicht &#252;bersehen werden, da sie den &#252;blichen Gepflogenheiten zuwiderl&#228;uft. Im Lauf der Zeit k&#246;nnen sich so Speicher- und Ressourcen-Lecks einschleichen, die dann nur mit erheblichem und fokussiertem Aufwand aufzur&#228;umen sind
@ -82055,9 +82093,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715786638937" ID="ID_220404719" MODIFIED="1715787515314" TEXT="C++ Basis-Kontrakt: Determinismus">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Es handelt sich um eines der markanten Eigenschaften der Sprache C++ : Kontrolle und Determinismus bis ins kleinste Detail &#8212; und das pr&#228;gt den allt&#228;glichen Stil der Arbeit; weithin kann man sich auf Abstraktionen verlassen, weil diese sich wiederum auf Abstraktionen verlassen k&#246;nnen; wenn alles genau und zuverl&#228;ssig ist, dann werden auch weitreichende Aktionen planbar und handhabbar.
@ -82067,9 +82103,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715787292122" ID="ID_882850258" MODIFIED="1715787964678" TEXT="es ist ein weit-reichendes Subsystem">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Hier geht es um das gesamte low-level-Model, sowie m&#246;glicherweise Teile des Build-Prozesses und des Regelwerks, die daran angekn&#252;pft sein k&#246;nnten &#8212; und das bedeutet, mit einer (wie es zun&#228;chst scheint) sehr lokalen und tief verborgenen Optimierung k&#246;nnte der Grund-Kontrakt in einem erheblichen Teil der Applikation ge&#228;ndert werden
@ -82081,9 +82115,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715786776566" ID="ID_1885525073" MODIFIED="1715786778242" TEXT="contra">
<node CREATED="1715786936089" ID="ID_853557707" MODIFIED="1715788899468" TEXT="nicht-triviale Kosten">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Der Aufwand, der allein f&#252;r das Aufrufen der aller Destruktoren getrieben werden mu&#223;, ist nicht unerheblich, denn f&#252;r jeden Typ mu&#223; eine Closure im Datensegment erzeugt werden und f&#252;r jede einzelne Allokation mu&#223; diese per Funktionszeiger aufrufbar sein; au&#223;erdem mu&#223; die gesamte Allokation navigierbar gemacht werden &#8212; also zwei &#187;Slots&#171; zus&#228;tzlich f&#252;r jede einzelne Allokation. Das ist sehr viel f&#252;r eine Datenstruktur, die aus vielen kleinen und sehr flexiblen Descriptor-Elementen bestehen wird; die meisten Nodes haben erwartungsgem&#228;&#223; nur einen Eingang und einen Ausgang, was bedeutet, da&#223; f&#252;r jeweils nur eine einzige ID (ein &#187;Slot&#171;) zus&#228;tzlich ein Container (2 &#187;Slot&#171;) und dann noch 4 &#187;Slot&#171; Allokations-Overhead notwendig sind.
@ -82093,9 +82125,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715786779246" ID="ID_1339652048" MODIFIED="1715788973479">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
in der Regel sind es<i>&#160;cold pages</i>
@ -82103,9 +82133,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Aus Performance-Sicht besonders fatal ist, da&#223; zum Zeitpunkt der Bulk-de-Allokation mit hoher Wahrscheinlichkeit alle betroffenen memory pages bereits &#187;cold&#171; sind, d.h. aus dem Cache herausgefallen; wir m&#252;ssen also eine Menge von Speicherseiten &#252;ber den Bus ziehen, blo&#223; um sie zu navigieren und dann...
@ -82115,9 +82143,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715786817201" ID="ID_1883341443" MODIFIED="1715789112354" TEXT="90% der F&#xe4;lle brauchen keinen dtor-Aufruf">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...in den allermeisten F&#228;llen n&#228;mlich<i>&#160;exakt gar nichts</i>&#160; zu tun. Dies unter der Annahme, da&#223; die Struktur gr&#246;&#223;tenteils selbst-referentiell ist; zwar werden dadurch reihenweise verkettete Destruktor-Aufrufe stattfinden, welche aber alle letztlich beim Allocator enden, welcher dann (ganz bewu&#223;t) nichts tut, weil der gesamte Speicherblock anschlie&#223;end ohnehin verworfen wird. Da es sich jedoch um dynamisch aufgebaute Datenstrukturen handelt, kann der Optimizer diesen Leerlauf nicht erkennen und beseitigen
@ -82127,9 +82153,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715786961514" ID="ID_1214786701" MODIFIED="1715789369565" TEXT="es handelt sich um einer permanent-laufende Aktivit&#xe4;t">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Es steht zu bef&#252;rchten, da&#223; w&#228;hrend der normalen Edit-T&#228;tigkeit alle par 1/10-sec ein Builder-Lauf getriggert wird &#8212; und ich sch&#228;tze, da&#223; ein erheblicher Anteil der tats&#228;chlichen Laufzeit in das Konstruieren der Datenstruktur geht, denn der zugrundeliegende trade-off ist ja grade<i>&#160; space-for-time.</i>&#160;Wenngleich auch der Neubau ebenfalls schlecht f&#252;r den Cache ist, so kann man doch zumindet in Teilen hoffen, da&#223; die neu gebauten Strukturen zumindest bis zur ersten Ber&#252;hrung durch den Play-Proze&#223; im L3 bleiben. F&#252;r die alten Strukturen gilt das aber nicht, sie stellen rein nutzlosen Balast dar.
@ -82141,9 +82165,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715789372444" ID="ID_869337683" MODIFIED="1715789375047" TEXT="Diskussion">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1715789376067" ID="ID_1679838911" MODIFIED="1715789555443" TEXT="Gefahr: premature optimisation">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
das ist &#187;der Klassiker&#171;.
@ -82166,9 +82188,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715789753089" ID="ID_1651672024" MODIFIED="1715789767679" TEXT="absehbar ist jedoch da&#xdf; hier ein gro&#xdf;er Hebel gegeben ist"/>
<node CREATED="1715789799595" ID="ID_630552591" MODIFIED="1715790098609" TEXT="eine &#xbb;Alles oder NIchts&#xab;-Entscheidung ist sp&#xe4;ter mindestens genauso schwer">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Angenommen, ich mache diese Optimierung jetzt <b>nicht</b>, bereite sie aber vor; sp&#228;ter dann zeigt sich (mit guter Wahrscheinlichkeit) tats&#228;chlich ein relevanter Overhead &#10233; dann ist der Druck zur Optimierung umso st&#228;rker, und man wird die vorbereitete Option &#187;ziehen&#171; und die weitreichenden Konsequenzen in Kauf nehmen, da die Behebung eines konkreten Problems immer alle strategischen und methodischen Erw&#228;gungen <b>&#252;bersteuert</b>. Das w&#228;re der schlechtest m&#246;gliche Verlauf, denn zu eine so sp&#228;ten Zeitpunkt kann man kaum mehr etwas tun, um eine weitreichende &#196;nderung der Konventionen abzufedern
@ -126497,9 +126517,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<icon BUILTIN="button_cancel"/>
<node CREATED="1715723719057" ID="ID_978649638" MODIFIED="1715723916920" TEXT="naja ... nur m&#xe4;&#xdf;ig hilfreich">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
viel Gepl&#228;nkel cool-getue; tats&#228;chlich hat er schon einen eigenst&#228;ndigen Gedanken, braucht aber sehr lange, ihn auszuformulieren; und zu den schwierigen praktischen Fragen mit STL-Containern sagt er gar nichts
@ -126511,9 +126529,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1715723729266" ID="ID_850299630" MODIFIED="1715723744425" TEXT="er zeigt Design-Schw&#xe4;chen von std::allocator auf (und warum es dazu kam)"/>
<node CREATED="1715723745821" ID="ID_1740554357" MODIFIED="1715723779904">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
dann skizziert er alle wesentlichen Standard-Allocator-Patterns als<i>&#160; composable allocators</i>
@ -126533,9 +126549,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<icon BUILTIN="yes"/>
<node CREATED="1715723947185" ID="ID_98135787" MODIFIED="1715724017929" TEXT="ab C++23 ist Erweitern sogar verboten">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Begr&#252;ndung: es ist sinnlos, weil das einzige, was man dabei machen kann, ist Fehler machen. Der Standard ist extrem genau und elaboriert f&#252;r dieses Thema, und wenn man sich an wirklich alle Vorgaben h&#228;lt, hat man praktisch keinen Spielraum mehr....
@ -126545,9 +126559,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
<node CREATED="1715724019592" ID="ID_398818246" MODIFIED="1715724070307" TEXT="sinnvoll ist es den Allocator selber zu schreiben">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...bei Bedarf kann man dort sogar einige optionale Methoden zus&#228;tzlich implementieren, z.B. construct (und das wird dann auch verwendet, anstatt der Standard-Implementierung in den Traits)