Library: verify fundamental properties of TrackingAllocator

* implement some further statistic and diagnostic helpers
 * explicitly create and discard a base allocation for test
This commit is contained in:
Fischlurch 2024-06-16 14:26:21 +02:00
parent 32bea9521b
commit be3cf61111
4 changed files with 118 additions and 11 deletions

View file

@ -96,6 +96,8 @@ namespace test{
Allocation& addAlloc (size_t bytes);
void discardAlloc (void* loc, size_t);
Allocation const* findAlloc (Location) const;
HashVal getChecksum() const;
size_t getAllocationCnt() const;
size_t calcAllocSize() const;
@ -150,7 +152,7 @@ namespace test{
PoolHandle
PoolRegistry::fetch_or_create (Literal poolID)
{
auto entry = pools_[poolID];
auto& entry = pools_[poolID];
auto handle = entry.lock();
if (handle) return handle;
@ -183,7 +185,7 @@ namespace test{
}
void
TrackingAllocator::deallocate (void* loc, size_t cnt) noexcept
TrackingAllocator::deallocate (Location loc, size_t cnt) noexcept
{
ENSURE (mem_);
mem_->discardAlloc (loc, cnt);
@ -204,23 +206,31 @@ namespace test{
}
void
MemoryPool::discardAlloc (void* loc, size_t bytes)
MemoryPool::discardAlloc (Location loc, size_t bytes)
{
if (contains (allocs_, loc))
{
auto& entry = allocs_[loc];
ASSERT (entry.buff);
ASSERT (entry.buff.front() == loc);
if (entry.buff.size() != bytes)
logAlarm ("SizeMismatch", entry.entryID, bytes, showAddr(loc));
if (entry.buff.size() != bytes) // *deliberately* tolerating wrong data
logAlarm ("SizeMismatch", entry.entryID, bytes, showAddr(loc)); // but log as incident to support diagnostics
logAlloc (poolID_, "deallocate", entry.entryID, bytes, showAddr(loc));
checksum_ -= entryNr_ * bytes;
checksum_ -= entryNr_ * bytes; // Note: using the given size (if wrong ⟿ checksum mismatch)
allocs_.erase(loc);
}
else // deliberately no exception here (for better diagnostics)
logAlarm ("FreeUnknown", bytes, showAddr(loc));
}
MemoryPool::Allocation const*
MemoryPool::findAlloc (Location loc) const
{
return contains (allocs_, loc)? & allocs_.at(loc)
: nullptr;
}
HashVal
MemoryPool::getChecksum() const
{
@ -256,6 +266,14 @@ namespace test{
return pool->getChecksum();
}
/** determine number of active front-end handles */
size_t
TrackingAllocator::use_count (Literal poolID)
{
PoolHandle pool = PoolRegistry::locate (poolID);
return pool.use_count() - 1;
}
/** get allocation count for mem-pool */
size_t
TrackingAllocator::numAlloc (Literal poolID)
@ -272,7 +290,32 @@ namespace test{
return pool->calcAllocSize();
}
/** probe if this allocator pool did allocate the given memory location */
bool
TrackingAllocator::manages (Location memLoc) const
{
return bool(mem_->findAlloc (memLoc));
}
/** retrieve the registered size of this allocation, if known. */
size_t
TrackingAllocator::getSize(Location memLoc) const
{
auto* entry = mem_->findAlloc (memLoc);
return entry? entry->buff.size()
: 0;
}
/** retrieve the internal registration ID for this allocation. */
HashVal
TrackingAllocator::getID (Location memLoc) const
{
auto* entry = mem_->findAlloc (memLoc);
return entry? entry->entryID
: 0;
}
}} // namespace lib::test

View file

@ -73,9 +73,10 @@ namespace test {
// standard copy operations acceptable
using Location = void*;
[[nodiscard]] void* allocate (size_t n);
void deallocate (void*, size_t =0) noexcept;
[[nodiscard]] Location allocate (size_t n);
void deallocate (Location, size_t =0) noexcept;
friend bool
@ -92,7 +93,12 @@ namespace test {
/* ===== Diagnostics ===== */
bool manages (Location) const;
size_t getSize(Location) const;
HashVal getID (Location) const;
static HashVal checksum (Literal pool =GLOBAL);
static size_t use_count (Literal pool =GLOBAL);
static size_t numAlloc (Literal pool =GLOBAL);
static size_t numBytes (Literal pool =GLOBAL);

View file

@ -169,6 +169,32 @@ namespace test{
Tracker::log.clear("Tracking-Allocator-Test");
Tracker::log.joinInto(log);
CHECK (TrackingAllocator::checksum() == 0, "Testsuite is broken");
CHECK (TrackingAllocator::use_count() == 0);
{
TrackingAllocator allo;
CHECK (TrackingAllocator::use_count() == 1);
CHECK (TrackingAllocator::numAlloc() == 0);
CHECK (TrackingAllocator::numBytes() == 0);
void* mem = allo.allocate (55);
CHECK (TrackingAllocator::numAlloc() == 1);
CHECK (TrackingAllocator::numBytes() == 55);
CHECK (allo.manages (mem));
CHECK (allo.getSize (mem) == 55);
HashVal memID = allo.getID (mem);
CHECK (0 < memID);
CHECK (TrackingAllocator::checksum() == memID*55);
allo.deallocate (mem, 42); // note: passing a wrong number here is marked as ERROR in the log
CHECK (not allo.manages (mem));
CHECK (allo.getSize (mem) == 0);
CHECK (allo.getID (mem) == 0);
CHECK (TrackingAllocator::use_count() == 1);
CHECK (TrackingAllocator::numAlloc() == 0);
CHECK (TrackingAllocator::numBytes() == 0);
}
CHECK (TrackingAllocator::checksum() == 0);
{
@ -191,6 +217,13 @@ SHOW_EXPR(join(vec2))
cout << "____Tracking-Allo-Log_________\n"
<< util::join(Tracker::log, "\n")
<< "\n───╼━━━━━━━━━━━━━━━━━╾────────"<<endl;
CHECK (log.verify("EventLogHeader").on("Tracking-Allocator-Test")
.before("logJoin")
.beforeCall("allocate").on(GLOBAL).argPos(1, 55)
.beforeEvent("error", "SizeMismatch")
.beforeCall("deallocate").on(GLOBAL).argPos(1, 42)
);
}
};

View file

@ -83558,6 +83558,32 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node COLOR="#435e98" CREATED="1718486596443" ID="ID_1250015263" MODIFIED="1718486605209" TEXT="verify checksum"/>
</node>
<node CREATED="1718462887129" ID="ID_1322153003" MODIFIED="1718462969529" TEXT="demonstrate_checkAllocator">
<node COLOR="#338800" CREATED="1718544835454" ID="ID_264718265" MODIFIED="1718544844296" TEXT="Basis-Allocator testen">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1718544845477" ID="ID_1456085342" MODIFIED="1718544875735" STYLE="fork" TEXT="Roh-Allokation belegen und freigeben"/>
<node COLOR="#435e98" CREATED="1718544856802" ID="ID_657924298" MODIFIED="1718544875737" STYLE="fork" TEXT="Statistiken verifizieren"/>
<node COLOR="#435e98" CREATED="1718544862722" ID="ID_506802563" MODIFIED="1718544934040" STYLE="fork" TEXT="Systematik der Checksumme dokumentieren">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Ich habe nun beschlossen, sie zu bilden als Produkt
</p>
<ul>
<li>
interne laufende ID der Allokation
</li>
<li>
nominelle Gr&#246;&#223;e der Basis-Allokation
</li>
</ul>
</body>
</html>
</richcontent>
</node>
</node>
<node COLOR="#338800" CREATED="1718492999206" ID="ID_94881308" MODIFIED="1718503992073" TEXT="Vector an den globalen Pool ankoppeln">
<icon BUILTIN="button_ok"/>
</node>
@ -83632,8 +83658,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
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>
</html></richcontent>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1718494864443" ID="ID_1936586349" MODIFIED="1718501206051" TEXT="Allokation belegen und freigeben">