BufferProvider: draft for the basic global allocator interface

This implementation and the accompanying test might seem pointless,
yet the point is that the interface is aligned to the emerging
concepts for memory allocators in Lumiera, while also directly
delegating to the std::allocator for the time being.

Before we're able to observe the actual allocator trend and behaviour,
it is pretty much moot to engage into any kind of optimisation;
the generic heap allocator performs quite well on recent C++ runtimes,
and, furthermore, the most important performance tweak is to use
a thread-local pool of recent allocations, which should allow
our jobs to run without impeding each other.
This commit is contained in:
Fischlurch 2026-04-27 23:45:05 +02:00
parent 76dbb980b5
commit bf446626a8
6 changed files with 533 additions and 55 deletions

View file

@ -20,6 +20,9 @@
#ifndef LIB_UTIL_QUANT_H #ifndef LIB_UTIL_QUANT_H
#define LIB_UTIL_QUANT_H #define LIB_UTIL_QUANT_H
#include "lib/integral.hpp"
#include <concepts>
#include <cstdlib> #include <cstdlib>
#include <climits> #include <climits>
#include <cfloat> #include <cfloat>
@ -31,7 +34,7 @@ namespace util {
template<typename N> template<typename N>
inline constexpr bool inline constexpr bool
isPow2 (N n) isPow2 (N n) noexcept
{ {
return n > 0 and !(n & (n-1)); return n > 0 and !(n & (n-1));
}; // at each power of 2, a new bit is set for the first time }; // at each power of 2, a new bit is set for the first time
@ -44,7 +47,8 @@ namespace util {
I quot; I quot;
I rem; I rem;
IDiv (I num, I den) constexpr
IDiv (I num, I den) noexcept
: quot(num/den) : quot(num/den)
, rem(num - quot*den) , rem(num - quot*den)
{ } { }
@ -54,7 +58,8 @@ namespace util {
struct IDiv<int> struct IDiv<int>
: div_t : div_t
{ {
IDiv (int num, int den) constexpr
IDiv (int num, int den) noexcept
: div_t(div (num,den)) : div_t(div (num,den))
{ } { }
}; };
@ -63,7 +68,8 @@ namespace util {
struct IDiv<long> struct IDiv<long>
: ldiv_t : ldiv_t
{ {
IDiv (long num, long den) constexpr
IDiv (long num, long den) noexcept
: ldiv_t(ldiv (num,den)) : ldiv_t(ldiv (num,den))
{ } { }
}; };
@ -72,14 +78,15 @@ namespace util {
struct IDiv<llong> struct IDiv<llong>
: lldiv_t : lldiv_t
{ {
IDiv (llong num, llong den) constexpr
IDiv (llong num, llong den) noexcept
: lldiv_t(lldiv (num,den)) : lldiv_t(lldiv (num,den))
{ } { }
}; };
template<typename I> template<typename I>
inline IDiv<I> inline constexpr IDiv<I>
iDiv (I num, I den) ///< support type inference and auto typing... iDiv (I num, I den) noexcept ///< support type inference and auto typing...
{ {
return IDiv<I>{num,den}; return IDiv<I>{num,den};
} }
@ -93,8 +100,8 @@ namespace util {
* @see UtilFloordiv_test * @see UtilFloordiv_test
*/ */
template<typename I> template<typename I>
inline I inline constexpr I
floordiv (I num, I den) floordiv (I num, I den) noexcept
{ {
if (0 < (num^den)) if (0 < (num^den))
return num/den; return num/den;
@ -115,8 +122,8 @@ namespace util {
* @see UtilFloorwarp_test * @see UtilFloorwarp_test
*/ */
template<typename I> template<typename I>
inline IDiv<I> inline constexpr IDiv<I>
floorwrap (I num, I den) floorwrap (I num, I den) noexcept
{ {
IDiv<I> res(num,den); IDiv<I> res(num,den);
if (0 > (num^den) and res.rem) if (0 > (num^den) and res.rem)
@ -129,6 +136,23 @@ namespace util {
} }
/** quantise towards ceiling.
* This function models to fit something into a tiled structure.
*/
template<typename U> requires std::unsigned_integral<U>
inline constexpr U
ceilDiv (U num, U den) noexcept
{
return (num + den - 1u) / den;
}
static_assert (0 == ceilDiv (0u,5u));
static_assert (1 == ceilDiv (1u,5u));
static_assert (1 == ceilDiv (4u,5u));
static_assert (1 == ceilDiv (5u,5u));
static_assert (2 == ceilDiv (6u,5u));
/** /**
* epsilon comparison of doubles. * epsilon comparison of doubles.
@ -146,8 +170,8 @@ namespace util {
* @see https://en.wikipedia.org/wiki/Unit_in_the_last_place * @see https://en.wikipedia.org/wiki/Unit_in_the_last_place
* @todo 3/2024 seems we have solved this problem several times meanwhile /////////////////////////////////TICKET #1360 sort out floating-point rounding and precision * @todo 3/2024 seems we have solved this problem several times meanwhile /////////////////////////////////TICKET #1360 sort out floating-point rounding and precision
*/ */
inline bool inline constexpr bool
almostEqual (double d1, double d2, unsigned int ulp =2) almostEqual (double d1, double d2, unsigned int ulp =2) noexcept
{ {
using std::fabs; using std::fabs;
return fabs (d1-d2) < DBL_EPSILON * fabs (d1+d2) * ulp return fabs (d1-d2) < DBL_EPSILON * fabs (d1+d2) * ulp

View file

@ -13,12 +13,30 @@
/** @file engine-buffer-manager.hpp /** @file engine-buffer-manager.hpp
** Central hub of buffer management within the Lumiera Render Engine. ** Central hub of buffer management within the Lumiera Render Engine.
** Instantiated as global service and part of the Engine, this global
** allocation coordinator is responsible to provide pre-allocated blocks
** for render buffers. These allocations are categorised by their size,
** and will be sent down to LocalMemPool instances running in each
** worker thread. This involves asynchronous messaging to avoid
** any blocking of work jobs due to central resource management.
** **
** @todo WIP-WIP-WIP 4/2026 ** @todo WIP-WIP 4/2026 The intention is to use a family of pools eventually,
** with some of the most relevant tile sizes. The EngineBufferManager
** would then actually retain ownership of all allocations and just
** _lease_ them to the LocalMemPool instances. Allocations would be
** added in extents, likely also using some usage bitmap. However
** building any such kind of optimised allocator requires to conduct
** very detailed _and_ realistic performance observations; furthermore
** it is likely that we'd need some dynamic scheme to select suitable
** tile sizes and pool dimensions. Not sure if it is even possible
** to improve performance by such a scheme; with some likelihood
** the majority of the benefits will be reaped already just by
** introducing thread-local pools without wasting too much memory.
** **
** @see buffer-provider.hpp ** @see EnginePufferManager_test
** @see LocalBufferStore_test ** @see LocalBufferStore_test
** @see BufferProviderProtocol_test ** @see BufferProviderProtocol_test
** @see buffer-provider.hpp
*/ */
#ifndef VAULT_MEM_ENGINE_BUFFR_MANAGA_H #ifndef VAULT_MEM_ENGINE_BUFFR_MANAGA_H
@ -26,43 +44,120 @@
#include "lib/error.hpp" #include "lib/error.hpp"
#include "lib/hash-value.h" #include "lib/util-quant.hpp"
#include "include/logging.h" #include "lib/allocator-handle.hpp"
//#include "lib/hash-value.h"
//#include "include/logging.h"
#include "vault/mem/buffhandle.hpp" #include "vault/mem/buffhandle.hpp"
#include "vault/mem/type-handler.hpp" //#include "vault/mem/type-handler.hpp"
#include "vault/mem/buffer-local-tag.hpp" //#include "vault/mem/buffer-local-tag.hpp"
#include "lib/nocopy.hpp" #include "lib/nocopy.hpp"
#include "lib/util.hpp" //#include "lib/util.hpp"
#include <unordered_map> #include <memory>
#include <array>
namespace vault{ namespace vault{
namespace mem { namespace mem {
using lib::HashVal; // using lib::HashVal;
using util::unConst; // using util::unConst;
namespace err = lumiera::error; namespace err = lumiera::error;
using std::byte;
/** */ namespace { // config and internal helpers...
namespace { // internal blah
} }
/* === deaf === */ /* === Setup of »naïve« buffer allocation === */
/**
* A placeholder definition for the real buffer allocator:
* - allocates buffers aligned to a fixed #TILE_SIZ
* - passes any allocation request directly to the heap allocator
* - performs no state tracking and cleanup whatsoever.
*/
struct HeapBufferAllocator
{
static constexpr size_t TILE_SIZ = 64;
using BaseTile = std::array<byte, TILE_SIZ>;
using Allo = std::allocator<BaseTile>;
using AlloT = std::allocator_traits<Allo>;
static_assert (util::isPow2 (sizeof(BaseTile)));
static_assert (lib::allo::is_Stateless_v<Allo>);
struct Alloc
{
Buff* mem;
size_t siz;
};
static constexpr size_t
numTiles (size_t sizRequest)
{
return util::ceilDiv (sizRequest, sizeof(BaseTile));
}
static Buff*
mark_as_Buffer (void* mem)
{
return static_cast<Buff*> (mem);
}
/**
* Allocate continuous memory block large enough to fit.
* @throws std::bad_alloc when allocation fails
* @note client is responsible to \ref deallocate()
*/
Alloc
allocate (size_t sizRequest)
{
Allo allo;
auto cnt = numTiles (sizRequest);
auto loc = AlloT::allocate (allo, cnt);
return {mark_as_Buffer(loc)
,cnt * TILE_SIZ
};
}
/**
* Deallocates a memory block that was previously
* [allocated](\ref allocate()) by this buffer allocator.
*/
void
deallocate (Alloc alloc)
{
Allo allo;
auto cnt = numTiles (alloc.siz);
auto mem = reinterpret_cast<BaseTile*> (alloc.mem);
AlloT::deallocate (allo, mem, cnt);
}
};
/*********************************************************//**
* Core service of the Render Engine : global buffer manager.
*/
class EngineBufferManager
{
public:
using BufferAllocator = HeapBufferAllocator;
};
}} // namespace vault::mem }} // namespace vault::mem
#endif /*VAULT_MEM_ENGINE_BUFFR_MANAGA_H*/ #endif /*VAULT_MEM_ENGINE_BUFFR_MANAGA_H*/

View file

@ -30,6 +30,7 @@
#include "lib/error.hpp" #include "lib/error.hpp"
#include "lib/integral.hpp" #include "lib/integral.hpp"
#include "lib/util-quant.hpp"
#include "vault/mem/buffer-metadata.hpp" #include "vault/mem/buffer-metadata.hpp"
#include "lib/format-string.hpp" #include "lib/format-string.hpp"
#include "lib/format-obj.hpp" #include "lib/format-obj.hpp"
@ -50,16 +51,10 @@ namespace mem {
using StorageWord = uint64_t; using StorageWord = uint64_t;
constexpr inline size_t WORD_SIZ = sizeof(StorageWord); constexpr inline size_t WORD_SIZ = sizeof(StorageWord);
constexpr size_t
ceilDiv (size_t num, size_t den) noexcept
{
return (num + den - 1u) / den;
}
constexpr size_t constexpr size_t
wordCnt (size_t sizeRequest) noexcept wordCnt (size_t sizeRequest) noexcept
{ {
return ceilDiv (sizeRequest, WORD_SIZ); return util::ceilDiv (sizeRequest, WORD_SIZ);
} }
static_assert (0 == wordCnt(0)); static_assert (0 == wordCnt(0));

View file

@ -37,6 +37,10 @@ return: 0
END END
TEST "Engine Buffer-Manager interface" EngineBufferManager_test <<END
END
PLANNED "Engine Interface basics" EngineInterface_test <<END PLANNED "Engine Interface basics" EngineInterface_test <<END
END END

View file

@ -0,0 +1,131 @@
/*
EngineBufferManager(Test) - cover the interface to a central buffer manager
Copyright (C)
2026, Hermann Vosseler <Ichthyostega@web.de>
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version. See the file COPYING for further details.
* *****************************************************************/
/** @file engine-buffer-manager-test.cpp
** unit test \ref EngineBufferManager_test
*/
#include "test/run.hpp"
#include "test/test-helper.hpp"
//#include "vault/mem/engine-buffer-metadata.hpp"
#include "vault/mem/engine-buffer-manager.hpp"
//#include "lib/depend-inject.hpp"
//#include "lib/thread.hpp"
//#include "lib/error.hpp"
#include "test/diagnostic-output.hpp"////////////TODO
//using std::this_thread::yield;
//using lib::Thread;
namespace vault {
namespace mem {
namespace test {
// using LERR_(LOGIC);
// using LERR_(LIFECYCLE);
namespace { // Test helper
// template<typename X>
// Buff*
// mark_as_Buffer(X& something)
// {
// return reinterpret_cast<Buff*> (std::addressof(something));
// }
//
}
/*****************************************************************************//**
* @test Show how the central buffer manager of the Render Engine can be accessed.
*/
class EngineBufferManager_test : public Test
{
virtual void
run (Arg)
{
// seedRand();
demonstrate_AllocatorInterface();
verify_DataTransfer();
verify_lulz();
}
/** @test show how to allocate buffer memory
* with the underlying base allocator.
* @remark 4/2026 for the first integration of the Render Engine,
* a simplified implementation is used that just delegates
* to the regular heap allocator (which actually performs
* quite well on modern C++ STDLib). The plan is to
* use some kind of tiling pool allocator eventually,
* contingent on the actual performance observations.
*/
void
demonstrate_AllocatorInterface()
{
using Allo = EngineBufferManager::BufferAllocator;
CHECK (lib::allo::is_Stateless_v<Allo>);
Allo allo;
auto a1 = allo.allocate (55);
auto a2 = allo.allocate (555);
CHECK (a1.mem);
CHECK (a2.mem);
CHECK (a1.siz == Allo::TILE_SIZ);
CHECK (a2.siz % Allo::TILE_SIZ == 0);
CHECK (a2.siz > 555);
// can use that memory without blowing up....
auto doooh = new(a1.mem) f128{std::numeric_limits<f128>::max()};
*doooh /= 2;
CHECK (2 == std::numeric_limits<f128>::max() / *doooh);
allo.deallocate (a1);
allo.deallocate (a2);
}
/** @test */
void
verify_DataTransfer()
{
}
/** @test
*/
void
verify_lulz()
{
}
};
/** Register this test class... */
LAUNCHER (EngineBufferManager_test, "unit engine");
}}} // namespace vault::mem::test

View file

@ -74191,8 +74191,9 @@
<icon BUILTIN="messagebox_warning"/> <icon BUILTIN="messagebox_warning"/>
</node> </node>
</node> </node>
<node CREATED="1716728664652" ID="ID_1644685634" MODIFIED="1776730151948" TEXT="Strukturen"> <node CREATED="1716728664652" ID="ID_1644685634" MODIFIED="1777328614629" TEXT="Strukturen">
<linktarget COLOR="#5c6c7a" DESTINATION="ID_1644685634" ENDARROW="Default" ENDINCLINATION="-892;2424;" ID="Arrow_ID_284707831" SOURCE="ID_622928577" STARTARROW="None" STARTINCLINATION="-1922;116;"/> <linktarget COLOR="#5c6c7a" DESTINATION="ID_1644685634" ENDARROW="Default" ENDINCLINATION="-892;2424;" ID="Arrow_ID_284707831" SOURCE="ID_622928577" STARTARROW="None" STARTINCLINATION="-1922;116;"/>
<linktarget COLOR="#345274" DESTINATION="ID_1644685634" ENDARROW="Default" ENDINCLINATION="-529;1146;" ID="Arrow_ID_491300253" SOURCE="ID_1944871660" STARTARROW="None" STARTINCLINATION="-2513;119;"/>
<node CREATED="1716728667779" ID="ID_467995115" MODIFIED="1716728670092" TEXT="Namen"> <node CREATED="1716728667779" ID="ID_467995115" MODIFIED="1716728670092" TEXT="Namen">
<node CREATED="1716728670955" ID="ID_1816165091" MODIFIED="1716728689109"> <node CREATED="1716728670955" ID="ID_1816165091" MODIFIED="1716728689109">
<richcontent TYPE="NODE"><html> <richcontent TYPE="NODE"><html>
@ -74481,7 +74482,7 @@
<node BACKGROUND_COLOR="#d2beaf" COLOR="#46418e" CREATED="1696538113039" ID="ID_314350695" MODIFIED="1696538164825" TEXT="#1279 : Beschlu&#xdf;(9/23) &#x27f9; auf C++ Standardlib aufgebaut"> <node BACKGROUND_COLOR="#d2beaf" COLOR="#46418e" CREATED="1696538113039" ID="ID_314350695" MODIFIED="1696538164825" TEXT="#1279 : Beschlu&#xdf;(9/23) &#x27f9; auf C++ Standardlib aufgebaut">
<icon BUILTIN="button_ok"/> <icon BUILTIN="button_ok"/>
<node CREATED="1696538113039" MODIFIED="1696538113039" TEXT="fr&#xfc;her gab es einen in C implementieren Threadpool-Service"/> <node CREATED="1696538113039" MODIFIED="1696538113039" TEXT="fr&#xfc;her gab es einen in C implementieren Threadpool-Service"/>
<node CREATED="1696538113039" MODIFIED="1696538113039" TEXT="im Zuge &#xbb;Playback Vertical Slice&#xab; wurde Anforderungs-Analyse gemacht"/> <node CREATED="1696538113039" ID="ID_49590855" MODIFIED="1696538113039" TEXT="im Zuge &#xbb;Playback Vertical Slice&#xab; wurde Anforderungs-Analyse gemacht"/>
</node> </node>
<node COLOR="#338800" CREATED="1695597011139" FOLDED="true" ID="ID_956380031" MODIFIED="1696538202836" TEXT="Neues Design Thread-Wrapper"> <node COLOR="#338800" CREATED="1695597011139" FOLDED="true" ID="ID_956380031" MODIFIED="1696538202836" TEXT="Neues Design Thread-Wrapper">
<linktarget COLOR="#499ca8" DESTINATION="ID_956380031" ENDARROW="Default" ENDINCLINATION="-1261;104;" ID="Arrow_ID_482806479" SOURCE="ID_125138411" STARTARROW="None" STARTINCLINATION="-1063;-42;"/> <linktarget COLOR="#499ca8" DESTINATION="ID_956380031" ENDARROW="Default" ENDINCLINATION="-1261;104;" ID="Arrow_ID_482806479" SOURCE="ID_125138411" STARTARROW="None" STARTINCLINATION="-1063;-42;"/>
@ -145856,7 +145857,8 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<icon BUILTIN="yes"/> <icon BUILTIN="yes"/>
<node CREATED="1777050440887" ID="ID_1006627416" MODIFIED="1777066692859" TEXT="Verhalten spezifizieren"> <node CREATED="1777050440887" ID="ID_1006627416" MODIFIED="1777066692859" TEXT="Verhalten spezifizieren">
<icon BUILTIN="yes"/> <icon BUILTIN="yes"/>
<node CREATED="1777050520227" ID="ID_796153621" MODIFIED="1777050524094" TEXT="Use-Cases"> <node CREATED="1777050520227" ID="ID_796153621" MODIFIED="1777325912544" TEXT="Use-Cases">
<linktarget COLOR="#36506f" DESTINATION="ID_796153621" ENDARROW="Default" ENDINCLINATION="-452;0;" ID="Arrow_ID_1304449539" SOURCE="ID_1675354420" STARTARROW="Default" STARTINCLINATION="-32;-602;"/>
<node CREATED="1777068198295" ID="ID_1010651012" MODIFIED="1777068390012" TEXT="Allokationsbedarf ank&#xfc;ndigen"> <node CREATED="1777068198295" ID="ID_1010651012" MODIFIED="1777068390012" TEXT="Allokationsbedarf ank&#xfc;ndigen">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
<head/> <head/>
@ -146091,10 +146093,191 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</node> </node>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776819109351" ID="ID_1998897998" MODIFIED="1776819155584" TEXT="EngineBufferManager"> <node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1776819109351" ID="ID_1998897998" MODIFIED="1777339324992" TEXT="EngineBufferManager">
<icon BUILTIN="yes"/> <icon BUILTIN="yes"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776819156872" ID="ID_1476925601" MODIFIED="1776819956355" TEXT="Grundkonzeption schaffen"> <node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1776819156872" ID="ID_1476925601" MODIFIED="1777339332224" TEXT="Grundkonzeption schaffen">
<icon BUILTIN="flag-yellow"/> <icon BUILTIN="pencil"/>
<node CREATED="1777325396485" ID="ID_947969066" MODIFIED="1777325400377" TEXT="Interface">
<node CREATED="1777325407524" ID="ID_1333052454" MODIFIED="1777325421966" TEXT="Zugang via lib::Depend&lt;EngineBufferManager&gt;">
<node CREATED="1777325446047" ID="ID_1500798718" MODIFIED="1777325451218" TEXT="geht das &#xfc;berhaupt?"/>
<node CREATED="1777325452127" ID="ID_1999785214" MODIFIED="1777325463483" TEXT="m&#xfc;&#xdf;te n&#xe4;mlich default-konstruierbar sein"/>
<node CREATED="1777325557816" ID="ID_1748588651" MODIFIED="1777325642908" TEXT="wird hier jemals ein &#xbb;Default-Setup&#xab; gebraucht?">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...das w&#228;re nur der Fall, wenn ein Unit-Test &#8222;mal eben&#8220; eine Render-Engine braucht. Denn sonst decken wir den Default-Fall bereits mit dem NaiveBufferSetup ab
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="help"/>
</node>
<node CREATED="1777325501367" ID="ID_586279034" MODIFIED="1777325521405" TEXT="tats&#xe4;chlich wollen wir hier eine explizit gemanagete Server-Komponente"/>
<node CREATED="1777325699181" ID="ID_1392466705" MODIFIED="1777325832394" TEXT="Dependency-Factory kann auf abstrakte Basisklasse konfiguriert werdn">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Und dann w&#252;rde jeder Zugriff mit einer Exception scheitern....
</p>
<p>
So lange, bis man den statische Aufruf t&#228;tigt:&#160;
</p>
<p>
<font color="#635e96" face="DejaVu Sans Mono" size="9pt"><b>DependInject</b></font><font color="#65533c" face="DejaVu Sans Mono" size="9pt">&lt;</font><font color="#635e96" face="DejaVu Sans Mono" size="9pt"><b>Base</b></font><font color="#65533c" face="DejaVu Sans Mono" size="9pt">&gt;::</font><font color="#61143c" face="DejaVu Sans Mono" size="9pt"><i>useSingleton&lt;Sub&gt;</i></font>
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
</node>
</node>
<node CREATED="1777325872302" ID="ID_1675354420" MODIFIED="1777325912544" TEXT="Use-Cases">
<arrowlink COLOR="#36506f" DESTINATION="ID_796153621" ENDARROW="Default" ENDINCLINATION="-452;0;" ID="Arrow_ID_1304449539" STARTARROW="Default" STARTINCLINATION="-32;-602;"/>
<node CREATED="1777326001051" ID="ID_825262980" MODIFIED="1777326053002" TEXT="Allokation(en) asynchron beauftragen"/>
<node CREATED="1777326037424" ID="ID_613961876" MODIFIED="1777326058745" TEXT="Allokation(en) synchron beauftragen"/>
<node CREATED="1777326109630" ID="ID_1521192845" MODIFIED="1777326120671" TEXT="Allokation asynchron zur&#xfc;ckgeben"/>
<node CREATED="1777326206909" ID="ID_421293619" MODIFIED="1777326210833" TEXT="Allokator-Steuerung">
<node CREATED="1777326212094" ID="ID_1130719488" MODIFIED="1777326215708" TEXT="Allokation"/>
<node CREATED="1777326216481" ID="ID_1774862481" MODIFIED="1777326219716" TEXT="Deallokation"/>
<node CREATED="1777326220702" ID="ID_911135656" MODIFIED="1777326226035" TEXT="Kapazit&#xe4;tsmanagement"/>
</node>
</node>
</node>
<node CREATED="1777326654102" ID="ID_499885447" MODIFIED="1777326656831" TEXT="Struktur">
<node CREATED="1777326657789" ID="ID_831464061" MODIFIED="1777326715033" TEXT="L&#xe4;ngerfristig: Policy-based-Design">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Schon allein um die konfigurierbaren Aspekte klar herauszustellen, und um ggfs. Quellen dynamischer Konfiguration zu verdrahten
</p>
</body>
</html>
</richcontent>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1777326753646" ID="ID_448684473" MODIFIED="1777326779620" TEXT="doch zun&#xe4;chst einmal: alles direkt coden">
<icon BUILTIN="yes"/>
<node CREATED="1777339002955" ID="ID_758544304" MODIFIED="1777339007206" TEXT="typedef BufferAllocator"/>
<node CREATED="1777339008730" ID="ID_1534654283" MODIFIED="1777339172707" TEXT="verwende fix eine Tile-Size von 64 Bytes">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...das ist die &#252;bliche Cache-Line-Size auf x86_64
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1777339178309" ID="ID_142350391" MODIFIED="1777339187028" TEXT="verdrahte direkt auf std::allocator"/>
</node>
<node CREATED="1777326795907" ID="ID_1470622255" MODIFIED="1777339362483" TEXT="verwendet einen Allocator">
<arrowlink COLOR="#47c9c9" DESTINATION="ID_1644044904" ENDARROW="Default" ENDINCLINATION="6;-56;" ID="Arrow_ID_1619156849" STARTARROW="None" STARTINCLINATION="-20;33;"/>
<node CREATED="1777328509534" ID="ID_1944871660" MODIFIED="1777328772390" TEXT="sollte mich an mein Allokatoren-Konzept-Framework halten....">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
auch wenn es erst mal gedanklich schwerf&#228;llt, und f&#252;r die zun&#228;chst angestrebte <i>naive Implementierung</i>&#160;wie ein sinnloser Tanz aussieht; denn dieses Framework ist gut durchdacht und sollte langsam zu einem R&#252;ckgrat f&#252;r Allokationsvorg&#228;nge werden. Zur Erinnerung: dieses Konzept habe ich an die Stelle eines &#187;globalen Allokators&#171; gestellt. Zun&#228;chst hatten wir ja den Ansatz mit Christian's &quot;Mempool&quot; &#8212; und ich habe mich jahrelang mit der Planlosigkeit dieser Idee herumgeplagt, bis ich langsam verstanden habe, was daran schief ist....
</p>
</body>
</html>
</richcontent>
<arrowlink COLOR="#345274" DESTINATION="ID_1644685634" ENDARROW="Default" ENDINCLINATION="-529;1146;" ID="Arrow_ID_491300253" STARTARROW="None" STARTINCLINATION="-2513;119;"/>
<node CREATED="1777328785465" ID="ID_1420803190" MODIFIED="1777328795899" TEXT="wir verwenden einen unterliegenden &#xbb;Allokator&#xab;"/>
<node CREATED="1777329110029" ID="ID_1388976086" MODIFIED="1777329129190" TEXT="Hier ist der base_type nur eine Speicherkachel"/>
<node CREATED="1777328936437" ID="ID_558800878" MODIFIED="1777328948520">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
Allokatoren sind <i>composable</i>
</p>
</body>
</html>
</richcontent>
<node CREATED="1777329176181" ID="ID_381595151" MODIFIED="1777329187583" TEXT="der unterliegende Allokator mag eine Pool-Hierarchie haben"/>
<node CREATED="1777329188341" ID="ID_323248358" MODIFIED="1777329208588" TEXT="der dar&#xfc;berliegende Allokator h&#xe4;lt die Ownership und leiht Allokationen aus"/>
</node>
</node>
<node CREATED="1777329356340" ID="ID_235497917" MODIFIED="1777330790158" TEXT="die &#xbb;Ownership&#xab;-Ebene mu&#xdf; zun&#xe4;chst ausgeklammert bleiben">
<arrowlink COLOR="#ce0827" DESTINATION="ID_860687505" ENDARROW="Default" ENDINCLINATION="135;-10;" ID="Arrow_ID_1201137989" STARTARROW="None" STARTINCLINATION="-14;74;"/>
<node CREATED="1777329370541" ID="ID_1130144304" MODIFIED="1777330545220">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
weil sie f&#252;r einen <i>naiven Allokator</i>&#160;nur schlecht zu implementieren ist
</p>
</body>
</html>
</richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...da wir ja letztlich alles an den globalen Allokator durchreichen wollen (weil der's sowiso besser kann), haben wir keinerlei Struktur mehr, die wir uns zunutze machen k&#246;nnen &#10233; f&#252;r jede de-Allokation m&#252;ssen wir den Tracking-Eintrag suchen
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1777329418716" ID="ID_1818082361" MODIFIED="1777330552447">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
f&#252;r eine <i>Pool-Hierarchie</i>&#160;dagegen ist eine effiziente Implementierung m&#246;glich
</p>
</body>
</html>
</richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
hierbei kann man sich die bekannte Element-Gr&#246;&#223;e zunutze machen
</p>
<ul>
<li>
zun&#228;chst findet man den zust&#228;ndigen Pool
</li>
<li>
sodann braucht es ggfs. einen Meta-Index oder eine sonstige Hilfstruktur, um ggfs. den jeweilgen Extent zu finden
</li>
<li>
im Extent mu&#223; man dann ein Bit in der Belegungs-Bitmap flippen
</li>
</ul>
</body>
</html>
</richcontent>
</node>
</node>
</node>
</node>
</node> </node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776819169143" ID="ID_1367745941" MODIFIED="1777050391595" TEXT="Schnittstelle f&#xfc;r asynchrones Messaging bedenken"> <node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776819169143" ID="ID_1367745941" MODIFIED="1777050391595" TEXT="Schnittstelle f&#xfc;r asynchrones Messaging bedenken">
<arrowlink COLOR="#fefab1" DESTINATION="ID_1503539674" ENDARROW="Default" ENDINCLINATION="-233;10;" ID="Arrow_ID_451160831" STARTARROW="None" STARTINCLINATION="92;5;"/> <arrowlink COLOR="#fefab1" DESTINATION="ID_1503539674" ENDARROW="Default" ENDINCLINATION="-233;10;" ID="Arrow_ID_451160831" STARTARROW="None" STARTINCLINATION="92;5;"/>
@ -146102,20 +146285,66 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</node> </node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776819181261" ID="ID_1026628741" MODIFIED="1776819956356" TEXT="alternative synchrone Schnittstelle bereitstellen"> <node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776819181261" ID="ID_1026628741" MODIFIED="1776819956356" TEXT="alternative synchrone Schnittstelle bereitstellen">
<icon BUILTIN="flag-yellow"/> <icon BUILTIN="flag-yellow"/>
<node CREATED="1776819196456" ID="ID_1985019567" MODIFIED="1776819221279"> <node CREATED="1777324291441" ID="ID_336948545" MODIFIED="1777324316333" TEXT="ist relevant f&#xfc;r &#xbb;sofort&#xab;-Allokation (Fallback)"/>
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
zun&#228;chst wird <u>nur diese</u>&#160;genutzt
</p>
</body>
</html></richcontent>
<icon BUILTIN="idea"/>
</node>
<node CREATED="1776819226503" ID="ID_1059062619" MODIFIED="1777051865655" TEXT="sollte kongruent zum Messaging sein"/> <node CREATED="1776819226503" ID="ID_1059062619" MODIFIED="1777051865655" TEXT="sollte kongruent zum Messaging sein"/>
<node CREATED="1776819244365" ID="ID_933815031" MODIFIED="1776819258406" TEXT="aber stets ein &#xbb;pull&#xab; vom lokalen Manager"/> <node CREATED="1776819244365" ID="ID_933815031" MODIFIED="1776819258406" TEXT="aber stets ein &#xbb;pull&#xab; vom lokalen Manager"/>
</node> </node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1777324327301" ID="ID_1965528564" MODIFIED="1777324340058" TEXT="lege zun&#xe4;chst einen &#xbb;naiven&#xab; Memory-Manager an">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1777324341484" ID="ID_269815037" MODIFIED="1777324543018" TEXT="einzig sinnvoll: direkt vom/zum Heap">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Es ist nicht sinnvoll, eine &#187;vorl&#228;ufige&#171; Implementierung eines heterogenen Memory-Managers zu machen. Da ist n&#228;mlich der Heap-Allokator<i>&#160; stets besser geeignet</i>&#160;&#8212; ist inzwischen einigerma&#223;en schwer geworden, den Heap-Allokator &#252;berhaupt noch zu schlagen. Mithin wird das auch gleich eine gute <b>Baseline-Implementierung</b>&#160;f&#252;r Performance-Messungen
</p>
</body>
</html>
</richcontent>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1777324354872" ID="ID_33339353" MODIFIED="1777324362776" TEXT="sp&#xe4;ter geplant: System von Pools">
<icon BUILTIN="hourglass"/>
<node CREATED="1777324463807" ID="ID_64824853" MODIFIED="1777324471021" TEXT="dabei ist aber sehr vieles noch unklar"/>
<node CREATED="1777324471804" ID="ID_409561662" MODIFIED="1777324485502" TEXT="kann das &#xfc;berhaupt funktionieren, ohne massiv Speicher zu verschwenden?"/>
<node CREATED="1777324494396" ID="ID_23718162" MODIFIED="1777324511253" TEXT="m&#xf6;glicherweise ist eine dynamische Steuerung notwendig + fall-Back auf den Heap-Allokator"/>
</node>
</node>
<node CREATED="1777324560690" ID="ID_318881353" MODIFIED="1777324567396" TEXT="Rahmen per Test abstecken">
<node COLOR="#338800" CREATED="1777339205760" ID="ID_1644044904" MODIFIED="1777339355233" TEXT="demonstrate_AllocatorInterface">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Das ist nun wirklich mehr eine Demonstration, denn ich kann da praktisch nichts verifizieren (au&#223;er da&#223; es keinen SEGFAULT gibt, wenn ich in den allozierten Speicher schreibe). Wenigstens ist damit schon mal sichergestellt, da&#223; der Code durch den Compiler geht
</p>
</body>
</html>
</richcontent>
<linktarget COLOR="#47c9c9" DESTINATION="ID_1644044904" ENDARROW="Default" ENDINCLINATION="6;-56;" ID="Arrow_ID_1619156849" SOURCE="ID_1470622255" STARTARROW="None" STARTINCLINATION="-20;33;"/>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1777330585249" ID="ID_1415692101" MODIFIED="1777330598348" TEXT="Ergebnis / Einsichten">
<icon BUILTIN="forward"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1777330604883" ID="ID_860687505" MODIFIED="1777330785076" TEXT="&#xbb;Ownership&#xab; ist zun&#xe4;chst freischwebend">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Das hei&#223;t, wir m&#252;ssen uns darauf verlassen, da&#223; der ganze komplexe Klapperatismus absolut korrekt funktioniert; wenn dem so ist, gen&#252;gt es, einfach blindlings neue Allokationen an die lokalen Pools zu schicken und freizugeben was aus den lokalen Pools zur&#252;ckgesendet wird. Das <b>hat zur Konsequenz</b>&#160;da&#223; gewisse zus&#228;tzliche Konsistenzchecks eingebaut werden m&#252;ssen, damit sich die Korrektheit auch erweisen l&#228;&#223;t
</p>
</body>
</html>
</richcontent>
<linktarget COLOR="#ce0827" DESTINATION="ID_860687505" ENDARROW="Default" ENDINCLINATION="135;-10;" ID="Arrow_ID_1201137989" SOURCE="ID_235497917" STARTARROW="None" STARTINCLINATION="-14;74;"/>
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
</node> </node>
</node> </node>
</node> </node>