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:
parent
72aea53ac3
commit
13e22f315a
4 changed files with 230 additions and 150 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -80686,9 +80686,7 @@ Date:   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ä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ß Christian den »Mempool« überall einführen wollte — ein Ansatz, den ich grundsätzlich unterstützte, wenngleich auch seine Implementierung zu einfach war, und ich damit diesen use-Case nicht sauber realisieren konnte. Damit unterblieben aber weitere Überlegungen zum Allocation-Trend
|
||||
|
|
@ -80699,9 +80697,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1715625485709" ID="ID_323773842" MODIFIED="1715625503477" TEXT="zu viel Locking — und möglicherweise an der falschen Stelle"/>
|
||||
<node CREATED="1715625511889" HGAP="39" ID="ID_1920622182" MODIFIED="1715625840520" TEXT="Effizienz der Familien-Pools erscheint fragwü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 »Familien« von Objekten vorgesehen — ohne jedoch zu klären, ob und wie sich daraus ein Amortisierungs-Effekt ergibt. Nach gründlicherer Ü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ürden die Einzelpools nur Administrations-Overhead verursachen, der seine Vorteile überhaupt nicht ausspielen kann; stattdessen sollte besser in Betracht gezogen werden, alles heterogen, so wie es kommt, in größere Blöcke zu packen. Das Tiling würde damit auf einem größeren Level stattfinden, und wäre in den Basis-Allocator verlagert...
|
||||
|
|
@ -80989,9 +80985,7 @@ Date:   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>
|
||||
⟹ Konsequenz: zusätzlicher Template-Parameter für das<i> Spacing</i>
|
||||
|
|
@ -81053,9 +81047,7 @@ Date:   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> implizite Runtime</i>
|
||||
|
|
@ -81075,9 +81067,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1715533228879" ID="ID_1909155403" MODIFIED="1715533251166" TEXT="der Destruktor muß wissen wie der Storage-Block freizugeben ist"/>
|
||||
<node CREATED="1715533251792" ID="ID_1479555840" MODIFIED="1715533283445" TEXT="u.u. muß überhaupt keine Freigabe gemacht werden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
wenn die Daten „woanders“ liegen
|
||||
|
|
@ -81087,9 +81077,7 @@ Date:   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>
|
||||
⟹ das <b>Allocator-Problem</b> überträgt sich <b>komplett</b>  auf den Container selber
|
||||
|
|
@ -81097,9 +81085,7 @@ Date:   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 »Slot« mit einem Functor oder Allocator-Pointer rumschleppt — oder doch wieder einen zusätzlichen Instanz-Typ-Tag
|
||||
|
|
@ -81118,9 +81104,7 @@ Date:   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:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
<node CREATED="1715618955861" ID="ID_189897298" MODIFIED="1715619378057" TEXT="dann halt doch bloß Heap-Allokationen machen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Da der Heap-Allokator inzwischen ziemlich performant ist, könnte man damit durchkommen...
|
||||
|
|
@ -81165,9 +81147,7 @@ Date:   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>  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ß-Kenntnis als Ganzes verworfen und neu verwendet wird.
|
||||
|
|
@ -81185,9 +81165,7 @@ Date:   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 — im Besonderen dürfte es schwierig werden, das Thema on-demand-growth vs non-copyable zu umschiffen
|
||||
|
|
@ -81203,9 +81181,7 @@ Date:   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ür später aufgehoben">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...das heißt, ich gehe mal davon aus, daß ich mit einer einzigen, dedizierten Implementierung erst mal den aktuellen Bedarf decken kann; daraus könnte allerdings später immer noch ein Concept gemacht werden, welches dann alternativ auch durch ScopedCollection oder durch eine embedded-storage-Lösung erfüllt werden kann.
|
||||
|
|
@ -81222,9 +81198,7 @@ Date:   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ößerer Blöcke; keinerlei de-Allokation und kein Locking
|
||||
|
|
@ -81234,9 +81208,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
<node CREATED="1715625881800" ID="ID_1460908503" MODIFIED="1715626254822" TEXT="man kö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äre ein solches Vorgehen erklärungsbedürftig
|
||||
|
|
@ -81260,9 +81232,7 @@ Date:   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ß Heap-Allokationen machen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...<i>wenn man schon </i>die bestehenden Implementierung nutzt (wohl wissend, daß ihre inhärenten Probleme erst mal nicht relevant sind), dann kann man genausogut <i>ganz auf blö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:   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äuft auf weitere <b>technische Schulden</b> hinaus
|
||||
|
|
@ -81288,9 +81256,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1715626414697" ID="ID_280677111" MODIFIED="1715626425820" TEXT="durch den Namen wäre die Kontinuitä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:   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önnte inkrementell umgestaltet werden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...da der davon abhängende Code <i>effektiv nur compilierbar ist, aber nicht lauffähig</i>
|
||||
|
|
@ -81315,9 +81279,7 @@ Date:   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 "commit"-Konzept wird aufgegeben">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
let it crash — wenn tatsächlich eine Exception fliegt, ist es ziemlich wahrscheinlich, daß der ganze Cluster sowiso weggeworfen wird; wenn nicht, dann akzeptieren wir einfach toten Speicher.
|
||||
|
|
@ -81327,9 +81289,7 @@ Date:   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:   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ß pervasiv überall im Code verwendet wird, analog zum Mempool. Inzwischen stehe ich auf dem Standpunkt, daß fü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ändnis nur noch sinnvoll, wenn sie extrem spezifisch sind
|
||||
|
|
@ -81353,9 +81311,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1715627069918" ID="ID_1496924967" MODIFIED="1715627170299" TEXT="es könnte nämlich eine Konvergenz geben">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...oder zumindest könnte man ein limitiertes Teil-Konzept umsetzen; mir fällt auf, daß diverse Methoden im Standard-Allocator inzwischen durch Traits ersetzt wurden.
|
||||
|
|
@ -81699,9 +81655,7 @@ Date:   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 überlassen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
alignof()-Operator und die Hilfsfunktion std::align()
|
||||
|
|
@ -81728,6 +81682,9 @@ Date:   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änger"/>
|
||||
|
|
@ -81742,8 +81699,8 @@ Date:   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ür zu große Objekte">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715820289221" ID="ID_1541316374" MODIFIED="1715820300780" TEXT="Überlauf: neuen Block belegen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1715820289221" ID="ID_1541316374" MODIFIED="1716130701433" TEXT="Ü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:   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:   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ätzlichen Pointer auf den aktuellen Block: da std::allign(pos,rest) den pos-Zeiger stets kohärent zusammen mit dem rest-cnt manipuliert, können wir stets aus beiden zusammen wieder zum Anfang des Blocks zurückfinden.
|
||||
|
|
@ -81791,9 +81744,93 @@ Date:   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ür die Infos">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1716130135948" ID="ID_287898352" MODIFIED="1716130151093" TEXT="ein generischer Function-Pointer fü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ß 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önnte, wä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ö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ß, 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ä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ä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 ⟹ Prüfsumme"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716130797235" ID="ID_532362151" MODIFIED="1716130811753" TEXT="Pointer und Größ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ü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:   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ösung">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
In diesem Konflikt stehen zwei gleichermaßen bedeutsame Belange gegeneinander, ohne einen klaren Ansatz zur Entscheidung
|
||||
|
|
@ -81829,9 +81864,7 @@ Date:   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öglichkeit">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...somit kann auf Basis der einzelnen, konkreten Datenstruktur entschieden (und später auch korrigiert) werden, ob ein expliziter clean-up-Aufruf notwendig ist; für die einzelne Datenstruktur dürfte das lokal jeweils klar entscheidbar sein, und ich erwarte, daß durch die Anbindung an den Allocation-Cluster diese Entscheidungsmöglichkeit auch langfristig klar dokumentiert ist — und zwar sollte das von üblichen C++ Praktiken abweichende Verhalten auch als der Spezialfall dargestellt sein (wenngleich auch erwartet wird, daß die meisten Datenstrukturen von diesem Spezialfall gebrauch machen)
|
||||
|
|
@ -81860,6 +81893,13 @@ Date:   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ür Error-Handling zurückbauen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716130852555" ID="ID_1309770620" MODIFIED="1716130866602" TEXT="Test fü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ür Verwendung mit STL-Container">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
|
|
@ -82043,9 +82083,7 @@ Date:   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ückisches Wartungs-Risiko">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Kurzfristig erscheint das als eine naheliegende Optimierung, die einem praktisch »in den Schoß fällt« (die Implementierung wird dadurch sogar drastisch einfacher). Aber längerfristig befürchte ich eine heimtücksiche Gefahr, denn die hier genommene Abkürzung kann leicht übersehen werden, da sie den üblichen Gepflogenheiten zuwiderläuft. Im Lauf der Zeit können sich so Speicher- und Ressourcen-Lecks einschleichen, die dann nur mit erheblichem und fokussiertem Aufwand aufzuräumen sind
|
||||
|
|
@ -82055,9 +82093,7 @@ Date:   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 — und das prägt den alltäglichen Stil der Arbeit; weithin kann man sich auf Abstraktionen verlassen, weil diese sich wiederum auf Abstraktionen verlassen können; wenn alles genau und zuverlässig ist, dann werden auch weitreichende Aktionen planbar und handhabbar.
|
||||
|
|
@ -82067,9 +82103,7 @@ Date:   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öglicherweise Teile des Build-Prozesses und des Regelwerks, die daran angeknüpft sein könnten — und das bedeutet, mit einer (wie es zunächst scheint) sehr lokalen und tief verborgenen Optimierung könnte der Grund-Kontrakt in einem erheblichen Teil der Applikation geändert werden
|
||||
|
|
@ -82081,9 +82115,7 @@ Date:   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ür das Aufrufen der aller Destruktoren getrieben werden muß, ist nicht unerheblich, denn für jeden Typ muß eine Closure im Datensegment erzeugt werden und für jede einzelne Allokation muß diese per Funktionszeiger aufrufbar sein; außerdem muß die gesamte Allokation navigierbar gemacht werden — also zwei »Slots« zusätzlich für jede einzelne Allokation. Das ist sehr viel für eine Datenstruktur, die aus vielen kleinen und sehr flexiblen Descriptor-Elementen bestehen wird; die meisten Nodes haben erwartungsgemäß nur einen Eingang und einen Ausgang, was bedeutet, daß für jeweils nur eine einzige ID (ein »Slot«) zusätzlich ein Container (2 »Slot«) und dann noch 4 »Slot« Allokations-Overhead notwendig sind.
|
||||
|
|
@ -82093,9 +82125,7 @@ Date:   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> cold pages</i>
|
||||
|
|
@ -82103,9 +82133,7 @@ Date:   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ß zum Zeitpunkt der Bulk-de-Allokation mit hoher Wahrscheinlichkeit alle betroffenen memory pages bereits »cold« sind, d.h. aus dem Cache herausgefallen; wir müssen also eine Menge von Speicherseiten über den Bus ziehen, bloß um sie zu navigieren und dann...
|
||||
|
|
@ -82115,9 +82143,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
<node CREATED="1715786817201" ID="ID_1883341443" MODIFIED="1715789112354" TEXT="90% der Fälle brauchen keinen dtor-Aufruf">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...in den allermeisten Fällen nämlich<i> exakt gar nichts</i>  zu tun. Dies unter der Annahme, daß die Struktur größtenteils selbst-referentiell ist; zwar werden dadurch reihenweise verkettete Destruktor-Aufrufe stattfinden, welche aber alle letztlich beim Allocator enden, welcher dann (ganz bewußt) nichts tut, weil der gesamte Speicherblock anschließ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:   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ät">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Es steht zu befürchten, daß während der normalen Edit-Tätigkeit alle par 1/10-sec ein Builder-Lauf getriggert wird — und ich schätze, daß ein erheblicher Anteil der tatsächlichen Laufzeit in das Konstruieren der Datenstruktur geht, denn der zugrundeliegende trade-off ist ja grade<i>  space-for-time.</i> Wenngleich auch der Neubau ebenfalls schlecht für den Cache ist, so kann man doch zumindet in Teilen hoffen, daß die neu gebauten Strukturen zumindest bis zur ersten Berührung durch den Play-Prozeß im L3 bleiben. Für die alten Strukturen gilt das aber nicht, sie stellen rein nutzlosen Balast dar.
|
||||
|
|
@ -82141,9 +82165,7 @@ Date:   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 »der Klassiker«.
|
||||
|
|
@ -82166,9 +82188,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1715789753089" ID="ID_1651672024" MODIFIED="1715789767679" TEXT="absehbar ist jedoch daß hier ein großer Hebel gegeben ist"/>
|
||||
<node CREATED="1715789799595" ID="ID_630552591" MODIFIED="1715790098609" TEXT="eine »Alles oder NIchts«-Entscheidung ist spä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äter dann zeigt sich (mit guter Wahrscheinlichkeit) tatsächlich ein relevanter Overhead ⟹ dann ist der Druck zur Optimierung umso stärker, und man wird die vorbereitete Option »ziehen« und die weitreichenden Konsequenzen in Kauf nehmen, da die Behebung eines konkreten Problems immer alle strategischen und methodischen Erwägungen <b>übersteuert</b>. Das wäre der schlechtest mögliche Verlauf, denn zu eine so späten Zeitpunkt kann man kaum mehr etwas tun, um eine weitreichende Änderung der Konventionen abzufedern
|
||||
|
|
@ -126497,9 +126517,7 @@ std::cout << tmpl.render({"what", "World"}) << s
|
|||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1715723719057" ID="ID_978649638" MODIFIED="1715723916920" TEXT="naja ... nur mäßig hilfreich">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
viel Geplänkel cool-getue; tatsächlich hat er schon einen eigenstä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 << tmpl.render({"what", "World"}) << s
|
|||
<node CREATED="1715723729266" ID="ID_850299630" MODIFIED="1715723744425" TEXT="er zeigt Design-Schwä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>  composable allocators</i>
|
||||
|
|
@ -126533,9 +126549,7 @@ std::cout << tmpl.render({"what", "World"}) << 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ündung: es ist sinnlos, weil das einzige, was man dabei machen kann, ist Fehler machen. Der Standard ist extrem genau und elaboriert für dieses Thema, und wenn man sich an wirklich alle Vorgaben hält, hat man praktisch keinen Spielraum mehr....
|
||||
|
|
@ -126545,9 +126559,7 @@ std::cout << tmpl.render({"what", "World"}) << 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ätzlich implementieren, z.B. construct (und das wird dann auch verwendet, anstatt der Standard-Implementierung in den Traits)
|
||||
|
|
|
|||
Loading…
Reference in a new issue