Library: idea for an extent management mechanism

* this is pure old-style low-level trickery
 * using a layout trick, the `AllocationCluster`
   can be operated with the bare minimum of overhead
 * this trick relies on the memory layout of `lib::LinkedElements`
This commit is contained in:
Fischlurch 2024-05-17 23:34:48 +02:00
parent c623298ac8
commit 72aea53ac3
3 changed files with 206 additions and 19 deletions

View file

@ -30,14 +30,110 @@
#include "lib/allocation-cluster.hpp"
#include "lib/error.hpp"
#include "lib/linked-elements.hpp"
#include "lib/util.hpp"
#include <cstddef>
#include <memory>
using util::isnil;
namespace lib {
namespace {// Configuration constants
const size_t EXTENT_SIZ = 256;
const size_t OVERHEAD = 2 * sizeof(void*);
const size_t STORAGE_SIZ = EXTENT_SIZ - OVERHEAD;
using HeapAlloc = std::allocator<std::byte>;
using Alloc = std::allocator_traits<HeapAlloc>;
HeapAlloc heap;
void*
allocate (size_t bytes)
{
return Alloc::allocate (heap, bytes);
}
void
destroy (void* storage)
{
Alloc::destroy (heap, static_cast<std::byte *> (storage));
}
}
/**
* An _overlay view_ for the AllocationCluster to add functionality
* for adding / clearing extents and registering optional deleter functions.
* @warning this is a tricky construct to operate each Allocation Cluster
* with the absolute necessary minimum of organisational overhead.
* The key point to note is that StorageManager is layout compatible
* with AllocationCluster itself achieved through use of the union
* ManagementView, which holds a Storage descriptor member, but
* also an alternate view to manage a chain of extents as
* intrusive linked list (lib::LinkedElements).
* @remark this trick relies on `std::align(pos,rest)` to manage the storage
* coordinates coherently, allowing to re-establish the begin
* of each storage block always, using pointer arithmetics.
*/
class AllocationCluster::StorageManager
{
struct Destructor
{
Destructor* next;
///////////////////////////////////////////////OOO store deleter function here
};
using Destructors = lib::LinkedElements<Destructor>;
struct Extent
{
Extent* next;
Destructors dtors;
std::byte storage[STORAGE_SIZ];
};
using Extents = lib::LinkedElements<Extent>;
union ManagementView
{
Storage storage{};
Extents extents;
};
ManagementView view_;
public:
static StorageManager&
access (AllocationCluster& clu)
{
return reinterpret_cast<StorageManager&> (clu);
}
void
addBlock()
{
closeCurrentBlock();
prependNextBlock();
}
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.rest = 0;
}
void
prependNextBlock()
{
view_.extents.emplace();
view_.storage.pos = & view_.extents.top().storage;
view_.storage.rest = STORAGE_SIZ;
}
};
@ -46,30 +142,49 @@ namespace lib {
* is managed by a separate instance of the low-level memory manager.
*/
AllocationCluster::AllocationCluster()
{
TRACE (memory, "new AllocationCluster");
}
{
TRACE (memory, "new AllocationCluster");
}
/** On shutdown of the AllocationCluster we need to assure a certain
* destruction order is maintained by explicitly invoking a cleanup
* operation on each of the low-level memory manager objects.
* operation on each of the low-level memory manager objects.
*/
AllocationCluster::~AllocationCluster() noexcept
{
try
{
TRACE (memory, "shutting down AllocationCluster");
}
ERROR_LOG_AND_IGNORE (progress, "discarding AllocationCluster")
}
try
{
TRACE (memory, "shutting down AllocationCluster");
}
ERROR_LOG_AND_IGNORE (progress, "discarding AllocationCluster")
/**
* Expand the alloted storage pool by a block,
* suitable to accommodate at least the indicated request.
* @remark Storage blocks are organised as linked list,
* allowing to de-allocate all blocks together.
*/
void
AllocationCluster::expandStorage (size_t allocRequest)
{
ENSURE (allocRequest + OVERHEAD <= EXTENT_SIZ);
void* newBlock = allocate (EXTENT_SIZ); ////////////////////////OOO obsolete ... use ManagementView instead!!!
StorageManager::access(*this).addBlock();
}
/* === diagnostics helpers === */
bool
AllocationCluster::_is_within_limits (size_t size, size_t align)
{
UNIMPLEMENTED ("size limits"); ///////////////////////////OOO enforce maximum size limits
}
} // namespace lib

View file

