From 4ac995548abd1f5acb84543bffaaad39886bfb74 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 5 Jul 2023 15:10:34 +0200 Subject: [PATCH] Block-Flow: identify required API operations - decision how to handle the Extent storage (by forced-cast) - decision to place the administrative record directly into the Extent TODO not clear yet how to handle the implicit limitation for future deadlines --- src/vault/gear/activity.hpp | 1 + src/vault/gear/block-flow.hpp | 67 +++++++- src/vault/mem/extent-family.hpp | 37 +++-- tests/vault/gear/block-flow-test.cpp | 13 +- wiki/renderengine.html | 4 +- wiki/thinkPad.ichthyo.mm | 227 +++++++++++++++++++++++++-- 6 files changed, 320 insertions(+), 29 deletions(-) diff --git a/src/vault/gear/activity.hpp b/src/vault/gear/activity.hpp index a9f440490..dd4634188 100644 --- a/src/vault/gear/activity.hpp +++ b/src/vault/gear/activity.hpp @@ -74,6 +74,7 @@ namespace gear { ,TIMESTOP ///< correspondingly signal end of some processing ,NOTIFY ///< push a message to another Activity ,PROBE ///< evaluate a condition and inhibit another target Activity + ,GATE ///< probe window + count-down; activate next Activity, else re-schedule ,TICK ///< internal engine »heart beat« for internal maintenance hook(s) }; diff --git a/src/vault/gear/block-flow.hpp b/src/vault/gear/block-flow.hpp index d7c95e8a3..42c5b6644 100644 --- a/src/vault/gear/block-flow.hpp +++ b/src/vault/gear/block-flow.hpp @@ -52,7 +52,10 @@ #include "vault/common.hpp" +#include "vault/gear/activity.hpp" +#include "vault/mem/extent-family.hpp" //#include "lib/symbol.hpp" +#include "lib/time/timevalue.hpp" #include "lib/nocopy.hpp" //#include "lib/util.hpp" @@ -64,7 +67,54 @@ namespace gear { // using util::isnil; // using std::string; + using lib::time::Time; + namespace {// hard-wired parametrisation + const size_t EPOCH_SIZ = 100; + const size_t ACTIVITIES_PER_FRAME = 10; + const size_t INITIAL_FRAMES = 50; + const size_t INITIAL_ALLOC = 1 + (INITIAL_FRAMES * ACTIVITIES_PER_FRAME) / EPOCH_SIZ; + + using Allocator = mem::ExtentFamily; + } + + + /** + * + */ + class Epoch + : public Allocator::Extent + { + + /// @warning will faked, not constructed + Epoch() = delete; + + public: + struct EpochGate + : Activity + { + EpochGate() + : Activity{GATE} + { + UNIMPLEMENTED ("initialise allocation usage marker to zero"); + } + // default copyable + }; + + static Epoch& + implantInto (Allocator::Extent& rawStorage) + { + Epoch& target = static_cast (rawStorage); + new(&target[0]) EpochGate{}; + return target; + } + + EpochGate& + gate() + { + return static_cast ((*this)[0]); + } + }; /** * Basic (abstracted) view of... @@ -75,11 +125,24 @@ namespace gear { class BlockFlow : util::NonCopyable { + Allocator alloc_; public: - explicit - BlockFlow (int woof) + BlockFlow() + : alloc_{INITIAL_ALLOC} { } + + Activity& + createActivity (Activity::Verb verb, Time deadline) + { + UNIMPLEMENTED ("place new allocation"); + } + + void + discardBefore (Time deadline) + { + UNIMPLEMENTED ("traverse oldest Epochs and discard obsoleted"); + } }; diff --git a/src/vault/mem/extent-family.hpp b/src/vault/mem/extent-family.hpp index b2ccf7018..d7e156327 100644 --- a/src/vault/mem/extent-family.hpp +++ b/src/vault/mem/extent-family.hpp @@ -71,32 +71,47 @@ namespace mem { class ExtentFamily : util::NonCopyable { - using Storage = std::array; - + public: struct Extent - : std::unique_ptr + : std::array + { + using Payload = T; + }; + + private: + struct Storage + : std::unique_ptr { /** * @note default ctor immediately allocates the full storage, - * but uses default initialisation rsp. no initialisation - * in case the payload type T is a POD + * but without initialisation since payload is `char` */ - Extent() - : std::unique_ptr{new Storage} + Storage() + : unique_ptr{new char[sizeof(Extent)]} { } + + /** access projected Extent storage type + * @warning payload is uninitialised and dtors won't be invoked + */ + Extent& + access() + { + ENSURE (get() != nullptr); + return reinterpret_cast (*get()); + } }; - using Extents = std::vector; + using Extents = std::vector; + Extents extents_; - size_t start_,after_; public: explicit ExtentFamily(size_t initialCnt =0) : extents_{initialCnt} - , start_{0} - , after_{initialCnt} + , start_{0} // Extents allocated yet marked unused + , after_{0} { } void diff --git a/tests/vault/gear/block-flow-test.cpp b/tests/vault/gear/block-flow-test.cpp index 81e431c88..4354925bf 100644 --- a/tests/vault/gear/block-flow-test.cpp +++ b/tests/vault/gear/block-flow-test.cpp @@ -26,6 +26,7 @@ #include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" #include "vault/gear/block-flow.hpp" //#include "lib/time/timevalue.hpp" //#include "lib/format-cout.hpp" @@ -36,10 +37,11 @@ using test::Test; //using std::move; //using util::isSameObject; +using lib::test::randTime; namespace vault{ -namespace mem { +namespace gear { namespace test { // using lib::time::FrameRate; @@ -72,6 +74,13 @@ namespace test { void simpleUsage() { + BlockFlow bFlow; + Time deadline = randTime(); + Activity tick = bFlow.createActivity(Activity::TICK, deadline); + ///////////////////////////////////////////////////////////////////////////////OOO diagnostic function to check allocation + + bFlow.discardBefore (deadline + Time{0,5}); + ///////////////////////////////////////////////////////////////////////////////OOO diagnostic function to check de-allocation } @@ -99,4 +108,4 @@ namespace test { -}}} // namespace vault::mem::test +}}} // namespace vault::gear::test diff --git a/wiki/renderengine.html b/wiki/renderengine.html index f522c69b1..7ab0a55d8 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -6853,7 +6853,7 @@ At first sight the link between asset and clip-MO is a simple logical relation b {{red{Note 1/2015}}} several aspects regarding the relation of clips and single/multichannel media are not yet settled. There is a preliminary implementation in the code base, but it is not sure yet how multichnnel media will actually be modelled. Currently, we tend to treat the channel multiplicity rather as a property of the involved media, i.e we have //one// clip object. -
+
//Render Activities define the execution language of the render engine.//
 The [[Scheduler]] maintains the ability to perform these Activities, in a time-bound fashion, observing dependency relations; activities allow for notification of completed work, tracking of dependencies, timing measurements, re-scheduling of other activities -- and last but not least the dispatch of actual [[render jobs|RenderJob]]. Activities are what is actually enqueued with priority in the scheduler implementation, they are planned for a »µ-tick slot«, activated once when the activation time is reached, and then forgotten. Each Activity is a //verb//, but can be inhibited by conditions and carry operation object data. Formally, activating an Activity equates to a predication, and the subject of that utterance is »the render process«.
 
@@ -6871,6 +6871,8 @@ The [[Scheduler]] maintains the ability to perform these Activities, in a time-b
 :push a message to another Activity or process record
 ;probe
 :invoke a closure within engine context; inhibit another target Activity, depending on the result.
+;gate
+:probe a launch window [start…deadline[ and check a count-down latch ⟹activate next Activity | else re-schedule @self into the future
 ;tick
 :internal engine »heart beat« -- invoke internal maintenance hook(s)
  
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 709841ae9..b278c277e 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -77761,7 +77761,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -77772,6 +77772,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

+
@@ -77809,7 +77810,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -77820,6 +77821,19 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

+ +
+ + + + + + +

+ probe a launch window from start to deadline, and additionally check a count-down latch; on success activate the next Activity, else re-schedule @self into the future +

+ +
@@ -78244,7 +78258,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -78289,11 +78303,41 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -78519,14 +78563,14 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- +

- Es handelt sich hierbei um ein grundsätzliches Problem. Es liegt in der Natur von IO, daß eine solche Operation eine unbestimmte Zeit dauern kann; und diese Zeit kann ganz erheblich sein, wenn das IO-Subsystem überlastet wird. Es gibt keine Möglichkeit, eine IO-Operation abzubrechen; vielmehr kommen die Daten irgendwann an, und landen dann in dem dafür vorgesehenen Buffer. Und solange das nicht passiert ist, muß der Buffer und der Callback im Speicher bereitliegen. Ich sehe keine andere Möglichkeit, als für jede Epoche einen Zähler aller schwebenden IO-Operationen mitzuführen. Mithilfe der »post«, »notify« und »guard«-Activities ließe sich das jedoch single-threaded verwirklichen — Synchronisations-Effekte treten daher nur für Threads, die grade eine IO-Operation abgeschlossen haben, sowie den Thread, der das GroomingToken hält + Es handelt sich hierbei um ein grundsätzliches Problem. Es liegt in der Natur von IO, daß eine solche Operation eine unbestimmte Zeit dauern kann; und diese Zeit kann ganz erheblich sein, wenn das IO-Subsystem überlastet wird. Es gibt keine Möglichkeit, eine IO-Operation abzubrechen; vielmehr kommen die Daten irgendwann an, und landen dann in dem dafür vorgesehenen Buffer. Und solange das nicht passiert ist, muß der Buffer und der Callback im Speicher bereitliegen. Ich sehe keine andere Möglichkeit, als für jede Epoche einen Zähler aller schwebenden IO-Operationen mitzuführen. Mithilfe der »post«, »notify« und »gate«-Activities ließe sich das jedoch single-threaded verwirklichen — Synchronisations-Effekte treten daher nur für Threads, die grade eine IO-Operation abgeschlossen haben, sowie den Thread, der das GroomingToken hält

@@ -78590,7 +78634,24 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + + + + + + + + +

+ nested Typedef Payload +

+ +
+
+ + + @@ -78604,29 +78665,32 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- +

- das heißt: es findet zwar eine default-Initialisierung statt, aber für einen Objekt-Typ bedeutet das value-Initialisierung der Member. Nur falls der Payload-Typ ein POD ist, findet keine Initialisierung statt — und ich hoffe, daß der Optimizer das checkt + das heißt: es findet zwar eine default-Initialisierung statt, aber für einen Objekt-Typ mit implizitem default-ctor bedeutet das default-Initialisierung der Member. Nach meinem Verständnis hat std::array einen impliziten default-ctor und als einziges Member ein Array, und dafür wiederum erfolgt dann default-Initialisierung jedes einzelnen Elements. Und da das Element ein base-value (char) ist, erfolgt überhaupt keine Initialisierung.

- +
- + + + - + + @@ -78634,6 +78698,25 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + +

+ genau für sowas war der gedacht ☻ +

+ +
+
+
+ + +
@@ -78653,6 +78736,124 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + +

+ ...selbst wenn es Zusammenhänge gibt — notfalls wird die Aktion in die nächst nachfolgende Epoche geschoben (welche stets länger lebt) +

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

+ jede Deadline vor dieser Zeit ist damit grundsätzlich obsolet +

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

+ zwar wird ein POST geplant, +

+

+ aber die angehängten Activities werden +

+

+ dafür später kopiert (Addresse ändert sich) +

+ +
+ +
+
+
@@ -79412,7 +79613,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- +