From 80a48abcf4453bb2f71aa44ec7dbf2e96f08f541 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 29 Aug 2023 16:40:52 +0200 Subject: [PATCH] Activity-Lang: determine role of the time window parameters --- src/vault/gear/activity-term.hpp | 39 +- tests/vault/gear/scheduler-activity-test.cpp | 7 +- wiki/renderengine.html | 26 +- wiki/thinkPad.ichthyo.mm | 475 ++++++------------- 4 files changed, 203 insertions(+), 344 deletions(-) diff --git a/src/vault/gear/activity-term.hpp b/src/vault/gear/activity-term.hpp index fbfa72518..2c0530513 100644 --- a/src/vault/gear/activity-term.hpp +++ b/src/vault/gear/activity-term.hpp @@ -53,7 +53,7 @@ #include "lib/time/timevalue.hpp" //#include "lib/util.hpp" -//#include +#include #include @@ -63,7 +63,7 @@ namespace gear { using lib::time::Time; using lib::time::TimeValue; // using util::isnil; -// using std::string; + using std::string; using std::move; using BlockFlowAlloc = BlockFlow; @@ -85,6 +85,9 @@ namespace gear { Activity* invoke_{nullptr}; Activity* post_{nullptr}; + Activity* gate_{nullptr}; + + public: enum Template {CALC_JOB ///< scheme for a synchronous media calculation job ,LOAD_JOB ///< scheme for an asynchronous data retrieval job @@ -96,19 +99,25 @@ namespace gear { : alloc_{move (allocHandle)} , invoke_{setupInvocation (job)} , post_{setupPost (start,after, invoke_)} - { } + { + configureTemplate (kind); + } -// virtual std::string -// diagnostic() const -// { -// return "Activity::Hook"; -// } + // standard copy acceptable -// operator std::string() const -// { -// return diagnostic(); -// } + operator std::string() const + { + return "Term-" + + (post_? string{*post_} : util::BOTTOM_INDICATOR) + + "⧐" + + (invoke_? string{*invoke_} : util::BOTTOM_INDICATOR); + } + + /** + * @return entrance point to this Activity-chain setup + * @remark use this call for instructing the Scheduler. + */ Activity& post() { @@ -117,6 +126,12 @@ namespace gear { } private: + void + configureTemplate (Template kind) + { + + } + Activity* setupInvocation (Job& job) { diff --git a/tests/vault/gear/scheduler-activity-test.cpp b/tests/vault/gear/scheduler-activity-test.cpp index e3de5e3ae..5dc8c3a76 100644 --- a/tests/vault/gear/scheduler-activity-test.cpp +++ b/tests/vault/gear/scheduler-activity-test.cpp @@ -350,7 +350,7 @@ namespace test { /** @test TODO verify the Activity term builder - * @todo WIP 8/23 🔁 define ⟶ implement + * @todo WIP 8/23 🔁 define 🔁 implement */ void termBuilder() @@ -365,8 +365,13 @@ namespace test { Time dead{0,10}; auto term = activityLang.buildCalculationJob (job,start,dead); + // Time window parameters have been included Activity& post = term.post(); CHECK (Activity::POST == post.verb_); + CHECK (start == post.data_.timeWindow.life); + CHECK (dead == post.data_.timeWindow.dead); + + cout << term< -
+
//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«.
 
@@ -6891,7 +6891,7 @@ Activities are organised into ''chains'', allowing to express relations based on
 There are //standard usage patters,// hard coded into the {{{ActivityLang}}} and expected by the {{{SchedulerCommutator}}}, to express all relevant [[patterns of operational logic|RenderOperationLogic]] necessary to represent time-bound and dependent playback and render tasks.
 
 !The Activity Language
-While the Activities are low-level primitives and can be handled directly by the scheduler, any actual rendering invocation must arrange several Activities into a suitable chain of operations. Thus the actual rendering invocation can be seen as a //sentence of the Activity Language.// Formally speaking, it is a //symbolic term.// Not every possible term (and thus sentence) leads to semantically sound behaviour, and thus the ''Scheduler Interface Setup'' is organised in the form of a //builder notation to construct viable Activity terms.// {{{vault::gear::ActivityLang}}} provides the framework for such builder invocations, and allows to create such terms as transient objects -- connected to the durable {{{Activity}}} records allocated into the [[»BlockFlow« memory manager|SchedulerMemory]] backing the Scheduler operation. The language term is thus a front-end, and exposes suitable extension and configuration points for the JobPlanningPipeline to instruct the necessary Scheduler operations to enact a specific [[render Job|RenderJob]].
+While the Activities are low-level primitives and can be handled directly by the scheduler, any actual rendering invocation must arrange several Activities into a suitable chain of operations. Thus the actual rendering invocation can be seen as a //sentence of the Activity Language.// Formally speaking, it is a //symbolic term.// Not every possible term (and thus sentence) leads to semantically sound behaviour, and thus the ''Scheduler Interface Setup'' is organised in the form of a //builder notation to construct viable Activity terms.// {{{vault::gear::ActivityLang}}} provides the framework for such builder invocations, and allows to create such terms as transient objects -- connected to the durable {{{Activity}}} records allocated into the [[»BlockFlow« memory manager|SchedulerMemory]] backing the Scheduler operation. The language term is thus a front-end, and exposes suitable extension and configuration points for the JobPlanningPipeline to instruct the necessary Scheduler operations in order to enact a specific [[render Job|RenderJob]].
 
 The //meaning// of Activities can be understood on two levels. For one, there is the abstract, //conceptual level:// Each Activity represents a verb to express something //performed by »the render process«// -- which in turn appears as a combination and connection of these elementary expressions. Activity verbs can be linked together in a limited number of ways
 * chaining means sequencing -- first //this// Activity, followed by //that// Activity
@@ -7041,7 +7041,7 @@ __see also__
 &rarr; the protocol [[how to operate the nodes|NodeOperationProtocol]]
 
-
+
//The operational logic of Activity execution is the concrete service provided by the [[Scheduler]] to implement interwoven [[render Activities|RenderActivity]] and [[Job  execution|RenderJob]].//
 * logically, each {{{Activity}}} record represents a //verb// to describe some act performed by »the render process«
 * the {{{ActivityLang}}} provides a //builder notation// to build „sentences of activities“ and it sets the framework for //execution// of Activities
@@ -7049,7 +7049,7 @@ __see also__
 * the ''Scheduler Layer-1'' ({{{SchedulerInvocation}}}) provides the low-level coordination and invocation mechanics to launch [[render Jobs|RenderJob]].
 
 !Framework for Activity execution
-The individual {{{Activity}}} records serve as atomic execution elements; an Activity can be invoked once, either by time-bound trigger in the Scheduler's priority queue, or by receiving an activation message (directly when in //management mode,// indirectly through the invocation queue else). The data structure of the {{{Activity}}} record (&rarr; [[description|RenderActivity]]) is maintained by the [[»block flow« memory allocation scheme|SchedulerMemory]] and can be considered stable and available (within the logical limits of its definition, which means until the overarching deadline has passed). The ''activation'' of an Activity causes the invocation of a hard-wired execution logic, taking into account the //type field// of the actual {{{Activity}}} record to be »performed«. This hard-wired logic however can be differentiated into a //generic// part (implemented directly in {{{class Activity}}}) and a //contextual// part, which is indirected through a ''λ-binding'', passed as ''execution context'', yet actually implemented by functions of ''Scheduler Layer-2''.
+The individual {{{Activity}}} records serve as atomic execution elements; an Activity can be invoked once, either by time-bound trigger in the Scheduler's priority queue, or by receiving an activation message (directly when in //management mode,// else indirectly through the invocation queue). The data structure of the {{{Activity}}} record (&rarr; [[description|RenderActivity]]) is maintained by the [[»block flow« memory allocation scheme|SchedulerMemory]] and can be considered stable and available (within the logical limits of its definition, which means until the overarching deadline has passed). The ''activation'' of an Activity causes the invocation of a hard-wired execution logic, taking into account the //type field// of the actual {{{Activity}}} record to be »performed«. This hard-wired logic however can be differentiated into a //generic// part (implemented directly in {{{class Activity}}}) and a //contextual// part, which is indirected through a ''λ-binding'', passed as ''execution context'', yet actually implemented by functions of ''Scheduler Layer-2''.
 !!!execution patterns
 Since the render engine can be considered performance critical, only a fixed set of //operational patterns// is supported, implemented with a minimum of indirections and thus with limited configurability. It seems indicated to confine the scope of this operational logic to a finite low-level horizon, assuming that //all relevant high-level render activities// can actually be //expressed in terms of these fundamental patterns,// in combination with an opaque JobFunctor.
 ;Frame Render Job