@ -97,9 +97,15 @@ namespace lib {
AllocationCluster* mother_;
};
/* maintaining the Allocation */
void* storage_;
size_t remain_;
class StorageManager;
/** maintaining the Allocation */
struct Storage
{
void* pos{nullptr};
size_t rest{0};
};
Storage storage_;
public:
AllocationCluster ();
@ -144,10 +150,12 @@ namespace lib {
void*
allotMemory (size_t bytes, size_t alignment)
{
void* loc = std::align(alignment, bytes, storage_, remain_);
ENSURE (_is_within_limits (bytes, alignment));
void* loc = std::align (alignment, bytes, storage_.pos, storage_.rest);
if (loc)
return loc;
UNIMPLEMENTED ("actual memory management");
expandStorage (bytes);
return allotMemory (bytes, alignment);
///////////////////////////////////////////////////////////OOO claim next macro block
}
@ -157,6 +165,9 @@ namespace lib {
{
return static_cast<X*> (allotMemory (cnt * sizeof(X), alignof(X)));
}
void expandStorage (size_t);
bool _is_within_limits (size_t,size_t);
};

View file

@ -81697,6 +81697,20 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715818949821" ID="ID_1747630681" MODIFIED="1715818962407" TEXT="Thema: Alignment">
<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>
<body>
<p>
alignof()-Operator und die Hilfsfunktion std::align()
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
</node>
<node CREATED="1715818964036" ID="ID_1917864530" MODIFIED="1715818999461" TEXT="bedeutet: der Offset wird justiert bis er auf einer Alignment-Grenze liegt"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715819022774" ID="ID_541145684" MODIFIED="1715819026470" TEXT="Anforderungen">
@ -81730,6 +81744,53 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</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="1715990297583" ID="ID_389684421" MODIFIED="1715990309548" TEXT="direkt per Standard-Allocator belegen">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715990310261" ID="ID_1768477879" MODIFIED="1715990332985" TEXT="Idee: stattdessen virtuell eine Extent-Struktur mit Linked-Elements erzeugen">
<icon BUILTIN="idea"/>
<node CREATED="1715991737062" ID="ID_690246579" MODIFIED="1715991797332" TEXT="Zweck: absolutes Minimum an Overhead">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
auch: eine gradzahlige Anzahl an Overhead-Slots
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1715991799166" ID="ID_1984378311" MODIFIED="1715991936313" TEXT="Trick: aktuellen Block-Start rekonstruieren">
<richcontent TYPE="NOTE"><html>
<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.
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1715991938427" ID="ID_1338480715" MODIFIED="1715991957260" TEXT="Mit einer Union lassen sich zwei verschiedene Arbeits-Modi realisieren">
<node CREATED="1715991959415" ID="ID_143253913" MODIFIED="1715991963118" TEXT="Allokations-Modus">
<node CREATED="1715991990569" ID="ID_1549411025" MODIFIED="1715992008134" TEXT="der Zeiger zeigt auf die n&#xe4;chste belegbare Zelle"/>
<node CREATED="1715992008639" ID="ID_1788117937" MODIFIED="1715992025683" TEXT="dahinter steth noch ein size_t mit der verbleibenden Speichermenge"/>
</node>
<node CREATED="1715991963775" ID="ID_1604234308" MODIFIED="1715991968419" TEXT="Extent-Modus">
<node CREATED="1715991970129" ID="ID_408389743" MODIFIED="1715991988683" TEXT="der Zeiger ist der top-Zeiger einer LinkedElements-List"/>
<node CREATED="1715992043143" ID="ID_398369421" MODIFIED="1715992052497" TEXT="er zeigt also auf den Anfang des Extents"/>
<node CREATED="1715992053205" ID="ID_670105438" MODIFIED="1715992066298" TEXT="direkt im Anfang des Extents liegt ein next-Zeiger f&#xfc;r die Blockverkettung"/>
<node CREATED="1715992069805" ID="ID_1072402772" MODIFIED="1715992084606" TEXT="damit kann weitere Funktionalit&#xe4;t in der Extent-Strukgur implementiert werden"/>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1715992091622" ID="ID_73255844" MODIFIED="1715992116009" TEXT="ACHTUNG: vor dem Umschalten in den Extent-Modus: Zeiger auf Blockanfang zur&#xfc;cksetzen">
<icon BUILTIN="clanbomber"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715820305436" ID="ID_1741026762" MODIFIED="1715820308396" TEXT="Clean-up">
<icon BUILTIN="flag-yellow"/>