Library: implement the MemoryPool for TrackingAllocator

- use a meta-registry of pools
- retrieve and manage the `MemoryPool` instances by shared_ptr, with a weak registry entry
- use a hastable for the allocations, keyed by the allocated memory address
This commit is contained in:
Fischlurch 2024-06-16 02:36:37 +02:00
parent ad90b7d687
commit a3fb6f46ed
3 changed files with 183 additions and 37 deletions

View file

@ -37,44 +37,130 @@
//#include "lib/unique-malloc-owner.hpp"
#include "lib/depend.hpp"
#include "lib/uninitialised-storage.hpp"
#include "lib/util.hpp"
//#include <string>
#include <unordered_map>
//using util::_Fmt;
using std::make_shared;
using std::make_pair;
//using std::string;
using util::contains;
using util::joinDash;
namespace lib {
namespace test{
/**
* @internal registration and tracking of memory allocations handed out.
*/
class MemoryPool
: util::NonCopyable
{
// using the allocated memory location as key
using Location = void*;
struct LocationHash
{
HashVal operator() (Location const& loc) const { return HashVal(loc); }
};
/** registration entry to maintain a single allocation */
struct Allocation
: util::MoveOnly
{
UninitialisedDynBlock<byte> buff{};
};
using AllocTab = std::unordered_map<const Location, Allocation, LocationHash>;
Literal poolID_;
AllocTab allocs_{};
public:
MemoryPool (Literal id)
: poolID_{id}
, allocs_{}
{ }
Allocation& addAlloc (size_t bytes);
void discardAlloc (void* loc);
};
namespace { // implementation details for common memory management
struct Allocation
{
UninitialisedDynBlock<byte> buff;
};
/* === Logging primitives === */
/**
* @internal registration and tracking of memory allocations handed out.
*/
class MemoryPool
inline EventLog& log() { return TrackingAllocator::log; }
template<typename...XS>
inline void
logAlarm (XS const& ...xs)
{
log().error (joinDash(xs...));
}
template<typename...ARGS>
inline void
logAlloc (Literal pool, string fun, ARGS const& ...args)
{
log().call (pool,fun,args...);
}
class PoolRegistry
: util::NonCopyable
{
std::unordered_map<Literal, std::weak_ptr<MemoryPool>> pools_{};
public:
static PoolHandle locate (Literal poolID);
private:
PoolHandle fetch_or_create (Literal poolID);
};
Depend<MemoryPool> globalPool;
}
Depend<PoolRegistry> poolReg;
/** static access front-end : locate (or create) a MemoryPool */
PoolHandle
PoolRegistry::locate (Literal poolID)
{
return poolReg().fetch_or_create (poolID);
}
PoolHandle
PoolRegistry::fetch_or_create (Literal poolID)
{
auto entry = pools_[poolID];
auto handle = entry.lock();
if (handle) return handle;
// create a new pool and enrol it for given ID
PoolHandle newPool = make_shared<MemoryPool> (poolID);
entry = newPool;
return newPool;
}
}//(End)Implementation memory pools and registration
TrackingAllocator::TrackingAllocator()
: mem_{}
: mem_{PoolRegistry::locate(GLOBAL)}
{ }
TrackingAllocator::TrackingAllocator (Literal id)
: mem_{}
{
UNIMPLEMENTED ("attach to specific pool");
}
: mem_{PoolRegistry::locate(id)}
{ }
void*
@ -89,11 +175,38 @@ namespace test{
UNIMPLEMENTED ("allocate memory block of size n");
}
MemoryPool::Allocation&
MemoryPool::addAlloc (size_t bytes)
{
Allocation newAlloc;
newAlloc.buff.allocate (bytes);
Location loc = newAlloc.buff.front();
ASSERT (not contains (allocs_, loc));
logAlloc (poolID_, "allocate", bytes, loc);
return allocs_.emplace (loc, move(newAlloc))
.first->second;
}
void
MemoryPool::discardAlloc (void* loc)
{
if (contains (allocs_, loc))
{
auto& entry = allocs_[loc];
ASSERT (entry.buff);
ASSERT (entry.buff.front() == loc);
logAlloc (poolID_, "deallocate", entry.buff.size());
allocs_.erase(loc);
}
else // deliberately no exception here (for better diagnostics)
logAlarm("FreeUnknown", loc);
}
/* ===== Diagnostics ===== */
EventLog TrackingAllocator::log{"test::TrackingAllocator"};
EventLog TrackingAllocator::log{"test::TrackingAllocator"};
HashVal

View file

@ -48,19 +48,21 @@ using std::byte;
namespace lib {
namespace test {
namespace { // common memory management for the TrackingAllocator
namespace {
const Symbol GLOBAL{"GLOBAL"};
/** common registration table and memory pool */
class MemoryPool;
}
/** common registration table and memory pool */
class MemoryPool;
using PoolHandle = std::shared_ptr<MemoryPool>;
class TrackingAllocator
{
std::shared_ptr<MemoryPool> mem_;
PoolHandle mem_;
public:
/** can be default created to attach to a common pool */
@ -94,7 +96,7 @@ namespace test {
static size_t numAlloc (Literal pool =GLOBAL);
static size_t numBytes (Literal pool =GLOBAL);
static EventLog log;
static EventLog log;
};
@ -113,7 +115,7 @@ namespace test {
/* ===== C++ standard allocator interface ===== */
using value_type = TY;
[[nodiscard]] TY* allocate (size_t cnt);
@ -122,7 +124,7 @@ namespace test {
/**
*
* C++ standard allocator API : allot raw memory for \a cnt elements of type \a TY
*/
template<typename TY>
TY*
@ -132,7 +134,8 @@ namespace test {
}
/**
*
* C++ standard allocator API : clear an existing allocation,
* which must have been allocated into the same pool, with given element cnt.
*/
template<typename TY>
void

View file

@ -83582,29 +83582,59 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1718489611591" ID="ID_1909546439" MODIFIED="1718489675778" TEXT="eine Checksumme f&#xfc;r jeden Pool"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718489712994" ID="ID_1366290941" MODIFIED="1718489752146" TEXT="Implementierung">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1718489717485" ID="ID_1890743066" MODIFIED="1718489729339" TEXT="das Front-End ist ein verpackter Shared-Ptr"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1718489712994" ID="ID_1366290941" MODIFIED="1718501228365" TEXT="Implementierung">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1718489717485" ID="ID_1890743066" MODIFIED="1718501225010" TEXT="das Front-End ist ein verpackter Shared-Ptr">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1718491430872" ID="ID_146190908" MODIFIED="1718491450055" TEXT="brauche eine getypte Sub-Klasse als Standard-Allocator(Adapter)">
<node CREATED="1718491670798" ID="ID_846381324" MODIFIED="1718491676634" TEXT="Name: TrackAlloc&lt;TY&gt;"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718494826583" ID="ID_721892573" MODIFIED="1718494833802" TEXT="delegierende impl">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718494843824" ID="ID_15578546" MODIFIED="1718494857263" TEXT="MemoryPool f&#xfc;hrt eine Hashtable aller Allokationen">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1718494843824" ID="ID_15578546" MODIFIED="1718501419835" TEXT="MemoryPool f&#xfc;hrt eine Hashtable aller Allokationen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
verwende die Speicheradresse direkt als Hash-Wert; mu&#223; dazu eine Hasher-Funktion implementieren und in den Typ der Hashtable aufnehmen
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718494864443" ID="ID_1936586349" MODIFIED="1718494876166" TEXT="Allokation belegen und freigeben">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1718494864443" ID="ID_1936586349" MODIFIED="1718501206051" TEXT="Allokation belegen und freigeben">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718489730263" ID="ID_5464621" MODIFIED="1718494857263" TEXT="der MemoryPool verwendet Mutex-Locking">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718494880219" ID="ID_1016934813" MODIFIED="1718494895130" TEXT="Meta-Registry aller Pools">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1718494880219" ID="ID_1016934813" MODIFIED="1718496931942" TEXT="Meta-Registry aller Pools">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1718496910802" ID="ID_7557345" MODIFIED="1718496918116" TEXT="statischer (Singleton)-Zugang">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1718496919436" ID="ID_605671279" MODIFIED="1718501276403" TEXT="Anfrage nach einem Pool">
<linktarget COLOR="#3d9b8e" DESTINATION="ID_605671279" ENDARROW="Default" ENDINCLINATION="72;7;" ID="Arrow_ID_144790255" SOURCE="ID_497979014" STARTARROW="None" STARTINCLINATION="63;7;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1718496924024" ID="ID_331961092" MODIFIED="1718496929142" TEXT="bei Bedarf neu anlegen">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718494895881" ID="ID_1075022808" MODIFIED="1718494905847" TEXT="Zugriff auf Pool &#xfc;ber den Namen">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#435e98" CREATED="1718497139158" ID="ID_504091335" MODIFIED="1718497165458" TEXT="der globale Pool ist lediglich eine hart gecodete fallback-ID">
<icon BUILTIN="idea"/>
</node>
<node COLOR="#338800" CREATED="1718501245066" ID="ID_497979014" MODIFIED="1718501276403" TEXT="Meta-Registry anfragen">
<arrowlink COLOR="#3d9b8e" DESTINATION="ID_605671279" ENDARROW="Default" ENDINCLINATION="72;7;" ID="Arrow_ID_144790255" STARTARROW="None" STARTINCLINATION="63;7;"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718494907182" ID="ID_1199907969" MODIFIED="1718494918916" TEXT="Informations-Funktionen">
<icon BUILTIN="flag-yellow"/>