@@ -7059,12 +7059,12 @@ Since the render engine can be considered performance critical, only a fixed set
 :** these Activities are chained-up (hooked onto the {{{next}}} pointer)
 :** depending on the //invocation context...//
 :*** in ''grooming mode'' (i.e. the current worker holds the {{{GroomingToken}}}) the follow-up activation happens synchronously
-:*** in ''work mode'' (i.e. the {{{GroomingToken}}} has been dropped) the Scheduler internals //must not be altered;// the chain has to be dispatched
+:*** in ''work mode'' (i.e. {{{GroomingToken}}} has been dropped) the Scheduler internals //must not be altered;// the chain thus has to be dispatched
 :** ⟹ the Activity Language invokes the ''λ-post''.
 :* {{{GATE}}} : provides a check-point to ensure the preconditions are met
-:** the current //wall-clock-time// is checked against the //deadline//
-:** moreover, a //prerequisite count// is checked, allowing passage only if the count has been ticked off to zero
-:** while surpassing the deadline simply obliterates all chained Activities, unmet prerequisites cause a spinning delay-and-recheck
+:** the current //scheduler-time// (≈ system time) is checked against the //deadline//
+:** moreover, a //prerequisite count// is checked, allowing passage only if the internal countdown latch has been ticked off to zero;
+:** while surpassing the deadline simply obliterates all chained Activities, unmet prerequisites cause a „spinning“ delay-and-recheck
 :** the count-down of prerequisites is caused by receiving a ''notification'' (either externally, or from a {{{NOTIFY}}}-Activity)
 :** receiving such a notification causes re-evaluation of the condition and possibly activation of the chain
 :** ⟹ the Activity Language evaluates the condition {prerequisite ≡ 0 and before deadline}.
@@ -7075,7 +7075,7 @@ Since the render engine can be considered performance critical, only a fixed set
 :** the {{{GroomingToken}}} is dropped, allowing other [[workers|SchedulerWorker]] to enter grooming mode and to retrieve further jobs.
 :** ⟹ the Activity Language invokes the ''λ-work''.
 :* {{{INVOKE}}} : actually invoke the JobFunctor given as immediate argument
-:** a fixed number of further {{{size_t}}} arguments are retrieved from the {{{FEED}}}-Activities following next
+:** a fixed number of further {{{uint64_t}}} arguments are retrieved from the {{{FEED}}}-Activities following next
 :** all currently foreseeable render operations invoked from here do not need more than 4 fixed arguments (the rest being prepared by the Builder)
 :**  ⟹ the Activity Language directly invokes the ''~JobFunctor'', in the current thread, which thus might be blocked indefinitely.
 :* {{{FEED}}} : used to transport argument data for render operations
@@ -7084,11 +7084,11 @@ Since the render engine can be considered performance critical, only a fixed set
 :** ⟹ the Activity Language invokes the ''λ-done''.
 :** the current time and a payload argument is emitted as message -- for self-regulation of the render engine
 :** logically, the current worker is now free for further work -- which is attained implicitly
-:* {{{NOTIFY}}} (optional) : pass a trigger event to some other Activity dependant on the current render operation's results
-:** the actual trigger is //double dispatched// -- depending on the target Activity given as argument
+:* {{{NOTIFY}}} (optional) : pass a trigger event to some other Activity dependent on the current render operation's results
+:** the actual trigger is //double dispatched// -- considering the target Activity given as argument
 :**  ⟹ the Activity Language ...
 :*** for a {{{GATE}}} as target ⟹ //triggers// the gate, which implies to decrement the dependency counter, possibly activating the chain
-:*** -- //further special trigger cases may be {{red{added later}}}// --
+:*** ┉┉ //further special trigger cases may be {{red{added later}}}// ┉┉
 :*** for any other target Activity ⟹ invoke the ''λ-post'' ⟹ contend for acquiring the {{{GroomingToken}}} to re-enter ''grooming mode''
 ;Media Reader Job
 :Retrieve raw media data from external storage, using ''asynchronous IO''
@@ -7120,7 +7120,7 @@ Since the render engine can be considered performance critical, only a fixed set
 ;Tick
 :Internal periodical maintenance duty cycle
 :* {{{TICK}}} : a special marker Activity, which re-inserts itself on each activation and performs an internal hook of the Render Engine
