From 14effc2349e9f042e76eba82e08a84320a081397 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 31 Aug 2023 20:18:35 +0200 Subject: [PATCH] Activity-Lang: consider logic for dependency notification ...turns out there is still a lot of leeway in the possible implementation, and seemingly it is too early to decide which case to consider the default. Thus I'll proceed with the drafted preliminary solution... - on primary-chain, an inhibited Gate dispatches itself into future for re-check - on Notification, activation happens if and only if this very notification opens the Gate - provide a specifically wired requireDirectActivation() to allow enforcing a minimal start time --- src/vault/gear/activity-term.hpp | 56 +++- tests/vault/gear/scheduler-activity-test.cpp | 50 ++++ wiki/renderengine.html | 6 +- wiki/thinkPad.ichthyo.mm | 260 +++++++++++++++++-- 4 files changed, 349 insertions(+), 23 deletions(-) diff --git a/src/vault/gear/activity-term.hpp b/src/vault/gear/activity-term.hpp index af3ff9b76..e9ca4d6d5 100644 --- a/src/vault/gear/activity-term.hpp +++ b/src/vault/gear/activity-term.hpp @@ -116,7 +116,7 @@ namespace gear { /** - * @return entrance point to this Activity-chain setup + * @return entrance point to this Activity-chain setup. * @remark use this call for instructing the Scheduler. */ Activity& @@ -126,6 +126,60 @@ namespace gear { return *post_; } + /** + * Builder operation: block this Term waiting for prerequisite notification. + * @param notificationSrc an `NOTIFY`-Activity to attach the notification-link + * @note using this feature implies to wire in a `GATE`-Activity (if not already + * present) and to increase the Gate's latch counter. Moreover, the Argument, + * _must be a `NOTIFY`_ and will be modified to store the link to this receiving + * Gate; typically this function is actually invoked starting from the other + * Term — the prerequisite — by invoking `appendNotificationTo(targetTerm)`. + */ + Term& + expectNotification (Activity& notificationSrc) + { + REQUIRE (Activity::NOTIFY == notificationSrc.verb_); + setupGate(); + ENSURE (gate_); + ENSURE (Activity::GATE == gate_->verb_); + gate_->data_.condition.incDependencies(); + notificationSrc.data_.notification.target = gate_; + return *this; + } + + /** + * Builder operation: append a Notification link to the end of this Term's chain. + * @param targetTerm another Term, which thereby becomes dependent on this Term. + * @remark the \q targetTerm will be inhibited, until this Term's chain has + * been activated and processed up to emitting the inserted `NOTIFY`. + */ + Term& + appendNotificationTo (Term& targetTerm) + { + UNIMPLEMENTED ("append NOTIFY and wire this through target.expectNotification()"); + return *this; + } + + /** + * Insert a self-inhibition to enforce activation is possible only after the + * scheduled start time. Relevant for Jobs, which are to be triggered by external + * events, while the actual computation must not be start prior to activating the + * main chain, even if all prerequisites are already fulfilled. + * @remark typical example is when a target buffer is known to be available only + * after the planned start time and until the planned deadline. + * @note the actual activation always goes through Activity::dispatch() and the + * primary chain is aborted with activity::SKIP. However, since the additional + * notification is inserted at a point executed holding the `GroomingToken`, + * the `dispatch()` actually happens synchronous and immediately processes + * the activated tail-chain in a nested call. + */ + Term& + requireDirectActivation() + { + UNIMPLEMENTED ("wire in self-Notification"); + return *this; + } + private: void configureTemplate (Template kind) diff --git a/tests/vault/gear/scheduler-activity-test.cpp b/tests/vault/gear/scheduler-activity-test.cpp index ca73bfa6e..18f093595 100644 --- a/tests/vault/gear/scheduler-activity-test.cpp +++ b/tests/vault/gear/scheduler-activity-test.cpp @@ -81,6 +81,7 @@ namespace test { dispatchChain(); scenario_RenderJob(); + scenario_Notification(); scenario_IOJob(); scenario_MetaJob(); } @@ -493,6 +494,55 @@ namespace test { + /** @test TODO usage scenario: Notification from prerequisite Jobs within time window + * - build [similar](\ref #scenario_RenderJob) »CalculationJob« wiring + * - configure extended dependency notification capabilities + * - Case-1 : a Notification decreases the latch, but blocks otherwise + * - Case-2 : when the primary chain is activated after the Notification, + * then the tail chain behind the Gate is dispatched + * @todo WIP 8/23 🔁 define ⟶ implement + */ + void + scenario_Notification() + { + Time nominal{7,7}; + + Time start{0,1}; + Time dead{0,10}; + Time now{555,5}; + + ActivityDetector detector; + Job testJob{detector.buildMockJob("testJob", nominal, 12345)}; + + BlockFlowAlloc bFlow; + ActivityLang activityLang{bFlow}; + auto term = activityLang.buildCalculationJob (testJob, start,dead); + + Activity& anchor = term.post(); + // insert instrumentation to trace activation + detector.watchGate (anchor.next, "theGate"); + + // establish a blocking prerequisite dependency + Activity trigger{Activity::NOTIFY}; + // ...in real usage this happens from building the dependency's Term + term.expectNotification (trigger); + + // additionally insert inhibition prior to primary-chain activation + term.requireDirectActivation(); + + CHECK (activity::PASS == ActivityLang::dispatchChain (anchor, now, detector.executionCtx)); + + CHECK (detector.verifyInvocation("theGate").arg("5.555 ⧐ Act(GATE") + .beforeInvocation("after-theGate").arg("⧐ Act(WORKSTART") + .beforeInvocation("CTX-work").arg("5.555","") + .beforeInvocation("testJob") .arg("7.007",12345) + .beforeInvocation("CTX-done").arg("5.555","")); + + cout << detector.showLog()< -
+
//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
@@ -7123,9 +7123,9 @@ Since the render engine can be considered performance critical, only a fixed set
 :**  ⟹ 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''.
+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}}} to proceed directly -- 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''.
 
-In a similar vein, also ''notifications'' need to happen decoupled from the activity chain from which they originate; thus the Post-mechanism is also used for dispatching notifications. Yet notifications are to be treated specially, since they are directed towards a receiver, which in the standard case is a {{{GATE}}}-Activity and will respond by //decrementing its internal latch.// Consequently, receiving a notification may cause the Gate to become opened; in this case the trigger is passed through a further dispatch through the ''λ-post'' to activate the chain-Activities hooked behind the Gate. The implementation of this state transition logic ensures that this chain behind a Gate can only be //activated once.//
+In a similar vein, also ''dependency notifications'' need to happen decoupled from the activity chain from which they originate; thus the Post-mechanism is also used for dispatching notifications. Yet notifications are to be treated specially, since they are directed towards a receiver, which in the standard case is a {{{GATE}}}-Activity and will respond by //decrementing its internal latch.// Consequently, receiving a notification may cause the Gate to become opened; in this case the trigger is passed through a further dispatch through the ''λ-post'' to activate the chain-Activities hooked behind the Gate. Otherwise, if the latch is already zero (or the deadline has passed), nothing happens. Thus the implementation of state transition logic ensures the chain behind a Gate can only be //activated once.//
 
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 851cb2578..4b296aa0a 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -76517,6 +76517,11 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + @@ -77491,10 +77496,24 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + - + + + + + + + + + + + + + + @@ -77506,6 +77525,12 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + +
@@ -77730,6 +77755,42 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ Falls es eine zeitliche Grenze gibt, vor der die Berechnungen grundsätzlich nicht starten sollen — beispielsweise weil die Ergebnis-Daten in einen Puffer geschrieben werden, der erst ab einem bestimmten Zeitpunkt verfügbar ist; dies wird dann indirekt codiert durch den Start-Zeitpunkt der Haupt-Berechnung, und das Einschleifen einer Notification auf das direkt nachfolgende Gate, was dazu führt, daß eine extern empfangene Notification von abgeschlossenen Vorgänger-Berechnungen erst nach diesem Zeitpunkt das Gate öffnen können. Diese interne Freischaltungs-Notification wird direkt hinter dem Ankerpunkt (dem POST) eingehängt, verwendet aber ansonsten die vorhandenen Mechanismen (indirekte Aktivierung über den Dispatch-hook) +

+ +
+
+
+
+
@@ -78080,11 +78141,50 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + + - - + + + + + + + + + + + + + +

+ ....denn die Implementierung des Notification-Dispatch erkennt, wenn eine Notification das Gate öffnet, und dispatched in diesem Fall den Chain sofort zur Ausführung und sperrt dann auch das Gate endgültig; das bedeutet: wenn die Aktivierung über diesen Mechanismus erfolgt, wird ein geplanter re-Trigger niemals zum Zug kommen (sondern dann stets ein bereits gesperrtes Gate vorfinden +

+ +
+ +
+ + + + + + +

+ entscheidendes Kriterium: was ist der Regelfall? +

+ +
+ + + +
+
+
+ + @@ -78125,6 +78225,59 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + + + + + +

+ nur wenn dadruch das Latch ⟼ 0 geht +

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

+ indem die deadline ≔ Time::MIN +

+ +
+
+
+ + + + + + + + + + + + + @@ -78303,6 +78456,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + +
@@ -79452,6 +79609,11 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + +
@@ -79509,8 +79671,24 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + + + + + + +

+ Es ist noch nicht klar, wie die Callbacks von async-IO aufgeschaltet werden +

+ +
+ +
+ + +
@@ -79930,18 +80108,6 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - - - - - - - - - - @@ -79969,11 +80135,40 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -80618,7 +80813,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -80629,6 +80824,19 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + @@ -82730,6 +82938,20 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + +