From cd415c05aa5637b6aae9393cb4f11fd2b712d632 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 12 Feb 2026 20:21:30 +0100 Subject: [PATCH] BufferProvider: implement first strike of diagnostics accessors ...just enough to be able to write the assertions in the first test case (..and the test case fails still, due to the pending work on sorting out the implementation APIs between `BufferStage` und `BufferStore`) --- src/steam/engine/buffhandle.hpp | 2 + .../engine/diagnostic-buffer-provider.cpp | 90 +++++++-- .../engine/diagnostic-buffer-provider.hpp | 41 ++-- .../diagnostic-buffer-provider-test.cpp | 11 +- tests/core/steam/engine/testframe.cpp | 14 +- tests/core/steam/engine/testframe.hpp | 2 +- wiki/thinkPad.ichthyo.mm | 180 +++++++++++++++++- 7 files changed, 289 insertions(+), 51 deletions(-) diff --git a/src/steam/engine/buffhandle.hpp b/src/steam/engine/buffhandle.hpp index 0a6d18269..6dc6477ac 100644 --- a/src/steam/engine/buffhandle.hpp +++ b/src/steam/engine/buffhandle.hpp @@ -151,6 +151,8 @@ namespace engine { return *pBuffer_; } + operator HashVal() const { return descriptor_; } + bool isValid() const { diff --git a/src/steam/engine/diagnostic-buffer-provider.cpp b/src/steam/engine/diagnostic-buffer-provider.cpp index e46ad4086..d9d7ecf7c 100644 --- a/src/steam/engine/diagnostic-buffer-provider.cpp +++ b/src/steam/engine/diagnostic-buffer-provider.cpp @@ -26,18 +26,78 @@ #include "steam/engine/diagnostic-buffer-provider.hpp" #include "steam/engine/heap-mem-buffer-store.hpp" +#include "lib/format-string.hpp" +#include "lib/util.hpp" + +#include namespace steam { namespace engine { + using util::_Fmt; + using util::unConst; + using diagn::Block; + using diagn::StateReg; + using std::ranges::find_if; + + /** * Implementation of tracking and instrumentation */ - class DiagnosticBufferProvider::BlockTracker + struct DiagnosticBufferProvider::BlockTracker + : util::NonCopyable { - + StateReg created; + StateReg emitted; + StateReg released; }; + + Block::Block (BuffHandle const& handle) + : handle{handle} + { } + + Block::Block (BuffDescr const& descr) + : handle{descr} + { } + + + size_t + StateReg::cnt() const + { + return reg_.size(); + } + + StateReg::Result + StateReg::operator[] (size_t seqNr) const + { + if (seqNr < cnt()) + return * reg_[seqNr]; + else + return error::Invalid(_Fmt{"no Buffer with seq-nr %d (%d known entries)"} + % seqNr % cnt() + , LERR_(BOTTOM_VALUE)); + } + + StateReg::Result + StateReg::byHandle (HashVal handle) const + { + if (auto pos = find_if (reg_, [&](auto& entry){ return handle == HashVal(*entry); }) + ;pos != reg_.end() + ) + return **pos; + else + return error::Invalid("requested Buffer never encountered" + , LERR_(BOTTOM_VALUE)); + } + + + /* ====== Accounting API ====== */ + void + StateReg::record (BuffHandle const& handle) + { + + } DiagnosticBufferProvider::DiagnosticBufferProvider() @@ -51,7 +111,13 @@ namespace engine { // INFO (proc_mem, "discarding %zu diagnostic buffer entries", outSeq_.size()); ////////////OOO implement based on dedicated tracking information in-object } - + BufferDiagnostic::BufferDiagnostic (DiagnosticBufferProvider& thePro) + : dbp_{thePro} + , created{dbp_.tracker_->created} + , emitted{dbp_.tracker_->emitted} + , released{dbp_.tracker_->released} + { } + /* === diagnostic API === */ @@ -79,24 +145,6 @@ namespace engine { // return dbp_.heapStore_.access_emitted(bufferID).accessMemory(); ///////////////////////////////////////TICKET 1410 : switch to newly defined tracking-API } - diagn::StateReg& - BufferDiagnostic::created () - { - UNIMPLEMENTED ("track all created buffer blocks"); - } - - diagn::StateReg& - BufferDiagnostic::emitted () - { - UNIMPLEMENTED ("track all emitted buffer blocks"); - } - - diagn::StateReg& - BufferDiagnostic::released() - { - UNIMPLEMENTED ("track all released buffer blocks"); - } - diff --git a/src/steam/engine/diagnostic-buffer-provider.hpp b/src/steam/engine/diagnostic-buffer-provider.hpp index 6673af5b0..584beb4dc 100644 --- a/src/steam/engine/diagnostic-buffer-provider.hpp +++ b/src/steam/engine/diagnostic-buffer-provider.hpp @@ -25,9 +25,11 @@ #include "lib/util.hpp" #include "steam/engine/type-handler.hpp" ///////////////OOO warum? #include "steam/engine/naive-buffer-setup.hpp" +#include "lib/result.hpp" #include "lib/nocopy.hpp" #include +#include namespace steam { @@ -40,22 +42,34 @@ namespace engine { namespace diagn {// state descriptors for diagnostics.... + /** represent the status of one allocation */ struct Block - : BuffHandle - , util::NonCopyable { + BuffHandle handle; + void* storage{nullptr}; + void* accessMemory() const { return storage; } - Block(BuffHandle const& handle) : BuffHandle{handle} { } - Block(BuffDescr const& descr) : BuffHandle{descr} { } + Block (BuffHandle const&); + Block (BuffDescr const&); + operator HashVal() const { return handle; } }; + class StateReg : util::NonCopyable { + using Registry = std::vector>; + Registry reg_; + public: + /* ========= Information API ========= */ + using Result = lib::Result; + Result operator[] (size_t seqNr) const; + Result byHandle (HashVal handle) const; size_t cnt() const; - Block const& operator[] (size_t seqNr) const; - Block const& byHandle (HashVal handle) const; + + /* ========= Accounting API ========= */ + void record (BuffHandle const&); }; }//(End)diagnostic descriptors. @@ -71,7 +85,7 @@ namespace engine { : public NaiveBufferSetup { HeapMemProvider& heapStore_; //////////////////////////////OOO fällt dann weg nach dem Umbau - class BlockTracker; + struct BlockTracker; std::unique_ptr tracker_; public: @@ -83,23 +97,22 @@ namespace engine { friend class BufferDiagnostic; }; + + /** Accessor-proxy to investigate transactions */ class BufferDiagnostic : util::MoveOnly { DiagnosticBufferProvider& dbp_; public: - BufferDiagnostic (DiagnosticBufferProvider& thePro) - : dbp_{thePro} - { } - + BufferDiagnostic (DiagnosticBufferProvider&); bool buffer_was_used (uint bufferID); ///< @deprecated ////////////////////////////////////////TICKET 1410 bool buffer_was_closed (uint bufferID); ///< @deprecated ////////////////////////////////////////TICKET 1410 void* accessMemory (uint bufferID); ///< @deprecated ////////////////////////////////////////TICKET 1410 bool all_buffers_released(); - diagn::StateReg& created (); - diagn::StateReg& emitted (); - diagn::StateReg& released(); + diagn::StateReg const& created; + diagn::StateReg const& emitted; + diagn::StateReg const& released; }; inline BufferDiagnostic diff --git a/tests/core/steam/engine/diagnostic-buffer-provider-test.cpp b/tests/core/steam/engine/diagnostic-buffer-provider-test.cpp index b2b5d8fc7..059410006 100644 --- a/tests/core/steam/engine/diagnostic-buffer-provider-test.cpp +++ b/tests/core/steam/engine/diagnostic-buffer-provider-test.cpp @@ -21,6 +21,7 @@ #include "steam/engine/diagnostic-buffer-provider.hpp" #include "steam/engine/buffhandle-attach.hpp" ///////////////////////////////////////////////////////////TICKET 1410 : remove unnecessary API #include "steam/engine/testframe.hpp" +#include "lib/test/diagnostic-output.hpp"//////////////////TODO #include @@ -97,8 +98,14 @@ namespace test { provider.emitBuffer (testBuff); provider.releaseBuffer(testBuff); -// diagn::Block& block0 = provider.access_emitted(0); ///////////////////////////////OOO provide suitable diagnostic API! -// CHECK (testData(dataID) == block0.accessMemory()); +SHOW_EXPR(watch(provider).created.cnt()) +SHOW_EXPR(watch(provider).emitted.cnt()) +SHOW_EXPR(watch(provider).released.cnt()) + CHECK (1 == watch(provider).created.cnt()); + CHECK (1 == watch(provider).emitted.cnt()); + CHECK (1 == watch(provider).released.cnt()); + diagn::Block block0 = watch(provider).emitted[0]; + CHECK (testData(dataID) == block0.accessMemory()); } diff --git a/tests/core/steam/engine/testframe.cpp b/tests/core/steam/engine/testframe.cpp index f0c7d550e..31e618c24 100644 --- a/tests/core/steam/engine/testframe.cpp +++ b/tests/core/steam/engine/testframe.cpp @@ -133,11 +133,11 @@ namespace test { } - TestFrame& - accessAsTestFrame (void* memoryLocation) + TestFrame const& + accessAsTestFrame (void const* memoryLocation) { REQUIRE (memoryLocation); - return *reinterpret_cast (memoryLocation); + return *reinterpret_cast (memoryLocation); } @@ -304,9 +304,9 @@ namespace test { } bool - TestFrame::operator== (void* memLocation) const + TestFrame::operator== (void const* memLocation) const { - TestFrame& candidate (accessAsTestFrame (memLocation)); + TestFrame const& candidate (accessAsTestFrame (memLocation)); return candidate.isSane() and candidate == *this; } @@ -420,14 +420,14 @@ namespace test { bool TestFrame::isAlive (void* memLocation) { - TestFrame& candidate (accessAsTestFrame (memLocation)); + TestFrame const& candidate (accessAsTestFrame (memLocation)); return candidate.isAlive(); } bool TestFrame::isDead (void* memLocation) { - TestFrame& candidate (accessAsTestFrame (memLocation)); + TestFrame const& candidate (accessAsTestFrame (memLocation)); return candidate.isDead(); } diff --git a/tests/core/steam/engine/testframe.hpp b/tests/core/steam/engine/testframe.hpp index 8a7aba91f..86a510242 100644 --- a/tests/core/steam/engine/testframe.hpp +++ b/tests/core/steam/engine/testframe.hpp @@ -126,7 +126,7 @@ namespace test { bool isValid() const; bool isPristine() const; - bool operator== (void* memLocation) const; + bool operator== (void const* memLocation) const; friend bool operator== (TestFrame const& f1, TestFrame const& f2) { return f1.contentEquals(f2); } friend bool operator!= (TestFrame const& f1, TestFrame const& f2) { return !f1.contentEquals(f2); } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 25cd4c1f7..302ebf1e4 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -111992,8 +111992,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + @@ -112008,8 +112009,39 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + + + + +

+ technisch wird das realisiert, indem wir den Block nur einmal erzeugen und dann in verschiedene Registries eintragen und aktualisieren; eingetragen wird er als shared-ptr, aber das API verbirgt das +

+ +
+
+ + + + +

+ Im Block(descriptor) selber stehen nur Protokoll-Werte, wie z.B. ein Status-ENUM; das ist alles potentiell fehleranfällig, denn naheliegenderweise zieht sich der user davon eine Kopie; eine solche Kopie bekommt aber keine Updates mehr mit +

+ +
+
+ + + + +

+ ...und hier wird die Sache noch verwirrender: das Buff-Handle selber ist zwar ein Value-Objekt, repräsentiert aber eine Referenz-Semantik. Das bedeutet, die Informations-Funktionen könnten einen aktualisierten Status-Wert sehen, der den materialisierten Feldern im Block(descriptor) wirderspricht +

+ +
+
@@ -112046,12 +112078,36 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + +
+ + + + + + +

+ ...deshalb muß man nämlich häufig in eine explizit getypte lokale Kopie materialisieren, da ich lib::Result mit einem Target-Typ-Operator ausgestattet habe — und nicht mit operator*(). Hier greifen also die Regeln für implizite Konversionen in C++, und diese sind inzwischen (C++17) deutlich restriktiver geworden; sie werden nur noch in einem getypten Zielkontext wirksam, also wenn sich aus dem Empfänger des Wertes der erwartete Typ ergibt; der Aufruf einer Funktion gehört da wohl nicht dazu. +

+ +
+ +
+
+ +
- - + + + + + @@ -112310,7 +112366,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + @@ -112326,6 +112384,116 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + + + + + + + + + + + +

+ möchte ich bieten weil man's machen kann +

+ +
+
+ + + + + +

+ wenn man diese Möglichkeit überhaupt bieten möchte, dann besser als dedizierte Funktion, denn die Status-Abfragen für einen Descriptor sind notwendigerweise nicht kongruent mit denen eines Handles (der Descriptor kann sowohl einen »Typ« repräsentieren, alsauch eine konkrete Allokation)i +

+ +
+
+ + + + + + + + + + + + + +

+ aber damit ist das Feature nur noch halb so nützlich +

+ +
+
+ + + + + + + +

+ ...weil ich mich nun dummerweise darauf festgelegt habe, den Block(descriptor) kongruent zu einem BuffHandle zu machen; das bedetuet, der Descriptor hat eine Back-Referenz auf einen BufferProvider, und verwendet diese auch zur Implementierung von Informationsfunktionen. Oder er könnte es tun (dies ist dann naheliegend ⟹ Wartungsproblem ↯). Da der Null-Value aus den Suchfunktionen der Registry erzeugt wird, brauchen wir einen Backlink auf die zugehörige Instanz des DiagnosticBufferProvider. Jaaa, das ist machbar.... +

+ +
+
+ + + + + + + + + + + + + +
+
+ + + + +

+ std::ranges::find_if mit Zugriffs-λ +

+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + @@ -112410,8 +112578,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - +