From bf41474004064b9dc7603599be8f2bead46cdca9 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 15 Nov 2024 02:20:36 +0100 Subject: [PATCH] Library: investigate Scheduler test failures ...which turn out not to be due to the PRNG changes * the SchedulerCommutator_test was inadvertently broken 2024-04-10 * SchedulerStress_test simply runs for 4min, which is not tolerated by our Testsuite setup see also: 5b62438eb --- .../vault/gear/scheduler-commutator-test.cpp | 76 ++---- wiki/thinkPad.ichthyo.mm | 257 +++++++++++++++--- 2 files changed, 230 insertions(+), 103 deletions(-) diff --git a/tests/vault/gear/scheduler-commutator-test.cpp b/tests/vault/gear/scheduler-commutator-test.cpp index c39860d35..403ea2ad2 100644 --- a/tests/vault/gear/scheduler-commutator-test.cpp +++ b/tests/vault/gear/scheduler-commutator-test.cpp @@ -110,7 +110,7 @@ namespace test { */ void demonstrateSimpleUsage() - { + { MARK_TEST_FUN SchedulerInvocation queue; SchedulerCommutator sched; Activity activity; @@ -141,7 +141,8 @@ namespace test { */ void verify_GroomingToken() - { + { MARK_TEST_FUN + SchedulerCommutator sched; auto myself = std::this_thread::get_id(); @@ -173,7 +174,8 @@ namespace test { */ void verify_GroomingGuard() - { + { MARK_TEST_FUN + SchedulerCommutator sched; // Case-1: if a thread already holds the token.... @@ -206,7 +208,8 @@ namespace test { */ void torture_GroomingToken() - { + { MARK_TEST_FUN + SchedulerCommutator sched; size_t checkSum{0}; @@ -281,61 +284,12 @@ namespace test { - - -// /** @test verify the logic to decide where and when to perform -// * the dispatch of a Scheduler Activity chain. -// */ -// void -// verify_DispatchDecision() -// { -// SchedulerCommutator sched; -// ___ensureGroomingTokenReleased(sched); -// -// Time t1{10,0}; -// Time t2{20,0}; -// Time t3{30,0}; -// Time now{t2}; -// -// auto myself = std::this_thread::get_id(); -// CHECK (sched.decideDispatchNow (t1, now)); // time is before now => good to execute -// CHECK (sched.holdsGroomingToken (myself)); // Side-Effect: acquired the Grooming-Token -// -// CHECK (sched.decideDispatchNow (t1, now)); // also works if Grooming-Token is already acquired -// CHECK (sched.holdsGroomingToken (myself)); -// -// CHECK (sched.decideDispatchNow (t2, now)); // Boundary case time == now => good to execute -// CHECK (sched.holdsGroomingToken (myself)); -// -// CHECK (not sched.decideDispatchNow (t3, now)); // Task in the future shall not be dispatched now -// CHECK (sched.holdsGroomingToken (myself)); // ...and this case has no impact on the Grooming-Token -// sched.dropGroomingToken(); -// -// CHECK (not sched.decideDispatchNow (t3, now)); -// CHECK (not sched.holdsGroomingToken (myself)); -// -// blockGroomingToken(sched); -// CHECK (not sched.acquireGoomingToken()); -// -// CHECK (not sched.decideDispatchNow (t1, now)); // unable to acquire => can not decide positively -// CHECK (not sched.holdsGroomingToken (myself)); -// -// CHECK (not sched.decideDispatchNow (t2, now)); -// CHECK (not sched.holdsGroomingToken (myself)); -// -// unblockGroomingToken(); -// -// CHECK (sched.decideDispatchNow (t2, now)); -// CHECK (sched.holdsGroomingToken (myself)); -// } - - - /** @test verify logic of queue updates and work prioritisation. */ void verify_findWork() - { + { MARK_TEST_FUN + SchedulerInvocation queue; SchedulerCommutator sched; @@ -399,7 +353,8 @@ namespace test { */ void verify_Significance() - { + { MARK_TEST_FUN + SchedulerInvocation queue; SchedulerCommutator sched; @@ -407,7 +362,7 @@ namespace test { Time t2{20,0}; Activity a2{2u,2u}; Time t3{30,0}; Activity a3{3u,3u}; Time t4{40,0}; Activity a4{4u,4u}; - // start,deadline, manif.ID, isCompulsory + // start,deadline, manif.ID, isCompulsory queue.instruct ({a1, t1, t4, ManifestationID{5}}); queue.instruct ({a2, t2, t2}); queue.instruct ({a3, t3, t3, ManifestationID{23}, true}); @@ -473,7 +428,8 @@ namespace test { */ void verify_postChain() - { + { MARK_TEST_FUN + // rigged execution environment to detect activations-------------- ActivityDetector detector; Activity& activity = detector.buildActivationProbe ("testActivity"); @@ -552,7 +508,8 @@ namespace test { */ void verify_dispatch() - { + { MARK_TEST_FUN + // rigged execution environment to detect activations-------------- ActivityDetector detector; Activity& activity = detector.buildActivationProbe ("testActivity"); @@ -621,6 +578,7 @@ namespace test { void integratedWorkCycle() { // ยท==================================================================== setup a rigged Job + MARK_TEST_FUN Time nominal{7,7}; Time start{0,1}; Time dead{0,10}; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 09731d773..d76b9e982 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -16716,9 +16716,7 @@ - - - +

...mit der Ausnahme des Automatismus, @@ -17252,9 +17250,7 @@ - - - +

...stammt im Kern noch von Joel Holdsworth < 2012 @@ -17773,9 +17769,7 @@ - - - +

...das heißt, der Menü-Button ist dann nur pro forma da, und bietet eine Fläche, auf der man zuverlässig dieses Menü trifft; letzteres ist relevant für eine Anzeige in Listen und Bins, bei der ansonsten die Ausdehnung des Widgets stark reduziert ist. Ein Klick auf das Name-Label hat eine andere Funktion (nämlich Editieren des Namens). Ein Weiterer Aspekt ist die Drag-Geste: es ist denkbar, diese auf dem Menü-Button nicht zu starten (wobei allerdings zu bedenken ist, das Ziehen auch noch an weitere Voraussetzungen zu knüpfen, z.B. einen Modifiere, oder den Umstand, daß das Objekt auch selektiert ist) @@ -18681,9 +18675,7 @@ - - - +

Die meisten IOS-Stream-Manipulatoren sind »sticky«, d.h. sie verändern per Seiteneffekt den Zustand im jeweiligen ostream. Ich hatte eine Methode zum Ausgeben einer Addresse, eingebaut im to-String-Framework, und diese hat std::output auf Hex-Ausgabe umgeschaltet. Erstaunlich daß ich das jahrelang nicht gemerkt habe! @@ -19192,9 +19184,7 @@ - - - +

weil in dem Fall jedesmal das Label wieder ausgeblendet wird, und dazu insgesamt drei mal die requested_width ermittelt werden muß @@ -20323,9 +20313,7 @@ - - - +

per default greift sich ein Button ja den links-Klick, und das soll auch so sein! @@ -43526,9 +43514,7 @@ - - - +

Im Regelfall möchte ich die präzise Integer-Bruch-Arithmetik, aber ich möchte die Grenzfälle nahtlos mit integrieren, und nehme für diese Grenzfälle absolut betrachtet erehbliche Fehler in Kauf. @@ -46004,9 +45990,7 @@ - - - +

das heißt. @@ -46490,9 +46474,7 @@ - - - +

presentation @@ -46730,9 +46712,7 @@ - - - +

gemeint, eine ENUM von verschiedenen Graden der Aufgeklappt-heit @@ -46874,9 +46854,7 @@ - - - +

...denn dort fehlt noch die konkrete Implementierung, @@ -47221,9 +47199,7 @@ - - - +

der schwierigste Teil, das Mutieren von Attributen, @@ -57531,8 +57507,7 @@ ...hatte vor einiger Zeit aufgeräumt und einen eigenen #include "lib/integral.hpp" geschaffen. Dadurch ist downstream der #include für time-value.hpp rausgefallen, und damit fehlte die String-conversion für Rationals

- -
+
@@ -57542,8 +57517,7 @@ ...dazu nochmal über die ganze Problematik nachgedacht und entsprechende Kommentare in #1258 und #1261 hinterlassen

- -
+
@@ -57562,6 +57536,131 @@

+ + + + + + +

+ ommit 5b62438eb404e20762a9f2ff6109c7cf54022064 +

+

+ Author: Ichthyostega <prg@ichthyostega.de> 2024-04-10 20:04:53 +

+

+ +

+

+ Scheduler-test: investigate logic problem related to the »Tick« deadline +

+

+ +

+

+ In the end, I decided that it ''is to early to decide anything'' in this respect... +

+

+ +

+

+ The actual situation encountered is a **Catch-22**: +

+

+  * in its current form, the »Tick« handler detects compulsory jobs beyond deadline +

+

+  * since such a Job ''must not be touched anymore,'' there is no way scheduling can proceed +

+

+  * so this would constitute a ''Scheduler Emergency'' +

+

+ All fine — just the »Tick« handler ''itself is a compulsory job'' — and being a job, it can well be driven beyond its deadline. In fact this situation was encountered as part of stress testing. +

+

+ +

+

+ Several mitigations or real solutions are conceivable, but in the end, +

+

+ too little is known yet regarding the integration of the scheduler within the Engine +

+

+ Thus I'll marked the problematic location and opened #1362 +

+ + +
+ +
+ + + + +

+ ...die definitiv auftreten kann, und die auf einem höheren (derzeit nicht existenten) Level der Architektur behandelt werden muß, als eine Scheduler-Emergency. +

+ + +
+ +
+ + + + +

+ ...bzw dorthin gezogen ist durch den Umbau der Scheduler-Struktur, welche zwar spät erfolgte, als Resultat der Stress-tests, aber insgesamt eine signifikante Verbessung des Codes darstellt. Leider hat dieser Umbau nun dazu geführt, daß Layer-2 diverse »Hooks« auf Service-Level ansprechen muß, und das ist wiederum ein HInweis, daß die Code-Anordnung nicht optimal ist +

+ + +
+ + + + + +
    +
  • + der Trigger würde in Scheduler::doWork() erkannt werden, was allerdings aus den Workern aufgerufen wird. +
  • +
  • + der »Tick« dutyCycle() würde aber logischerweise die gleiche Situation auch erkennen +
  • +
  • + nur das Problem ist: dieser »Tick« könnte unerreichbar sein, denn er liegt selber in einem Compulsory-Job, und die Queue könnte schon vorher geblockt sein durch einen anderen Compulsory-Job +
  • +
+ + +
+ +
+
+ + + + +

+ siehe auch Kommentar im Ticket #1362 Scheduler Emergency +

+ + +
+ + + +

+ https://issues.lumiera.org/ticket/1362#comment:1 +

+ + +
+ +
+
@@ -57587,6 +57686,66 @@

+ + + + + + + + +

+ scheduler-stress-test.cpp:415: watch_expenseFunction: (isLimited (3, socket, 9 )) +

+

+ Hier beobachten wir ein lineares Model der Beladung; die lineare Regression hat einen konstanten Sockel(9ms) knapp oberhalb der bisher tolerierten Overheads für start-up und spin-down (+Test-setup); erwartet werden ~6ms +

+ + +
+
+
+ + + + + +

+ scheduler-stress-test.cpp:270: setup_systematicSchedule: (fabs (runTime-expected) < 5000) +

+

+ Hier wird zunächst »auf dem Trockenen« demonstriert, wie aus der Kapazitätsrechnung eine zu erwartende effektive concurrent-run-time abgeleitet wird. Am Ende wird ein tatsächlicher Scheduler-Lauf mit diesem (relativ locker dimensionierten) Schedule gestartet  — und hier überschreiten wir den Timeout von 5 Sekunden, was bedeutet, daß das Schedule komplett aus dem Ruder gelaufen sein muß (möglicherweise wurden sogar Job-Deadlines überfahren, in welchem Fall das Scheduler unvollständig hängen bleibt) +

+ + +
+
+
+
+ + + + +

+ wenn der Test durläuft sind die beobachteten Kenndaten des Schedulers wie erwartet +

+ + +
+ + + +

+ also die Concurrency ist wirklich gut, die back-to-back-Zeit weicht nur 10ms vom theoretischen Wert ab +

+ + +
+
+
+ + +
@@ -57596,8 +57755,20 @@ CHECK: work-force-test.cpp:425: thread_1: verify_scalePool: (2*fullCnt == uniqueCnt)

+
+ + + + +

+ Dieser Test skaliert den Worker-Pool, wartet dann jeweils eine (fest konfigurierte) Zeitspanne, um anschließend den Status zu prüfen — ein bekanntermaßen fragiles Schema, obwohl ich inzwischen Timings ausgeknobelt habe, die auf meiner Maschine hinreichend sicher sind. Für zuverlässiges Testen müßte man auf den Status der WorkForce eigens warten, und dafür möchte ich jedoch kein Core-API bereitstellen, denn ich möchte niemanden ermutigen, in Richtung einer »pinball-machine« zu gehen.... +

+
+ + +
@@ -57632,8 +57803,7 @@ ich hab damals auf theoretischem Weg die Gefahr duplikater Einträge entdeckt...

- - + @@ -57651,8 +57821,7 @@ ...und aber eine dieser Infos einfach ignoriert wird, nämlich die konkrete Info, die der im BuffHandle vom Client eingebettet ist. Daher habe ich für die einzige Implementierung, den TrackingHeapBlockProvider beide Infos in einer Assertion verglichen. Und genau dieser Check scheitert jetzt (noch nicht klar warum)

- -
+