Scheduler-test: continue investigation - combine base expense with stress factor
After an extended break due to "real life issues".... Pick up the investigation, with the goal to ascertain a valid definition and understanding of all test parameters. A first step is to establish a baseline ''without using a computational load''; this might be some kind of base overhead of the scheduler. However -- the way the test scaffolding was built, it is difficult to create a feedback loop for the statistical test setup with binary search, since it is not really clear how the single control parameter of the test algorithm, the so called "stress factor", shall be interpreted and how it can be combined with a base load. An extended series of tests, while watching the observed value patterns qualitatively, seems to corroborate the former results, indicating that the base expense in my test setup (using a debug build) is at ~200µs / Node / core. Yet the difficulty to interpret this result and arrive at a logical and generic model prevents me from translating this into a measurement scheme, which can be executed independently from a specific test setup and hardware
This commit is contained in:
parent
0aa1edf07c
commit
602b7dbe3a
6 changed files with 132 additions and 20 deletions
|
|
@ -981,16 +981,16 @@ namespace lib {
|
|||
* already been exhausted. The aggregate is default-initialised at start of each group
|
||||
* and then the computation functor \a FAGG is invoked for each consecutive element marked
|
||||
* with the same _grouping value_ — and this grouping value itself is obtained by invoking
|
||||
* the functor \a FGRP on each source value. No capturing or even reordering of the source
|
||||
* elements takes place, rather groups are formed based on the changes of the grouping value
|
||||
* over the source iterator's result sequence.
|
||||
* the functor \a FGRP on each source value. All computation are performed on-the-fly. No
|
||||
* capturing or reordering of the source elements takes place, rather groups are formed
|
||||
* based on the changes of the grouping value over the source iterator's result sequence.
|
||||
* @tparam AGG data type to collect the aggregate; must be default constructible and assignable
|
||||
* @tparam GRP value type to indicate a group
|
||||
* @note while `groupFun` is adapted, the `aggFun` is _not adapted_ to the source iterator,
|
||||
* but expected always to take the _value type_ of the preceding iterator, i.e. `*srcIter`.
|
||||
* This limitation was deemed acceptable (adapting a function with several arguments would
|
||||
* require quite some nasty technicalities). The first argument of this `aggFun` refers
|
||||
* to the accumulator by value, and thereby also implititly defines the aggregate result type.
|
||||
* to the accumulator by value, and thereby also implicitly defines the aggregate result type.
|
||||
*/
|
||||
template<class SRC, typename AGG, class GRP>
|
||||
class GroupAggregator
|
||||
|
|
|
|||
|
|
@ -541,16 +541,16 @@ namespace time {
|
|||
: Duration::NIL;
|
||||
}
|
||||
|
||||
template<typename INT>
|
||||
template<typename NUM>
|
||||
inline Offset
|
||||
operator* (INT factor, Duration const& dur)
|
||||
operator* (NUM factor, Duration const& dur)
|
||||
{
|
||||
return factor * Offset(dur);
|
||||
}
|
||||
|
||||
template<typename INT>
|
||||
template<typename NUM>
|
||||
inline Offset
|
||||
operator* (Duration const& dur, INT factor)
|
||||
operator* (Duration const& dur, NUM factor)
|
||||
{
|
||||
return factor*dur;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ namespace test {
|
|||
investigateWorkProcessing()
|
||||
{
|
||||
MARK_TEST_FUN
|
||||
TestChainLoad<8> testLoad{64};
|
||||
TestChainLoad<8> testLoad{256};
|
||||
testLoad.seedingRule(testLoad.rule().probability(0.6).minVal(2))
|
||||
.pruningRule(testLoad.rule().probability(0.44))
|
||||
.setSeed(55)
|
||||
|
|
@ -369,7 +369,11 @@ SHOW_EXPR(loadMicros)
|
|||
{
|
||||
usec LOAD_BASE = 500us;
|
||||
usec BASE_EXPENSE = 200us;
|
||||
double UPPER_STRESS = 8;
|
||||
double UPPER_STRESS = 12;
|
||||
//
|
||||
double FAIL_LIMIT = 0.7;
|
||||
double TRIGGER_SDEV = 0.25;
|
||||
double TRIGGER_DELTA = 0.5;
|
||||
// uint CONCURRENCY = 4;
|
||||
// bool SCHED_DEPENDS = true;
|
||||
bool showRuns = true;
|
||||
|
|
@ -377,7 +381,7 @@ SHOW_EXPR(loadMicros)
|
|||
auto
|
||||
testLoad()
|
||||
{
|
||||
TestChainLoad<8> testLoad{64};
|
||||
TestChainLoad<8> testLoad{256};
|
||||
testLoad.seedingRule(testLoad.rule().probability(0.6).minVal(2))
|
||||
.pruningRule(testLoad.rule().probability(0.44))
|
||||
.setSeed(55);
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@ namespace test {
|
|||
double FAIL_LIMIT = 2.0; ///< delta-limit when to count a run as failure
|
||||
double TRIGGER_FAIL = 0.55; ///< %-fact: criterion-1 failures above this rate
|
||||
double TRIGGER_SDEV = FAIL_LIMIT; ///< in ms : criterion-2 standard derivation
|
||||
double TRIGGER_DELTA = 2*FAIL_LIMIT; ///< in ms : criterion-3 delta above this limit
|
||||
double TRIGGER_DELTA = 2*FAIL_LIMIT; ///< in ms : criterion-3 average delta above this limit
|
||||
bool showRuns = false; ///< print a line for each individual run
|
||||
bool showStep = true; ///< print a line for each binary search step
|
||||
bool showRes = true; ///< print result data
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ namespace test {
|
|||
const bool SCHED_NOTIFY = true; ///< explicitly set notify dispatch time to the dependency's start time.
|
||||
|
||||
inline uint
|
||||
defaultConcurr()
|
||||
defaultConcurrency()
|
||||
{
|
||||
return work::Config::getDefaultComputationCapacity();
|
||||
}
|
||||
|
|
@ -1675,6 +1675,7 @@ namespace test {
|
|||
FrameRate levelSpeed_{1, SCHEDULE_LEVEL_STEP};
|
||||
FrameRate planSpeed_{1, SCHEDULE_PLAN_STEP};
|
||||
TimeVar nodeExpense_{SCHEDULE_NODE_STEP};
|
||||
double stressFact_{1.0};
|
||||
bool schedNotify_{SCHED_NOTIFY};
|
||||
bool schedDepends_{SCHED_DEPENDS};
|
||||
uint blockLoadFactor_{2};
|
||||
|
|
@ -1806,7 +1807,7 @@ namespace test {
|
|||
getExpectedEndTime()
|
||||
{
|
||||
return _raw(startTimes_.back() - startTimes_.front()
|
||||
+ Duration{nodeExpense_}*chainLoad_.size());
|
||||
+ Duration{nodeExpense_}*(chainLoad_.size()/stressFact_));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1881,8 +1882,8 @@ namespace test {
|
|||
withAdaptedSchedule (double stressFac =1.0, uint concurrency=0)
|
||||
{
|
||||
if (not concurrency) // use hardware concurrency (#cores) by default
|
||||
concurrency = defaultConcurr();
|
||||
ENSURE (isLimited (1u, concurrency, 3*defaultConcurr()));
|
||||
concurrency = defaultConcurrency();
|
||||
ENSURE (isLimited (1u, concurrency, 3*defaultConcurrency()));
|
||||
withLevelDuration (compuLoad_->timeBase);
|
||||
fillAdaptedSchedule (stressFac, concurrency);
|
||||
return move(*this);
|
||||
|
|
@ -2024,6 +2025,7 @@ namespace test {
|
|||
fillDefaultSchedule()
|
||||
{
|
||||
size_t numPoints = chainLoad_.topLevel()+2;
|
||||
stressFact_ = 1.0;
|
||||
startTimes_.clear();
|
||||
startTimes_.reserve (numPoints);
|
||||
for (size_t level=0; level<numPoints; ++level)
|
||||
|
|
@ -2034,12 +2036,13 @@ namespace test {
|
|||
fillAdaptedSchedule (double stressFact, uint concurrency)
|
||||
{
|
||||
REQUIRE (stressFact > 0);
|
||||
stressFact_ = stressFact;
|
||||
size_t numPoints = chainLoad_.topLevel()+2;
|
||||
startTimes_.clear();
|
||||
startTimes_.reserve (numPoints);
|
||||
startTimes_.push_back (Time::ZERO);
|
||||
chainLoad_.levelScheduleSequence (concurrency)
|
||||
.transform([&](double scheduleFact){ return (scheduleFact/stressFact) * Offset{1,levelSpeed_};})
|
||||
.transform([&](double scheduleFact){ return (scheduleFact/stressFact_) * Offset{1,levelSpeed_};})
|
||||
.effuse(startTimes_);
|
||||
}
|
||||
|
||||
|
|
@ -2048,7 +2051,7 @@ namespace test {
|
|||
{
|
||||
ENSURE (level < startTimes_.size());
|
||||
return startTimes_[level]
|
||||
+ nodeExpense_ * nodeIDX;
|
||||
+ nodeExpense_ * (nodeIDX/stressFact_);
|
||||
}
|
||||
|
||||
auto
|
||||
|
|
|
|||
|
|
@ -110893,7 +110893,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="pencil"/>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1704915326966" ID="ID_117301056" MODIFIED="1704915346470" TEXT="8 Kerne gleichmäßige Last 500µs">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1705011582353" ID="ID_166772872" MODIFIED="1705011589953" TEXT="verwende erst mal Graph-3"/>
|
||||
<node CREATED="1705011582353" ID="ID_166772872" MODIFIED="1705011589953" TEXT="verwende erst mal Graph-3">
|
||||
<node CREATED="1707608885510" ID="ID_1295414407" MODIFIED="1707608916339" TEXT="Begründung: schneller ramp-up auf maximale Parallelität (8)"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1704940787856" FOLDED="true" ID="ID_548135052" MODIFIED="1705010869404" TEXT="SEGFAULT">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1704990398092" ID="ID_80295046" MODIFIED="1704990404404" TEXT="Beobachtungen">
|
||||
|
|
@ -110995,9 +110997,112 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<linktarget COLOR="#3a84b6" DESTINATION="ID_1350365350" ENDARROW="Default" ENDINCLINATION="-192;14;" ID="Arrow_ID_980960219" SOURCE="ID_909211409" STARTARROW="None" STARTINCLINATION="118;-27;"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1705011154754" ID="ID_791359995" MODIFIED="1705011274983" TEXT="ohne Last : ∅Δ= 1.5±0.84ms">
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1707609859180" ID="ID_1719205806" MODIFIED="1707609894793" TEXT="Problem: binäre Suche greift nicht">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1707609897512" ID="ID_72695158" MODIFIED="1707610206793" TEXT="zunächst einmal: sie kann gar nicht greifen ohne Last oder Basis-Aufwand">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...das ist eine inhärente Limitierung, die ich jedoch als Grenzfall und damit nicht relevant betrachte; zum einen sind dann meistens die Laufzeiten so kurz, daß die statistischen Triggerschwellen gar nicht greifen können, und außerdem, wenn das generierte Schedule gar keine zeitliche Komponente enthält — also alle Jobs gleichzeitig starten sollen — dann läßt sich auch nichts <i>verdichten</i> und der binäre Suchalgorithmus konvergiert auf das erste gefundene Rand-Intervall
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1707610226341" ID="ID_1584389346" MODIFIED="1707610261379" TEXT="aber ein größeres Problem ist die Behandlung der Grundlast pro Node"/>
|
||||
<node CREATED="1707610290285" ID="ID_473792890" MODIFIED="1707610302914" TEXT="zunächst hatte ich ein fixes Level-Spacing">
|
||||
<node CREATED="1707610303909" ID="ID_887804445" MODIFIED="1707610311438" TEXT="damit hat die Suche stets funktioniert"/>
|
||||
<node CREATED="1707610312034" ID="ID_1201617415" MODIFIED="1707610336933" TEXT="aber ein solches Schedule kann nicht einer ungleichmäßigen Last angepaßt werden"/>
|
||||
<node CREATED="1707610337591" ID="ID_1332091220" MODIFIED="1707610694900" TEXT="daher habe ich dieses durch eine Auswertung der konkreten Gewichte im Graphen ersetzt"/>
|
||||
</node>
|
||||
<node CREATED="1707610393515" ID="ID_1786822433" MODIFIED="1707614415690" TEXT="daher ist der gesamte Code (immer noch) auf Level-basiertes Scheduling festgelegt">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
das ist eine im Rückblick ungeschickte Vereinfachung, die ich ganz zu Beginn für den SchedulerCtx gemacht habe; eigentlich müßte man die Implementierung jetzt wergwerfen und nochmal systematisch von Null auf neu aufbauen. Das versuche ich zu vermeiden, da es sich letztlich nur um Test / Expermental-Code handelt, und zudem gegenwärtig nur eine erste Grobeinschätzung durch die Streß-Tests gefordert ist (ich gehe davon aus, daß das ganze Test-Setup später für detailiertere Messungen ohnehin noch einmal neu implementiert werden muß, wenn wir denn auch dafür Zeit haben)
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<arrowlink DESTINATION="ID_283584517" ENDARROW="Default" ENDINCLINATION="228;0;" ID="Arrow_ID_1539288430" STARTARROW="None" STARTINCLINATION="124;4;"/>
|
||||
</node>
|
||||
<node CREATED="1707610627921" ID="ID_1778105375" MODIFIED="1707610681593" TEXT="ohne Gewichte fällt nun aber das »adapted schedule« auf Spacing ≡ 0 zurück"/>
|
||||
<node CREATED="1707614351040" ID="ID_700762186" MODIFIED="1707614375635" TEXT="⟹ daraufhin eine Basis-Last pro Node eingeführt"/>
|
||||
<node CREATED="1707614376388" ID="ID_283584517" MODIFIED="1707614415690" TEXT="...konnte aber nur am Ausgang aufgepflanzt werden">
|
||||
<linktarget COLOR="#a9b4c1" DESTINATION="ID_283584517" ENDARROW="Default" ENDINCLINATION="228;0;" ID="Arrow_ID_1539288430" SOURCE="ID_1786822433" STARTARROW="None" STARTINCLINATION="124;4;"/>
|
||||
</node>
|
||||
<node CREATED="1707614419191" ID="ID_1025878422" MODIFIED="1707614444983" TEXT="Konsequenz: muß auch den Streß-Faktor nachträglich auf die Basis-Last wirken lassen">
|
||||
<node CREATED="1707614503019" ID="ID_1769908346" MODIFIED="1707614521668" TEXT="ganz einfach: alle Verwendungen des Datenfelds ScheduleCtx::nodeExpense_"/>
|
||||
<node CREATED="1707614522688" ID="ID_1730567856" MODIFIED="1707614532147" TEXT="diese ebenfalls durch den Streß-Faktor teilen"/>
|
||||
<node CREATED="1707614567083" ID="ID_1736914328" MODIFIED="1707614581900" TEXT="muß dazu den Streß-Faktor speichern/merken"/>
|
||||
<node CREATED="1707614948455" ID="ID_841534742" MODIFIED="1707614984070" TEXT="und: die Duration nodeExpense wird nun mit Float-Faktor gestreckt">
|
||||
<node CREATED="1707615008583" ID="ID_1207850749" MODIFIED="1707615016054" TEXT="sollte theoretisch gehen"/>
|
||||
<node CREATED="1707615016529" ID="ID_718863605" MODIFIED="1707615051541" TEXT="Implementierung im Offset::stretchedByFloatFactor(double)"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1707615082863" ID="ID_1220483214" MODIFIED="1707615106482" TEXT="beruht auf einer Umwandlung der micro-Ticks in double">
|
||||
<icon BUILTIN="clanbomber"/>
|
||||
<node CREATED="1707615115889" ID="ID_1308444115" MODIFIED="1707615127667" TEXT="das ist ziemlich effizient"/>
|
||||
<node CREATED="1707615128760" ID="ID_100737133" MODIFIED="1707615208146" TEXT="aber gefährlich in Randbereichen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Die Mantisse des Double-Datentyps ist 24bit lang. Das reicht nicht, um einen 64bit-Integer fehlerfrei mit voller Genauigkeit darzustellen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1707615137470" ID="ID_1401860255" MODIFIED="1707615149202" TEXT="wir bewegen uns hier nicht in Randbereichen">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1707617703614" ID="ID_352684823" MODIFIED="1707617753914" TEXT="damit Suche möglich — mit angepaßten Triggerschwellen">
|
||||
<node CREATED="1707617755166" ID="ID_1259074236" MODIFIED="1707617769129" TEXT="arbeite mit einer längeren Kette (256 Nodes)"/>
|
||||
<node CREATED="1707617770829" ID="ID_1581001797" MODIFIED="1707617798425" TEXT="verwende wesentlich engere Triggerschwellen"/>
|
||||
<node CREATED="1707617799250" ID="ID_1778310142" MODIFIED="1707617871008" TEXT="qualitativ ist das statistische Kriterium weiterhin deutlich erkennbar">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
das heißt, es gibt einen Punkt ab dem die Standardabweichung deutlich ansteigt, und viele Einzel-Läufe deutlich länger brauchen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="forward"/>
|
||||
</node>
|
||||
<node CREATED="1707617878582" ID="ID_858405258" MODIFIED="1707617891896" TEXT="Messung bleibt aber fragwürdig bei so engen Toleranzen"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1707618776055" ID="ID_317119938" MODIFIED="1707618798820" TEXT="Wirkung des Streß-Faktors auf die Grundlast pro Node unklar">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1707618848101" ID="ID_1201441596" MODIFIED="1707618881939" TEXT="konzeptionell sollte der Streß-Faktor etwas unter 1.0 liegen"/>
|
||||
<node CREATED="1707618801851" ID="ID_889310986" MODIFIED="1707618826852" TEXT="die Suche konvergiert nun auf einen Streß-Faktor ~ 10.3"/>
|
||||
<node CREATED="1707618831111" ID="ID_1810672913" MODIFIED="1707618844217" TEXT="was will uns das sagen?">
|
||||
<node CREATED="1707618893358" ID="ID_1916673389" MODIFIED="1707618912376" TEXT="klar ist : mit dem Fix ist eine Rückkopplung hergestellt"/>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1707618913108" ID="ID_909181249" MODIFIED="1707618948056" TEXT="aber nicht klar ist: was bedeuten die Konstanen und Skalen?">
|
||||
<icon BUILTIN="flag-pink"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1707618964358" ID="ID_1529369833" MODIFIED="1707619157383" TEXT="hinzu kommt: es ergibt sich wieder ein sehr ähnlicher Durchschnitt (~200µs / Node / Core)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Er liegt tatsächlich etwas niedriger, nämlich 180µs ±5µs. Die Zahlen sind erstaunlich stabil und relativ genau, und passen auch mit dem statistischen Verhalten zusammen; insofer betrachte ich die 5.8ms Gesamtlaufzeit als einen <b>empirischen Fakt</b>. Und es paßt in's Bild, daß dieser Wert etwas niedriger liegt für eine lange Kette (Cache-Effekte)
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1705011154754" ID="ID_791359995" MODIFIED="1707617975551" TEXT="ohne Last : ∅t= 1.6±0.84ms">
|
||||
<node CREATED="1705011415631" ID="ID_1195549031" MODIFIED="1705179740014" TEXT="das wären ∅ ≈ 200µs /Node/Core"/>
|
||||
</node>
|
||||
<node CREATED="1707617976882" ID="ID_1281369249" MODIFIED="1707617983299" TEXT="ohne Last + längere Kette">
|
||||
<node CREATED="1707618081003" ID="ID_1931518067" MODIFIED="1707618092662" TEXT="∅t= 5.8±0.28ms"/>
|
||||
<node CREATED="1707618103200" ID="ID_330105230" MODIFIED="1707618120594" TEXT="entsprechend ∅ ≈ 180µs /Node/Core"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue