diff --git a/src/vault/gear/activity-term.hpp b/src/vault/gear/activity-term.hpp index 20130cce4..2f8f9caef 100644 --- a/src/vault/gear/activity-term.hpp +++ b/src/vault/gear/activity-term.hpp @@ -171,12 +171,13 @@ namespace gear { * Term — the prerequisite — by invoking #appendNotificationTo(targetTerm). */ Term& - expectNotification (Activity& notificationSrc) + expectNotification (Activity& notificationSrc, bool unlimitedTime =false) { REQUIRE (notificationSrc.is (Activity::NOTIFY)); setupGate(); gate_->incDependencies(); - notificationSrc.setNotificationTarget (gate_, Time{post_->data_.timeWindow.life}); + Time triggerTimeStart{unlimitedTime? Time::ANYTIME : post_->data_.timeWindow.life}; + notificationSrc.setNotificationTarget (gate_, triggerTimeStart); return *this; } @@ -187,11 +188,11 @@ namespace gear { * been activated and processed up to emitting the inserted `NOTIFY`. */ Term& - appendNotificationTo (Term& targetTerm) + appendNotificationTo (Term& targetTerm, bool unlimitedTime =false) { Activity& success = alloc_.create (Activity::NOTIFY); insert (findTail (callback_? callback_ : invoke_), &success); - targetTerm.expectNotification (success); + targetTerm.expectNotification (success, unlimitedTime); return *this; } diff --git a/src/vault/gear/scheduler.hpp b/src/vault/gear/scheduler.hpp index 0e3d012ac..f43a379ab 100644 --- a/src/vault/gear/scheduler.hpp +++ b/src/vault/gear/scheduler.hpp @@ -205,8 +205,8 @@ namespace gear { /** build Activity chain and hand-over to the Scheduler. */ ScheduleSpec post(); - ScheduleSpec linkToSuccessor (ScheduleSpec&); - ScheduleSpec linkToPredecessor(ScheduleSpec&); + ScheduleSpec linkToSuccessor (ScheduleSpec&, bool unlimitedTime =false); + ScheduleSpec linkToPredecessor(ScheduleSpec&, bool unlimitedTime =false); private: void maybeBuildTerm(); }; @@ -569,20 +569,20 @@ namespace gear { } inline ScheduleSpec - ScheduleSpec::linkToSuccessor (ScheduleSpec& succSpec) + ScheduleSpec::linkToSuccessor (ScheduleSpec& succSpec, bool unlimitedTime) { this->maybeBuildTerm(); succSpec.maybeBuildTerm(); - term_->appendNotificationTo (*succSpec.term_); + term_->appendNotificationTo (*succSpec.term_, unlimitedTime); return move(*this); } inline ScheduleSpec - ScheduleSpec::linkToPredecessor (ScheduleSpec& predSpec) + ScheduleSpec::linkToPredecessor (ScheduleSpec& predSpec, bool unlimitedTime) { predSpec.maybeBuildTerm(); this->maybeBuildTerm(); - predSpec.term_->appendNotificationTo (*term_); + predSpec.term_->appendNotificationTo (*term_, unlimitedTime); return move(*this); } diff --git a/tests/vault/gear/scheduler-stress-test.cpp b/tests/vault/gear/scheduler-stress-test.cpp index 003ea90a4..a67ebda7f 100644 --- a/tests/vault/gear/scheduler-stress-test.cpp +++ b/tests/vault/gear/scheduler-stress-test.cpp @@ -71,6 +71,7 @@ namespace test { * @see SchedulerActivity_test * @see SchedulerInvocation_test * @see SchedulerCommutator_test + * @see stress-test-rig.hpp */ class SchedulerStress_test : public Test { @@ -145,8 +146,11 @@ namespace test { - /** @test TODO build a scheme to adapt the schedule to expected runtime. - * @todo WIP 12/23 🔁 define ⟶ implement + /** @test build a scheme to adapt the schedule to expected runtime. + * - as in many other tests, use the massively forking load pattern + * - demonstrate how TestChainLoad computes an idealised level expense + * - verify how schedule times are derived from this expense sequence + * @todo WIP 12/23 ✔ define ⟶ ✔ implement */ void setup_systematicSchedule() @@ -164,7 +168,6 @@ namespace test { cpuLoad.calibrate(); double micros = cpuLoad.invoke(); -SHOW_EXPR(micros); CHECK (micros < 550); CHECK (micros > 450); @@ -285,7 +288,17 @@ SHOW_EXPR(micros); /** @test TODO determine the breaking point towards scheduler overload - * @todo WIP 1/24 🔁 define ⟶ implement + * - use the integrated StressRig + * - demonstrate how parameters can be tweaked + * - perform a run, leading to a binary search for the breaking point + * @note on my machine, I observe stress factors close below 0.5, due to the fact + * that the ComputationalLoad typically takes 2 times as long in concurrent + * usage compared to its calibration, which is done in a tight loop. This + * is strange and may well be due to some peculiarity of my system. Which + * also implies that this test's behaviour might be difficult to verify, + * other than by qualitative interpretation of the log output on STDOUT. + * @see stress-test-rig.hpp + * @todo WIP 1/24 ✔ define ⟶ ✔ implement */ void search_breaking_point() @@ -303,10 +316,6 @@ SHOW_EXPR(micros); }; auto [stress,delta,time] = StressRig::with().searchBreakingPoint(); - -SHOW_EXPR(stress) -SHOW_EXPR(delta) -SHOW_EXPR(time) CHECK (delta > 2.0); CHECK (0.55 > stress and stress > 0.4); } diff --git a/tests/vault/gear/stress-test-rig.hpp b/tests/vault/gear/stress-test-rig.hpp index f125755cd..72ace65dc 100644 --- a/tests/vault/gear/stress-test-rig.hpp +++ b/tests/vault/gear/stress-test-rig.hpp @@ -161,6 +161,7 @@ namespace test { { testSetup.withLoadTimeBase(CONF::LOAD_BASE) .withBaseExpense (CONF::BASE_EXPENSE) + .withSchedNotify (CONF::SCHED_NOTIFY) .withSchedDepends(CONF::SCHED_DEPENDS) .withAdaptedSchedule(stressFac, CONF::CONCURRENCY); } @@ -181,11 +182,11 @@ namespace test { avgT += runTime[i]; } avgT /= CONF::REPETITIONS; - avgD = fabs (avgT-expT); + avgD = (avgT-expT); // can be < 0 for (uint i=0; i CONF::FAIL_LIMIT); if (fail) ++ pf; @@ -331,6 +332,7 @@ namespace test { usec LOAD_BASE = 500us; usec BASE_EXPENSE = 0us; + bool SCHED_NOTIFY = true; bool SCHED_DEPENDS = false; uint CONCURRENCY = work::Config::getDefaultComputationCapacity(); double EPSILON = 0.01; ///< error bound to abort binary search diff --git a/tests/vault/gear/test-chain-load.hpp b/tests/vault/gear/test-chain-load.hpp index cbb4ac354..e435ddeac 100644 --- a/tests/vault/gear/test-chain-load.hpp +++ b/tests/vault/gear/test-chain-load.hpp @@ -1673,7 +1673,7 @@ namespace test { FrameRate levelSpeed_{1, SCHEDULE_LEVEL_STEP}; FrameRate planSpeed_{1, SCHEDULE_PLAN_STEP}; TimeVar nodeExpense_{SCHEDULE_NODE_STEP}; - double schedNotify_{SCHED_NOTIFY? 1.0:0.0}; + bool schedNotify_{SCHED_NOTIFY}; bool schedDepends_{SCHED_DEPENDS}; uint blockLoadFactor_{2}; size_t chunkSize_{DEFAULT_CHUNKSIZE}; @@ -1713,7 +1713,8 @@ namespace test { { size_t predIdx = chainLoad_.nodeID (pred); size_t succIdx = chainLoad_.nodeID (succ); - schedule_[predIdx].linkToSuccessor (schedule_[succIdx]); + bool unlimitedTime = not schedNotify_; + schedule_[predIdx].linkToSuccessor (schedule_[succIdx], unlimitedTime); } /** continue planning: schedule follow-up planning job */ @@ -1733,7 +1734,7 @@ namespace test { .startTime(jobStartTime (levelDone+1)) .lifeWindow(SAFETY_TIMEOUT) .post() - .linkToPredecessor (schedule_[lastNodeIDX]) + .linkToPredecessor (schedule_[lastNodeIDX], not schedNotify_) ; // Setup wait-dependency on last computation } @@ -1859,9 +1860,9 @@ namespace test { } ScheduleCtx&& - withSchedNotify (double degree) + withSchedNotify (bool doSetTime =true) { - schedNotify_ = degree; + schedNotify_ = doSetTime; return move(*this); } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 33a3390e4..10bb80173 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -107645,8 +107645,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -107733,8 +107733,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -107751,13 +107751,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + +
- - + + @@ -107824,7 +107824,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -107889,35 +107889,26 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + - - + + + - + - + - - - - -

- eigentlich wäre das eine Ja/Nein-Entscheidung, aber da sie über einen Zeit-Parameter gesteuert wird, kann man hier alles zwischen Time::ANYTIME und dem nominellen Zeitpunkt des Folge-Jobs explizit setzen; dieser Parameter hat sich akzidentell aus der Implementierung  ergeben und wird im NOTIFY-Verb gespeichert; das vorliegen dieses Parameters ist es auch, wodurch der eigentliche explizite Trigger für den Folge-Job wegfallen kann. Setzt man hier die nominelle Zeit ein, so wird das NOTIFY tatsächlich erst zu dieser Zeit zugestellt, und das bedeutet, daß auch Dependency-Ketten nach dem nominellen Schedule „getaktet“ sind. Im anderen Extremfall gibt es keine Limitierung und das NOTIFY wird vom Scheduler zur nächstmöglichen Gelegenheit zugestellt. Sofern allerdings die Berechnung ohnehin im Verzug ist, spielt diese Unterscheidung keine Rolle mehr (dann wird nämlich immer sofort getriggert); es könnte aber für zusätzlichen Flexibilitäts-Puffer sorgen, wenn ein Schedule zeitweilig zu dünn besetzt ist, denn erst dadurch könnte der Scheduler sogar vorzeitig fertig werden. -

- -
-
- - + + @@ -107956,8 +107947,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -108006,8 +107997,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -108019,8 +108010,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -108030,13 +108021,40 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

+ + + + + +

+ ...es ist nämlich redundant: wenn man keinen constraint setzen möchte, dann definiert man eben die Start-Zeit des Nachfolgers entsprechend früher. +

+ +
- - + + + + + + + + + + + + + + + + + + + + + - - @@ -110721,6 +110739,21 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + +

+ ohne Limitierung der NOTIFY-Zeit ist die Performance minimal besser +

+ +
+ + + + + +