-:**  ⟹ the Activity Language invokes the ''λ-work''
+:**  ⟹ the Activity Language invokes the ''λ-tick''
 
 !!!Post and dispatch
 An Activity is //performed// by invoking its {{{activate(now, ctx)}}} function -- however, there is a twist: some Activities require interaction with the Scheduler queue or may even alter this queue -- and such Activities must be performed //in »management mode«// (single threaded, holding the {{{GroomingToken}}}). These requirements can be fulfilled by //dispatching// an Activity through the ''λ-post'', which attempts to acquire the {{{GroomingToken}}} and otherwise sends the action through the //dispatch queue.// Moreover, some follow-up activities need to happen //later// -- and this can be encoded by using a {{{POST}}}-Activity, which both defines a time window of execution and causes its chain-Activity to be sent through ''λ-post''.
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index c76c7f5e6..ce7ecbf8f 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -71430,9 +71430,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

ResIter::value_type ≡ JobTIcket @@ -71461,9 +71459,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

was wäre an der Stelle logisch korrekt ? @@ -71474,9 +71470,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

die Frage lautet: @@ -71493,9 +71487,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

für die Expanded-Results klar: brauche exakt den Ergebnis-Typ  des Iterators @@ -71507,9 +71499,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

...denn das ergibt sich erst im Aufrufkontext; man denke z.B. an rvalue/lvalue-Probleme und temporaries, und das alles noch mit constness gemischt. Auf weia @@ -71525,9 +71515,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

Fazit: Konversion in SRC::value_type ist per Abschwächung die korrekte Forderung @@ -71557,9 +71545,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

Und zwar erscheint mir die STL zugleich als zu komplex und zu offen; sie verleitet zu einem Low-level-Geknobel. Genau deshalb habe ich die gesamte Iteratoren- und Konzept-Hierarchie der STL beiseite geschoben, und ein »Lumiera Forward Iterator«-Concept neu definiert. @@ -71570,9 +71556,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

Denn ganz bewußt habe ich es abgelehnt, mit Lumiera ein universelles Framework zu schaffen (wiewohl eine Tendenz dorthin nicht zu verleugnen ist). Vielmehr geht es mit allen Konventionen und Definitionen um eine Gründung, also darum, einen Raum zu schaffen, in dem sich etwas Neues von einem wohl bestimmten Charakter entwickeln kann. Ich richte mich also nicht nach dem Vorhandenen und ich muß nicht dem Vorhandenen in allen seinen Weiterungen und Verzweigungen entsprechen.  Diese Haltung entspricht jedoch auch meinem Charakter: meine Fähigkeiten zum Erfassen und Sortieren vorgegebener Normen und Gepflogenheiten waren (und sind) gering, wenn ich mich auf einen solchen Anspruch einlasse, stehe ich schnell kräftemäßig mit dem Rücken zur Wand. Anders die meisten meiner Kollegen, die blühen da gradezu auf. @@ -71592,9 +71576,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

der Implementator möchte mit den Typedefs die Signaturen aufbauen @@ -71604,9 +71586,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

der Nutzer möchte wissen, wie er mit Resultaten umgehen kann @@ -71628,9 +71608,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

...für die STL schon, aber das ist genau meine Kritik: die STL ist hier zu konkret und zu sehr low-level — ein const_iterator ist demnach etwas Anderes als ein iterator von einem Container über const-Werte, und das widerspricht meinem Konzept, einen Iterator als eine opaque Quelle zu betrachten @@ -71665,9 +71643,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

auch das zum Glück @@ -71740,9 +71716,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

...was wohl genau daran liegt, daß das TypeBinding bisher konzeptionell "daneben" war @@ -71803,9 +71777,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

hier ist ein Hinweis auf TICKET #1125 : get rid of Val @@ -71843,9 +71815,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

analog zu meta::Strip, nur weniger aggressiv @@ -71931,9 +71901,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

      using              _PID = PlacementMO::ID; @@ -71966,9 +71934,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

TransformIter<RangeIter<__normal_iterator<const GenNode*, vector<GenNode> > > @@ -71986,9 +71952,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

Hatte zunächst gedacht, generell sollte value_type den Typparameter unverändert durchreichen (sofern kein nested Binding erfolgt). Tatsächlich bestand das Problem aber nur bei Pointern, und das lösen wir besser direkt in den RefTraits @@ -72014,9 +71978,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

IterAdapter selber sieht sauber aus.... @@ -72027,9 +71989,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

und im Besonderen kein automatisches Entfernen von Indirektionen, und kein Rückgriff auf interne Typdefinitionen (also grade nicht  ValueTypeBinding verwenden!) @@ -72105,9 +72065,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

   * @note @@ -72170,9 +72128,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

der Double wird nämlich (wohlweislich) für diese Diagnostic-Anzeige auf 8 Stellen gerundet ... genau wegen Probemen wie hier @@ -72185,9 +72141,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

1 * 1.1 = 1.100000000000000000000000000001 @@ -72204,9 +72158,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

konkret: double verhält sich anders als const double oder volatile double @@ -72220,9 +72172,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

  • @@ -72252,9 +72202,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    das heißt, wir erkennen gar nicht mehr, daß der Typ möglicherweise nested Bindings hat, weil viele Konstrukte für Klassen gar nicht valide sind für Referenzen, und daher die Erkennungs-Mechanismen ins Leer laufen @@ -72318,9 +72266,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...welches sich hier konkret so manifestiert hat, daß der ResultIterator::value_type falsch deduziert wurde als JobTicket  (anstatt JobTicket* ) @@ -72350,9 +72296,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    möglicherweise hat damals (2017) das perfect forwarding noch nicht so gut funktioniert (wir verwenden ja debian/stable, das war dann von 2015 und hatte noch etwas ältere Compiler) @@ -72394,9 +72338,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    HA!  std::is_convertible<const JobTicket, const JobTicket>()  ⟶ false @@ -72424,9 +72366,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    denn es ist letztlich egal, welcher Typ für welchen eintritt @@ -72439,9 +72379,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    nein! das Muster ist nicht symmetrisch @@ -72456,9 +72394,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    was bedeutet, das Ergebnis muß ein gemeinsamer Schnitt-Typ von beiden sein @@ -72468,9 +72404,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    und das bedeutet, daß beide Ergebnistypen einen gemeinsamen Schnitt-Typ haben müssen, der auf den Argumenttyp des Expand-Funktors konvertierbar ist @@ -72498,9 +72432,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ist vielleicht sogar ein Compiler-Bug? @@ -72536,9 +72468,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...und zwar weil eben auch der IterStack mit involviert ist, und die State-Core-Implementierungs-Funktionen allesamt verzweigen, je nachdem ob schon expandierte Kinder da sind; es bringt nichts, diese Verzweigungs-Struktur irgendwo wegzupacken, entweder man zerreißt sie in zwei Teile (wodurch sie unverständlich wird), oder der Expander selber wird eine leere Hülle, und alle Logik wandert in ein Delegate (wozu das?) @@ -72571,9 +72501,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...das hat sich nun schon mehrfach als sehr hilfreich erwiesen: man instantiiert das Trait-Template „auf der grünnen Wiese“ und kann es dann direkt mit lib::test::TypeDebugger analysieren... @@ -72669,9 +72597,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    und korrumpiert daher die laufende Berechnung auf top-Level @@ -72690,9 +72616,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    Prerequisites sind privat in JobTicket @@ -72702,9 +72626,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    deshalb können sie erst im Konstruktor gebaut werden @@ -72714,9 +72636,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    außerdem gibt es kein Mutatons-API @@ -72726,9 +72646,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    also müssen sie auch bereits im Konstruktor vollständig gebaut werden @@ -72738,9 +72656,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    und obendrein ist JobTicket non-Copyable @@ -72750,9 +72666,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    also muß es per emplace erzeugt werden @@ -72780,9 +72694,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    Entscheidung im Hinblick auf den AllocationCluster @@ -72790,9 +72702,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    das kommt nicht von Ungefähr: dieses ganze (relativ fragile) Setup mit den Referenzen in LinkedElements mache ich ganz bewußt, weil am Ende ein Allocation-Schema beabsichtigt ist, bei dem viele Elemente in kurzer Zeit in einen gemeinsam allozierten großen Block gelegt werden; dort bleiben sie bestehen, selbst nachdem ihr Destruktor aufgerufen wurde. Die De-Allokation erfolgt auf einmal, zusammen mit dem gesamten Segment @@ -72808,9 +72718,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    das ist eine »bastel-Lösung« @@ -72825,9 +72733,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    list::emplace_back  funktioniert @@ -72848,9 +72754,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    Verwende eine halb-Rotation über size_t ⟹ @@ -72898,9 +72802,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...und das ist gut so @@ -72914,9 +72816,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ärgerliche Konsequenz: bekomme viele Instanzen vom JobFunktor @@ -72930,9 +72830,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...ich darf nicht daran hängenbleiben, daß der Marker literal in der InvocationInstanceID steckt; das mit der Uniton ist ohnehin nur ein temporärer Trick und kann nicht dauerhaft so bleiben — vielmehr ist die Lösung, den chained-Hash-Mechanismus für den Test so umzufunktionieren, daß man mit ihm beweisen kann, daß ein ganz bestimmter Job auch aufgerufen wurde. @@ -72948,9 +72846,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...mit dem man zufällige pseudo-Invocations erzeugen kann und diese auch später mithilfe eines statischen Invocation-Log verifizieren. @@ -72960,9 +72856,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...und die setzt auf die für später tatsächlich vorgesehene Hash-Verknüpfung auf, welche in diesem Fall auch die nominelle Zeit in die InvocationInstanceID mit einrechnet — nicht jedoch die reale Deadline (die in der Job-Instanz explizit vermerkt ist) @@ -72976,9 +72870,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    Bisher wird noch die Fiktion aufrecht erhalten, daß die Basis-Schnittstelle zum Scheduler in reinem C geschrieben ist; tatsächlich ist dadurch so mancher Teil der implementierung grenzwertig bzw. würde tatsächlich mit reinem C nicht (mehr) funktionieren; außerdem bekommen wir mehfrach geschichtete Vererbungen und müssen regelmäßig casten und implizite ungeprüfte Annahmen machen. @@ -73041,9 +72933,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    hier Problem mit der Model-Port-Differenzierung geeignet »unter den Teppich kehren« @@ -73057,9 +72947,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    tatsächlich: erst mal nur stupide aufdoppeln @@ -73067,9 +72955,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...eine billige und manipulative Implementierung in MockSegmentation @@ -73089,9 +72975,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    das erlaubt flexibles Hinzufügen, ohne daß Addressen invalidiert werden. Die Tickets selber müssen NonCopyable sein @@ -73174,9 +73058,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    sonst ⟹ REJECT @@ -73302,9 +73184,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    Nach logischer Analyse der spezifiziereten Fälle lassen sich einige Verzweigungen verkürzen @@ -73380,9 +73260,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    lib/split-splice.hpp @@ -73399,9 +73277,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    tja... @@ -73444,9 +73320,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    [-100~100[┤ @@ -73486,9 +73360,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    expect:├[-100~2[[4_5[[5_10[[10~100[┤ @@ -73501,9 +73373,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    bei der Verarbeitung des Successors hat einer der Fälle auf die Operation opPred_ für den Predecessor geprüft; im konkreten Fall war das TRUNC, wohingegen für den Successor SEAMLESS vorgesehen war. Daher wurde dann an dieser Stelle eine Trucated-copy dies Successors eingefügt, wobei in diesem Fall das Trucate gar nicht verkürzt hat, da der Anfangspunkt des Successors bündig liegt; so kommt es, daß der Successor komplett aufgedoppelt wurde @@ -73514,9 +73384,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...habe im Debugger verifiziert, daß das mit den Interatoren-Positionen wirklich klappt: sie bleiben stabil. Trotzdem wird der Code lesbarer, wenn man nur in diesem Stück pred_ explizit bezeichnet als "insPos" (und pred_ nicht weiter verwendet). @@ -73688,9 +73556,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    Ich kann an dieser Stelle noch nicht auf die tatsächiche Implementierung vorgreifen, sonst wird das alles ein undurchdringbares Knäuel. Die eigentliche Implementierung muß stark auf Performance optimiert sein, und daher ist die Datenstruktur vermutlich schwierig zu navigieren. Also baue ich hier ganz bewußt erst mal eine Fake-Variante auf, mit einer anderen Implementierung und einer bequemen Datenstruktur @@ -73716,9 +73582,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ... vor allem eine zusätzliche Indirektion, deren Wirkung nicht einfach abzuschätzen ist. Die tatsächliche Listenlänge muß letztlich immer irgendwo explizit repräsentiert werden, und wenn man dies in einem Subtyp verbirgt, muß jeder Datenzugriff zwingend einmal durch eine Indirektion laufen @@ -73781,9 +73645,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    geht nicht: ist privat (und das ist sinnvoll so!) @@ -73801,9 +73663,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    und zwar ist die JobTicket-Struktur explizit darauf angelegt, anderweitig erstellte Deskriptoren zu verlinken; das soll so sein aus Performance-Gründen (Cache Locality ⟹ AllocationCluster) @@ -73817,9 +73677,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    Spezifikation: JobTicket erstellen @@ -73849,9 +73707,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    die muß definitiv von „wo anders“ kommen @@ -73868,9 +73724,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    Ziel sollte tatsächlich sein, die Komplexitäten mit der Allokation aus dem funktionalen Code heraus zu verbergen; denn dies dient nur dem separaten Belang der Performance @@ -73885,9 +73739,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...ist hier relevant, denn dies scheidet eine einfache Funktions/Konstruktor-Schnittstelle aus; wir müssen einen strukturierten Datensatz bereitstellen @@ -73897,9 +73749,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    Zunächst wurden LinkedElements lediglich aus Gründen der Konsistenz auch hierfür verwendet. Eine intrusive-single-linked-List mag für die Vernetzung der Prerequisites sinnvoll sein, aber für eine Sprungtafel nach Channel-Nr ließe sich genauso gut eine Array-backed-Implementation konstruieren (vielleicht dann ein neuer Anlauf anstelle der alten Idee des »RefArray« ?) @@ -73909,9 +73759,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...denn es wird noch deutlich über dieses PlaybackVerticalSlice hinaus dauern, bis die erste rudimentäre Implementierung des Builders am Start ist — und erst dann gibt es eine praktischen Bezugspunkt für das Design @@ -73922,9 +73770,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...möglicherweise könnte zumindest so der wichtigste Standardfall komplett ohne einen eigens allozierten JobFunktor dargestellt werden — einfach indem alle notwendigen Parameter direkt aus der referenzierten ProcNode gezogen werden. Um diese Möglichkeit abzuschätzen, müßte aber zuerst definiert werden, wie der Übergang zu den Prerequisites konkret im Proc-Node-Graph dargestellt werden: durch spezielle Metadaten? oder durch eine besondere Marker-Node, die wie eine Quelle fungiert? @@ -73975,9 +73821,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...nach zwei Tagen Gewürge.... @@ -74009,9 +73853,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    über die interne Provision-Datastruktur (LinkedElements) @@ -74058,9 +73900,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...was auf eine Verwirrung in den Konzepten und Begriffen hindeutet (die ich schon seit Tagen vermute, aber noch nicht recht fassen kann) @@ -74081,9 +73921,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    also relativ zum Ursprung des Time-Grid dieser Timeline @@ -74103,9 +73941,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...deshalb kapiere ich ihn immer nicht @@ -74119,9 +73955,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...weil ich erst mal einen Test schreiben wollte, und sonst noch keinerlei tragende Strukturen hatte @@ -74131,9 +73965,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ⟹ alles mit Latency und Deadline muß weg @@ -74149,9 +73981,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    also besser dann als separaten Test dokumentieren @@ -74180,9 +74010,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    allein schon, weil wir eine limitierte Domäne haben bezüglich lib::time::Time @@ -74226,9 +74054,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...oder genauer gesagt, ein Design-Mismatch — das ganze ID-System in Lumiera ist magisch und „hintenrum“ mit globalen Tabellen verbunden; damals erschien mir das gradezu natürlich, heute sehe ich leider keine bessere Lösung, die man in C++ realisieren kann (Scala löst dieses Problem mit den Implicits bzw. Givens) @@ -74239,9 +74065,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...und nicht das ultimative Medien-Framework!! @@ -74255,9 +74079,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    es lebe die DummyPlayConnection @@ -74274,9 +74096,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    DataSink ist ein lib::Handle<play::OutputSlot::Connection> @@ -74295,9 +74115,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...denn eine »state core« wird automatisch von TreeExplorer erkannt und adaptiert... @@ -74320,9 +74138,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    siehe iter-chain-search.hpp @@ -74333,9 +74149,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...man packt den eigentlichen TreeExplorer-Builder-Aufruf in eine Hilfsunktion und greift den decltype vom Rückgabewert ab; von diesem Typ kann man dann erben (und verwendet die erwähnte Hilfsfunktion im Konstruktor, um den Parent-Typ zu initialisieren)i @@ -74346,9 +74160,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    So macht es der TreeExplorer selber, und nach etlichen Versuchen bin ich auch hier bei dieser Lösung gelandet (und zufrieden damit) @@ -74371,9 +74183,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    In diesem Zusammenhang ist type inference praktisch unvermeidbar, denn die komplexen Typen vom TreeExplorer können anders nicht explizit gemacht werden — aber das Problem ist, die Typen sind rekursiv, denn den neuen, erweiterten Builder-Typ muß ich schon kennen, um ihn in dem TreeEplorer-Builder als Core zu übergeben, aber erst durch diesen Aufruf wird dieser neue erweiterte Builder überhaupt definiert @@ -74383,9 +74193,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...also zunächst einen deaktivierten NumIter als Basisklasse, und an diesen später einen aktivierten NumIter zuweisen...  ziemlich häßlich, aber damit bekomme ich es überhaupt erst mal durch den Compiler... @@ -74417,9 +74225,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...weil sie erst nach den Builder-Typen definiert werden kann, aber bereits vor ihnen gebraucht wird @@ -74430,9 +74236,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...weil man dadruch von der Definitionsreihenfolge entkoppeln kann @@ -74443,9 +74247,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    geht, ist aber alles andere als klar, da man zunächst den Member-Fun-Pointer abgreifen muß, und dann von diesem den decltype ziehen (und erst damit kann man lib::meta::_Fun anwenden) @@ -74469,9 +74271,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    das löst ganz elegant beide Probleme @@ -74504,9 +74304,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    Zwischen-Fazit: Anwendung von TreeExplorer passiert nur in einem Funktions-Scope @@ -74571,9 +74369,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    Der expand()-Mechanismus im TreeExplorer ist kein monadisches flatMap  — sondern nur ähnlich (aber an den intendierten Nutzen angepaßt): das Vater-Element erscheint zunächst selbst im Resultat-Iterator, und dann erst folgen expandierte Kind-Elemente; monadisches flatMap würde den Vater sofort konsumieren und rekursives flatMap würde sofort bis auf unterste Blatt-Ebene entfalten. Aber die Konsequenz ist: da wir den Vater selber einmal durchreichen, müssen Ergebnistyp und Quelltyp kompatibel sein @@ -74593,9 +74389,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    Fazit: in diesem dritten Anlauf konnte ich das Problem befriedigend lösen @@ -74632,9 +74426,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...denn TreeExplorer hat die Eigenschaft, von der »state-core« zu erben, und damit ihr public-API nach außen durchzureichen — im Besonderen auch für obere Layer in der Pipeline @@ -74668,9 +74460,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...und zwar durch den gleichen Template-Slicing-Trick, der auch schon bei TreeExplorer selber so erfolgreich funktioniert: der Builder wird durch ein std::move auf die Basisklasse beschnitten und fällt dann als Temporary am Ende der Builder-Expressison einfach weg, aber aller relevanter Content ist in das Ergebnis geschoben worden, welches wegen RVO direkt am Zielort konstruiert wird @@ -77848,9 +77638,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - + - + @@ -77930,7 +77720,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - + @@ -78430,6 +78220,55 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    + + + + + + + + +

    + Zunächst hatte ich auf abstrakter Ebene festgestellt, daß „zur Aktivierung stets ein Zeitfenster gegeben sein muß“ — und beschlossen, dies „kontextuell“ bereitzustellen. Inzwischen hat sich aber herausgebildet, daß nur die allerwenigsten Activities tatsächlich vom Scheduler aktiviert werden; es könnte sein, daß der Scheduler ausschließlich POST-Activities handhabt, welche ohnehin das Zeitfenster explizit als Parameter transportieren. Allerdings wird das λ-post  in verschiedenen Fällen aufgerufen, und zwar mit POST-, GATE- und NOTIFY-Activities. +

    + +
    +
    + + + + +

    + Die GATE-Activity definiert auch noch einmal eine Deadline; welche Angabe gilt dann, und unter welchen Umständen? Kann es hier Widersprüche geben, und damit eine Präzedenz? +

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