BufferProvider: connect the first wire-tap to record locked state

...this turns out to be surprisingly difficult,
due to various subclass / protected visibility problems.
Not sure if the component design within `DiagnosticBufferProvider`
is sane yet...
This commit is contained in:
Fischlurch 2026-02-16 23:57:12 +01:00
parent 43c4f7a518
commit 945636c446
5 changed files with 95 additions and 32 deletions

View file

@ -81,7 +81,7 @@ namespace engine {
BufferProvider::getDescriptorFor (size_t storageSize)
{
auto& typeKey = bufferStage_->defineBufferType (storageSize, TypeHandler::RAW);
return BuffDescr (*this, typeKey);
return buildDescriptor (typeKey);
}
@ -89,7 +89,7 @@ namespace engine {
BufferProvider::getDescriptorFor(size_t storageSize, TypeHandler specialTreatment)
{
auto& typeKey = bufferStage_->defineBufferType (storageSize, move (specialTreatment));
return BuffDescr (*this, typeKey);
return buildDescriptor (typeKey);
}
@ -143,7 +143,7 @@ namespace engine {
auto [storage, localTag] = bufferStore_->provideBuffer (typeKey.storageSize(), type, typeKey.localTag());
auto& stateKey = bufferStage_->mark_locked (typeKey, storage, localTag);
return BuffHandle (BuffDescr(*this, HashVal(stateKey)), storage);
return BuffHandle (buildDescriptor(stateKey), storage);
} // NOTE: not the underlying parent descriptor!
@ -211,6 +211,12 @@ namespace engine {
/* === BuffDescr and BuffHandle === */
BuffDescr
BufferProvider::buildDescriptor (HashVal key)
{
return {*this, key};
}
bool
BufferProvider::was_created_by_this_provider (BuffDescr const& descr) const
{

View file

@ -187,6 +187,7 @@ namespace engine {
protected:
~BufferProvider();
BuffDescr buildDescriptor (HashVal);
bool was_created_by_this_provider (BuffDescr const&) const;
using Buff = StreamType::ImplFacade::DataBuffer; ///< marker type for an actual data buffer

View file

@ -30,6 +30,7 @@
#include "lib/util.hpp"
#include <algorithm>
#include <utility>
#include <memory>
@ -42,27 +43,34 @@ namespace engine {
using diagn::StateReg;
using std::unique_ptr;
using std::ranges::find_if;
using std::move;
using metadata::Key;
/**
* Implementation of tracking and instrumentation
*/
struct DiagnosticBufferProvider::BlockTracker
: util::NonCopyable
{
StateReg created;
StateReg emitted;
StateReg released;
};
Block::Block (BuffHandle const& handle)
: handle{handle}
/* ====== Accounting API ====== */
Block::Block (BuffDescr typeDescriptor, Key stateKey, Buff* mem)
: handle{typeDescriptor, mem}
, storage{mem}
{ }
Block::Block (BuffDescr const& descr)
: handle{descr}
{ }
void
StateReg::record (PBlock blockRef)
{
reg_.emplace_back (move (blockRef));
}
void
StateReg::record (Block block)
{
record (std::make_shared<Block> (block));
}
size_t
StateReg::cnt() const
@ -93,6 +101,32 @@ namespace engine {
, LERR_(BOTTOM_VALUE));
}
bool
StateReg::contains (HashVal handle) const
{
return bool(byHandle (handle));
}
/**
* Implementation of tracking and instrumentation
*/
struct DiagnosticBufferProvider::BlockTracker
: util::NonCopyable
{
StateReg created;
StateReg emitted;
StateReg released;
void
record_locked (BuffDescr typeDescriptor, Key stateKey, Buff* mem)
{
REQUIRE (not created.contains (typeDescriptor));
created.record (Block{typeDescriptor, stateKey, mem});
}
};
class DiagnosticBufferProvider::InstrumentedStageProxy
: public BufferProviderSetup::Stage
@ -102,6 +136,7 @@ namespace engine {
StageImp stage_;
Tracker& tracker_;
DiagnosticBufferProvider& provider_;
/* === BufferStage proxy implementation === */
@ -127,7 +162,9 @@ namespace engine {
ID
mark_locked (ID typeKey, Buff* storage, LocalTag implMark) override
{
return stage_->mark_locked (typeKey, storage, implMark);
ID stateKey = stage_->mark_locked (typeKey, storage, implMark);
tracker_.record_locked (provider_.buildDescriptor(stateKey), stateKey, storage);
return stateKey;
}
ID
@ -155,18 +192,13 @@ namespace engine {
}
public:
InstrumentedStageProxy (StageImp rawImpl, Tracker& tracker)
InstrumentedStageProxy (StageImp rawImpl, Tracker& tracker, DiagnosticBufferProvider& provider)
: stage_{move(rawImpl)}
, tracker_{tracker}
, provider_{provider}
{ }
};
/* ====== Accounting API ====== */
void
StateReg::record (BuffHandle const& handle)
{
reg_.emplace_back (std::make_shared<Block> (handle));
}
DiagnosticBufferProvider::DiagnosticBufferProvider()
@ -174,7 +206,7 @@ namespace engine {
, heapStore_{dynamic_cast<HeapMemBufferStore&> (*bufferStore_)} //////////////////////////////////////////TICKET 1410 : obsolete after switch to newtracking-API
, tracker_{std::make_unique<BlockTracker>()}
{
decorate<InstrumentedStageProxy> (bufferStage_, *tracker_);
decorate<InstrumentedStageProxy> (bufferStage_, *tracker_, *this);
}
DiagnosticBufferProvider::~DiagnosticBufferProvider()

View file

@ -37,6 +37,8 @@ namespace engine {
namespace error = lumiera::error;
using Buff = StreamType::ImplFacade::DataBuffer; ///////////TODO consider to define that marker type at some suitable central location
class HeapMemBufferStore; //////////////////////////////OOO fällt dann weg nach dem Umbau
class BufferDiagnostic;
@ -46,10 +48,10 @@ namespace engine {
struct Block
{
BuffHandle handle;
void* storage{nullptr};
void* accessMemory() const { return storage; }
Buff* storage{nullptr};
Buff* accessMemory() const { return storage; }
Block (BuffHandle const&);
Block (BuffDescr, metadata::Key, Buff* mem);
Block (BuffDescr const&);
operator HashVal() const { return handle; }
};
@ -58,7 +60,8 @@ namespace engine {
class StateReg
: util::NonCopyable
{
using Registry = std::vector<std::shared_ptr<Block>>;
using PBlock = std::shared_ptr<Block>;
using Registry = std::vector<PBlock>;
Registry reg_;
public:
@ -66,10 +69,12 @@ namespace engine {
using Result = lib::Result<Block const&>;
Result operator[] (size_t seqNr) const;
Result byHandle (HashVal handle) const;
bool contains (HashVal handle) const;
size_t cnt() const;
/* ========= Accounting API ========= */
void record (BuffHandle const&);
void record (Block);
void record (PBlock);
};
}//(End)diagnostic descriptors.

View file

@ -112855,6 +112855,26 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<node CREATED="1771276666297" ID="ID_80656960" MODIFIED="1771276686235" TEXT="mit dem nun angelegten API gen&#xfc;gt es, die BufferStage zu dekorieren">
<icon BUILTIN="idea"/>
</node>
<node COLOR="#338800" CREATED="1771282492426" ID="ID_1137207493" MODIFIED="1771284960337" TEXT="mu&#xdf; auch die zugeh&#xf6;rige (umschlie&#xdf;ende) DiagnosticBufferProvider-Instanz zug&#xe4;nglich machen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...und zwar, weil wir ein BuffHandle speichern wollen, das einen BufferProvider einschlie&#223;t. Dazu brauchen wir die R&#252;ckreferenz auf den Provider. Und das darf eigentlich nur BufferProvider selber...
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="yes"/>
</node>
</node>
<node CREATED="1771282534052" ID="ID_1418547018" MODIFIED="1771282553829" TEXT="es gibt eigentlich nur eine Konstruktor-Funktion: beim Locking"/>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1771282627528" ID="ID_1818084511" MODIFIED="1771282645961" TEXT="Sichtbarkeits-Problem: nur BufferProvider kann einen BuffDescr erzeugen">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1771282651196" ID="ID_1065300465" MODIFIED="1771282682996" TEXT="klarer Fall: mu&#xdf; die Funktion per protected-API zug&#xe4;nglich machen"/>
<node CREATED="1771282684240" ID="ID_1294774953" MODIFIED="1771282696183" TEXT="kann dann auch &#xfc;berall im BufferProvider selber verwendet werden"/>
</node>
</node>
</node>
@ -113165,8 +113185,7 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
Deshalb nenne ich es auch ein &#187;Protocol&#171; &#8212; wollten wir etwas wirklich <i>wasserdichtes,</i>&#160; dann m&#252;&#223;ten wir die Struktur ganz anders anlegen, und vermutlich auch deutlich rigider, und mehr interne Zugriffe verwenden.
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<arrowlink COLOR="#6d4975" DESTINATION="ID_693750944" ENDARROW="Default" ENDINCLINATION="-1078;42;" ID="Arrow_ID_480988688" STARTARROW="None" STARTINCLINATION="-465;29;"/>
</node>
</node>