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:
parent
ad90b7d687
commit
a3fb6f46ed
3 changed files with 183 additions and 37 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -83582,29 +83582,59 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1718489611591" ID="ID_1909546439" MODIFIED="1718489675778" TEXT="eine Checksumme fü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<TY>"/>
|
||||
<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ührt eine Hashtable aller Allokationen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1718494843824" ID="ID_15578546" MODIFIED="1718501419835" TEXT="MemoryPool führt eine Hashtable aller Allokationen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
verwende die Speicheradresse direkt als Hash-Wert; muß 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 ü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"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue