diff --git a/src/vault/gear/scheduler.hpp b/src/vault/gear/scheduler.hpp index ad702dccc..d56d9f955 100644 --- a/src/vault/gear/scheduler.hpp +++ b/src/vault/gear/scheduler.hpp @@ -319,6 +319,7 @@ namespace gear { private: void handleDutyCycle (Time now); void handleWorkerTermination (bool isFailure); + void maybeScaleWorkForce(); void triggerEmergency(); @@ -500,6 +501,7 @@ namespace gear { inline void Scheduler::postChain (ActivationEvent actEvent) { + maybeScaleWorkForce(); ExecutionCtx ctx{*this, actEvent}; layer2_.postDispatch (actEvent, ctx, layer1_); } @@ -673,6 +675,23 @@ namespace gear { loadControl_.markWorkerExit(); } + /** + * Hook invoked whenever a new task is passed in. + * Ensures that the Scheduler is in running state and + * possibly steps up the WorkForce if not yet running at + * full computation power. + * @note the capacity scales down automatically when some + * workers fall idle for extended time (> 2sec). + */ + inline void + Scheduler::maybeScaleWorkForce() + { + if (empty()) + ignite(); + else + workForce_.incScale(); + } + /** * Trip the emergency brake and unwind processing while retaining all state. */ diff --git a/tests/vault/gear/scheduler-service-test.cpp b/tests/vault/gear/scheduler-service-test.cpp index fa78239e5..a7b88867d 100644 --- a/tests/vault/gear/scheduler-service-test.cpp +++ b/tests/vault/gear/scheduler-service-test.cpp @@ -80,10 +80,10 @@ namespace test { virtual void run (Arg) { -// simpleUsage(); -// verify_StartStop(); -// verify_LoadFactor(); -// invokeWorkFunction(); + simpleUsage(); + verify_StartStop(); + verify_LoadFactor(); + invokeWorkFunction(); scheduleRenderJob(); walkingDeadline(); } @@ -101,6 +101,21 @@ namespace test { } + /** + * @internal helper to inject a new task into the Scheduler, + * without also activating WorkForce and load control. + * @remark this class is declared friend by the Scheduler to grant + * this kind of »implementation backdoor« access; the function + * defined there does essentially the same than Scheduler::postChain() + */ + void + postNewTask (Scheduler& scheduler, Activity& chain, Time start) + { + ActivationEvent actEvent{chain, start}; + Scheduler::ExecutionCtx ctx{scheduler, actEvent}; + scheduler.layer2_.postDispatch (actEvent, ctx, scheduler.layer1_); + } + /** @test get the scheduler into running state * @todo WIP 10/23 ✔ define ⟶ ✔ implement @@ -114,7 +129,7 @@ namespace test { CHECK (isnil (scheduler)); Activity dummy{Activity::FEED}; - auto postIt = [&] { scheduler.postChain (ActivationEvent{dummy, RealClock::now()+t200us}); }; + auto postIt = [&] { postNewTask (scheduler, dummy, RealClock::now()+t200us); }; scheduler.ignite(); CHECK (isnil (scheduler)); // no start without any post() @@ -169,7 +184,7 @@ namespace test { auto createLoad = [&](Offset start, uint cnt) { // use internal API (this test is declared as friend) for (uint i=0; i - + - - - - - + + + + + + + + + + + + + + + + + + - - - @@ -82694,21 +82704,18 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - - - +

....also kein Locking etc; allerdings greift der LoadController jetzt per Lambda darauf zu.

- -
+
@@ -82948,6 +82955,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

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

...im Lastbetrieb möchte man das eigentlich auch nicht: ein ankommender Thread soll gemäß aktueller Situation klassifiziert werden, aber nicht erst mal um das Grooming-Token konkurrieren

- -
+
@@ -83005,19 +83010,17 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - - - +

....und das würde in dem Fall das Problem durch den ersten »Tick« nebenbei beheben — aber nicht, falls der Scheduler bereits läuft und leer gefallen ist

- -
- + + +
@@ -84276,22 +84279,19 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - - - +

daher muß für einen neuen Job ein step up erfolgen

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

Aus Sicht des Testaufbaues wäre es sehr wünschenswert. Aber da das Scheduler-API high-Level ist, sehe ich keine einfache Möglichkeit, für einen Test dazwischen zu gehen. Ein Mocking / Austauschen des Scheduler wäre hier nicht zielführend (weil es genau auf die Interaktion mit der integrierten Scheduler-Implementierung ankommt).