From 70bef003248c7849aad07f0062b9b4fac4d43e8c Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 24 Jun 2026 23:48:15 +0200 Subject: [PATCH] Invocation: provide a fake engine context setup The purpose of this test is to invoke a Render Node graph using the full service environment as present in the Render Engine. However, for sake of clarity, I do not want to pull up the Engine subsystem, but rather use a local / mocked setup of all the services involved. The node invocation is performed from within a worker thread, to demonstrate integration with the thread-local memory pools. The first simple test case builds and then pulls a source node. --- src/steam/engine/engine-ctx.hpp | 2 - src/steam/engine/render-environment.cpp | 2 +- tests/46node.tests | 2 +- tests/steam/engine/node-opera-test.cpp | 125 +++++++++++++++++- tests/vault/mem/buffer-provider-load-test.cpp | 2 +- wiki/thinkPad.ichthyo.mm | 73 +++++++++- 6 files changed, 195 insertions(+), 11 deletions(-) diff --git a/src/steam/engine/engine-ctx.hpp b/src/steam/engine/engine-ctx.hpp index 35ab90618..895a0d3f8 100644 --- a/src/steam/engine/engine-ctx.hpp +++ b/src/steam/engine/engine-ctx.hpp @@ -63,9 +63,7 @@ namespace engine { static lib::Depend access; - private: EngineCtx(); - friend class lib::DependencyFactory; }; diff --git a/src/steam/engine/render-environment.cpp b/src/steam/engine/render-environment.cpp index 59ee8c953..2804c6ded 100644 --- a/src/steam/engine/render-environment.cpp +++ b/src/steam/engine/render-environment.cpp @@ -68,7 +68,7 @@ namespace engine{ BufferProvider& EngineFacilities::setupCacheProvider() ////////////////////////////////////////////////////////////////TICKET #1223 : in what ways does client code need to interact with the Frame Cache / Management? { - return getNaiveBufferManager(); + return setupBufferProvider(); } diff --git a/tests/46node.tests b/tests/46node.tests index d025f04b3..dec8daa31 100644 --- a/tests/46node.tests +++ b/tests/46node.tests @@ -26,7 +26,7 @@ TEST "Proc Node metadata key" NodeMeta_test <("NodeOpera_test"); } + auto buildStore() { return std::make_unique(); } + + BufferProvider& setupBufferProvider() override { return *this; } + }; + + struct TestEngineCtx + { + // install mock instances for the relevant services + lib::DependInject::Local<> metaHub; + lib::DependInject::Local<> globalPool; + + // install a rigged access front-end for the buffer management + lib::DependInject::Local bufferSetup; + lib::DependInject::Local frontEndCtx; + }; + + } + @@ -45,7 +96,79 @@ namespace test { virtual void run (Arg) { - UNIMPLEMENTED ("operate some render nodes as linked together"); + seedRand(); + + invokeSimpleNode(); + } + + + /** @test directly invoke a simple source node. + * - use the node builder to create a simple node + * immediately into the current stack frame + * - the processing function feeds a fixed random number + * into the given output buffer + * - then launch a worker thread to pull this node + * - create an output buffer directly from the worker thread + * - invoke the single port of the node, which is visible + * since it was created before starting the local worker thread + * - after the invocation, the fixed random number should have been + * placed into the output buffer + * - after the worker thread has finished, a single buffer allocation + * should have happened; this allocation was sent back automatically + * and can be claimed and released by the global buffer manager. + */ + void + invokeSimpleNode() + { + int randNum{rani()}; + auto fun = [&](int* buff){ *buff = randNum; }; + + TestEngineCtx mockEngine; + + ProcNode node{prepareNode("Test") + .preparePort() + .invoke("fun()", fun) + .completePort() + .build()}; + + Thread testWorker{[&] /* === directly perform a node invocation === */ + { + BuffHandle buff = EngineCtx::access().mem.lockBufferFor (-55); + Time nomTime{Time::ZERO}; + ProcessKey key{0}; + uint port{0}; + + CHECK (-55 == buff.accessAs()); + + // Trigger Node invocation... + buff = node.pull (port, buff, nomTime, key); + + CHECK (randNum == buff.accessAs()); + buff.release(); + }}; + + while (testWorker) + yield(); // wait for worker to finish + + // the central services were indeed requested / created + CHECK (mockEngine.bufferSetup); + CHECK (mockEngine.globalPool); + CHECK (mockEngine.metaHub); + + // at least two buffer types registered (one generic for int) + CHECK (2 <= mockEngine.metaHub->cntEntries()); + + // one buffer was requested... + CHECK (1 == watch(*mockEngine.globalPool).numAllocs()); + + sleep_for (500us); // additional delay for the local pool's destructor + // (which is invoked after the thread has terminated) + + // process and close remaining allocations + // sent back by the local pool's destructor... + mockEngine.globalPool->processPendingRequests(); + // now there should be no memory leaks....... + CHECK (0 == watch(*mockEngine.globalPool).bytesLeased()); } }; diff --git a/tests/vault/mem/buffer-provider-load-test.cpp b/tests/vault/mem/buffer-provider-load-test.cpp index eeef3bc24..5b0eddbb8 100644 --- a/tests/vault/mem/buffer-provider-load-test.cpp +++ b/tests/vault/mem/buffer-provider-load-test.cpp @@ -303,7 +303,7 @@ namespace test { * - the prime goal is to demonstrate correctness, balancing memory demand * mostly through lock-free queues, without loosing any allocation. */ - class BufferProviderLoad_test : public Test + class BufferProviderLoad_test : public Test { virtual void diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 09e1fa1ce..5ea211881 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -89082,7 +89082,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -89095,6 +89095,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ @@ -91082,9 +91083,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + @@ -98868,6 +98870,21 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + +

+ Hier besteht ein »bottleneck« — insofern wir sparsam mit dem Speicher in den Segmenten und der Job-Activity-Language umgehen müssen; möglicherweise lassen sich gewisse (theoretische) Freiheitsgrade zusammenfalten in eine Processing-ID, an die ein Mapping gebunden wird (⟶ Stream-Types, Ausführungs-Zustand, Switchboard). Letztlich wird das aber über mehrere Stufen heruntergebrochen, so daß beim Einstieg in den jeweiligen Node-Pull eigentlich alle Freiheitsgrade und Parameter disjunkt vorliegen sollten... +

+ + +
+ + +
@@ -116661,9 +116678,52 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + + + + +

+ Das möchte ich so halten zur Dokumentation der Zusammenhänge; hier geht es um Komponenten-Integration — nicht um einen Systemtest. Teils werden jedoch bereits die gleichen Komponenten verwendet, wie in der »echten Engine«, vor allem der BufferProvider mit lokalen Pools. Andererseits werden die RenderNodes noch direkt erzeugt. +

+ + +
+ + + + + + +

+ diese Subklasse ist zugleich ein BufferProviderSetup, und etabliert damit auch das Schema mit den local-mem-pools +

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

+ ...ich wollte diese direkten Referenz-Felder, um im produktiven Einsatz mir jeweils eine Indirektion einzusparen ⟹ das hat die Konsequenz, daß ich auch eine neue Instanz des EngineCtx (als front-End) erzeugen muß, um eine spezielle lokale Instanz des BufferProviderSetup injizieren zu können. Deshalb muß EngineCtx dann doch public konstruierbar sein (und nicht private mit fried für die DependencyFactory). Schade, aber letztlich irrelevant. +

+ + +
+ +
+
+ + + @@ -116673,13 +116733,16 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + + + + +