From a21057bdf2316e05b895cb8091cd27e2a1a192e3 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 22 Oct 2023 23:25:35 +0200 Subject: [PATCH] Scheduler: control structure for the worker-functor --- src/vault/gear/load-controller.hpp | 17 ++- src/vault/gear/scheduler.hpp | 87 ++++++++++-- .../vault/gear/scheduler-commutator-test.cpp | 6 +- wiki/thinkPad.ichthyo.mm | 130 +++++++++++------- 4 files changed, 170 insertions(+), 70 deletions(-) diff --git a/src/vault/gear/load-controller.hpp b/src/vault/gear/load-controller.hpp index a0fd936df..e515f4393 100644 --- a/src/vault/gear/load-controller.hpp +++ b/src/vault/gear/load-controller.hpp @@ -96,7 +96,9 @@ namespace gear { } enum - Capacity {SPINTIME ///< imminent activities + Capacity {DISPATCH ///< sent to work + ,TENDNEXT ///< reserved for next task + ,SPINTIME ///< awaiting imminent activities ,NEARTIME ///< capacity for active processing required ,WORKTIME ///< typical stable work task rhythm expected ,IDLETIME ///< time to go to sleep @@ -114,7 +116,18 @@ namespace gear { { UNIMPLEMENTED ("establish a randomised targeted delay time"); } - + + Capacity + incomingCapacity (Time head, Time now) + { + UNIMPLEMENTED ("decide how to use incoming free work capacity"); + } + + Capacity + outgoingCapacity (Time head, Time now) + { + UNIMPLEMENTED ("decide how to use outgoing free work capacity"); + } }; diff --git a/src/vault/gear/scheduler.hpp b/src/vault/gear/scheduler.hpp index ce847368c..2c4cdb336 100644 --- a/src/vault/gear/scheduler.hpp +++ b/src/vault/gear/scheduler.hpp @@ -55,6 +55,7 @@ //#include "lib/util.hpp" //#include +#include namespace vault{ @@ -62,13 +63,14 @@ namespace gear { // using util::isnil; // using std::string; + using std::move; - namespace { // Scheduler default config - - const auto IDLE_WAIT = 20ms; ///< sleep-recheck cycle for workers deemed _idle_ - const size_t DISMISS_CYCLES = 100; ///< number of wait cycles before an idle worker terminates completely - Offset POLL_WAIT_DELAY{FSecs(1,1000)}; ///< delay until re-evaluating a condition previously found unsatisfied - } + namespace { // Scheduler default config + + const auto IDLE_WAIT = 20ms; ///< sleep-recheck cycle for workers deemed _idle_ + const size_t DISMISS_CYCLES = 100; ///< number of wait cycles before an idle worker terminates completely + Offset POLL_WAIT_DELAY{FSecs(1,1000)}; ///< delay until re-evaluating a condition previously found unsatisfied + } @@ -163,13 +165,11 @@ namespace gear { /** - * + * The worker-Functor: called by the active Workers from the + * \ref WorkForce to pull / perform the actual render Activities. */ - activity::Proc - getWork() - { - UNIMPLEMENTED("the Worker-Funkction"); - } + activity::Proc getWork(); + private: void @@ -184,12 +184,37 @@ namespace gear { * @return how to proceed further with this worker */ activity::Proc - scatteredDelay() + scatteredDelay (LoadController::Capacity capacity) { UNIMPLEMENTED("scattered short-term delay"); } + /** + * monad-like step sequence: perform sequence of steps, + * as long as the result remains activity::PASS + */ + struct WorkerInstruction + { + activity::Proc lastResult = activity::PASS; + + /*** exposes the latest verdict as overall result */ + operator activity::Proc() + { + return activity::SKIP == lastResult? activity::PASS + : lastResult; + } + + template + WorkerInstruction + performStep (FUN step) + { + if (activity::PASS == lastResult) + lastResult = step(); + return move(*this); + } + }; + /** @internal expose a binding for Activity execution */ class ExecutionCtx; }; @@ -201,7 +226,7 @@ namespace gear { * some aspects of Activity _activation_ however require external functionality, * which — for the purpose of language definition — was abstracted as _Execution-context._ * The implementation of these binding functions fills in relevant external effects and - * is in fact supplied by the implementation internals of the scheduler itself. + * is in fact supplied by the implementation internals of the scheduler itself. */ class Scheduler::ExecutionCtx : private Scheduler @@ -260,5 +285,39 @@ namespace gear { + /** + * @remarks this function is invoked from within the worker thread(s) and will + * - decide if and how the capacity of this worker shall be used right now + * - possibly go into a short targeted wait state to redirect capacity at a better time point + * - and most notably jump into the dispatch of the render Activities, to calculate media data. + * @return an instruction for the work::Worker how to proceed next: + * - activity::PROC causes the worker to poll again immediately + * - activity::SLEEP induces a sleep state + * - activity::HALT terminates the worker + */ + inline activity::Proc + Scheduler::getWork() + { + ExecutionCtx& ctx = ExecutionCtx::from(*this); + Time now = ctx.getSchedTime(); + Time head = layer1_.headTime(); + + return WorkerInstruction{} + .performStep([&]{ return scatteredDelay( + loadControl_.incomingCapacity (head,now)); + }) + .performStep([&]{ + Activity* act = layer2_.findWork(layer1_,now); + return layer2_.postDispatch (act, now, ctx, layer1_); + }) + .performStep([&]{ return scatteredDelay( + loadControl_.outgoingCapacity (head,now)); + }) + ; + } + + + + }} // namespace vault::gear #endif /*SRC_VAULT_GEAR_SCHEDULER_H_*/ diff --git a/tests/vault/gear/scheduler-commutator-test.cpp b/tests/vault/gear/scheduler-commutator-test.cpp index c90e5c0c7..2c47148c4 100644 --- a/tests/vault/gear/scheduler-commutator-test.cpp +++ b/tests/vault/gear/scheduler-commutator-test.cpp @@ -436,7 +436,7 @@ namespace test { */ void integratedWorkCycle() - { // ===================================================================== setup a rigged Job + { // ·==================================================================== setup a rigged Job Time nominal{7,7}; Time start{0,1}; Time dead{0,10}; @@ -455,7 +455,7 @@ namespace test { detector.watchGate (anchor.next, "theGate"); - // ===================================================================== setup test subject + // ·=================================================================== setup test subject SchedulerInvocation queue; SchedulerCommutator sched; @@ -477,7 +477,7 @@ namespace test { }); - // ===================================================================== actual test sequence + // ·=================================================================== actual test sequence // Add the Activity-Term to be scheduled for planned start-Time sched.postDispatch (&anchor, start, detector.executionCtx, queue); CHECK (detector.ensureNoInvocation("testJob")); diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 4299286ff..092e06f64 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -81992,8 +81992,59 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ kann um fünf Ecken gehen; auch dispatchNotify landed irgend wann bei postDispatch +

+ +
+
+ + + + + + + + + + + + + + + + + + + @@ -82138,16 +82189,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

um das System nicht unnötig zu belasten

- -
+
@@ -82170,44 +82218,35 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

Das bedeutet: bei nur vereinzelt vorhandenen Tasks dürfen diese nicht zufällig verteilt werden (sonst bleiben alle Worker am Leben). Vielmehr muß bevorzugt derjenige den nächsten Task bekommen, der ohnehin  grade gearbeitet hat

- -
+
- - - +

Idler: findet direkt beim Eintritt in pullWork() nichts zu tun vor

- -
+
- - - +

Worker: findet nach einem Work-Zyklus nichts zu tun vor

- -
+
@@ -82234,30 +82273,24 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

...weil der water-level ein internes Implementierungsdetail von Layer-1 ist, und der eigentliche Dispatch mit "now" erfolgt. Möglicherweise hab' ich mich da verrant — andererseits wollte ich ganz explizit nicht überall und in jeder Activity auch noch eine Startzeit mitschleppen, sondern habe mich darauf verlegt, diese Information kontextuell zu handhaben

- -
+
- - - +

...und ich hatte kürzlich noch solche Zweifel ob das Design komplett entgleist, habe mich dann aber entschieden, locker zu lassen

- -
+
@@ -82278,16 +82311,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

damit im Schnitt jedes 1/Nte - Warte-Intervall sich ein Worker meldet

- -
+ @@ -82295,16 +82325,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

denn: innerhalb der zeitnah-Phase wird jeder verfügbare worker per gezieltem Schlaf auf die nächste headTime gesetzt, und damit ist er bis dahin geblockt. Also sollte es extrem unwahrscheinlich sein, daß inzwischen so kurzfristig noch was dazwischen geplant wird

- -
+
@@ -82407,16 +82434,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

man schickt einen Worker in »scattered delay«

- -
+ @@ -82426,6 +82450,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + +
@@ -89989,16 +90020,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

⟹ bedeutet für jedes Ereignis auch eine Kategorisierung zu erfassen, so daß dann in der Auswertung später proportionale Anteile beobachtbar werden

- -
+