Scheduler: fundamentals of capacity classification
Workers asking for the next task are classified as belonging to some fraction of the free capacity, based on the distance to the closest next Activity known to the scheduler
This commit is contained in:
parent
b61ca94ee5
commit
84ca2460c1
4 changed files with 236 additions and 15 deletions
|
|
@ -31,6 +31,39 @@
|
|||
** are designed to withstand a short-term imbalance, expecting that general
|
||||
** engine parametrisation will be adjusted based on moving averages.
|
||||
**
|
||||
** # Principles for Engine Load Control
|
||||
**
|
||||
** Scheduling and dispatch of Activities are driven by active workers invoking
|
||||
** the Scheduler-Service to retrieve the next piece of work. While this scheme
|
||||
** ensures that the scarce resource (computation or IO capacity) is directed
|
||||
** towards the most urgent next task, achieving a smooth operation of the engine
|
||||
** without wasted capacity requires additionally to control the request cycles
|
||||
** of the workers, possibly removing excess capacity. Whenever a worker pulls
|
||||
** the next task, an assessment of the timing situation is conducted, and the
|
||||
** worker is placed into some partition of the overall available capacity,
|
||||
** to reflect the current load and demand. Workers are thus moved between
|
||||
** the segments, preferring to assign work to workers already in the active
|
||||
** segment, thereby allowing idle workers to be shut down after some time.
|
||||
**
|
||||
** The key element to decide upon the classification of a worker is the current
|
||||
** scheduling situation: are some Activities overdue? does the next Activity
|
||||
** to be considered reach far into the future? If there is immediately imminent
|
||||
** work, then capacity is kept around; otherwise the capacity can be considered
|
||||
** to be in excess for now. A worker not required right now can be sent into a
|
||||
** targeted sleep delay, in order to shift its capacity into a zone where it
|
||||
** will more likely be required. It is essential to apply some randomisation
|
||||
** on such capacity shifts, in order to achieve an even distribution of free
|
||||
** capacity and avoid contention between workers asking for new assignments.
|
||||
**
|
||||
** When a worker becomes available and is not needed at the moment, the first
|
||||
** thing to check is the time of the next approaching Activity; this worker
|
||||
** can then be directed close to this next task, which thereby has been tended
|
||||
** for and can be marked accordingly. Any further worker appearing meanwhile
|
||||
** can then be directed into the time zone _after_ the next approaching task.
|
||||
** Workers immediately returning from active work are always preferred for
|
||||
** assigning new tasks, while workers returning from idle state are typically
|
||||
** sent back into idle state, unless there is direct need for more capacity.
|
||||
**
|
||||
** @see scheduler.hpp
|
||||
** @see SchedulerStress_test
|
||||
**
|
||||
|
|
@ -59,7 +92,27 @@ namespace gear {
|
|||
|
||||
// using util::isnil;
|
||||
// using std::string;
|
||||
using std::chrono::microseconds;
|
||||
|
||||
using lib::time::Time;
|
||||
using lib::time::FSecs;
|
||||
using lib::time::Offset;
|
||||
using lib::time::Duration;
|
||||
using std::chrono_literals::operator ""ms;
|
||||
using std::chrono_literals::operator ""us;
|
||||
|
||||
namespace { // Scheduler default config
|
||||
|
||||
inline TimeValue
|
||||
_uTicks (std::chrono::microseconds us)
|
||||
{
|
||||
return TimeValue{us.count()};
|
||||
}
|
||||
|
||||
|
||||
Duration SLEEP_HORIZON{_uTicks (20ms)};
|
||||
Duration WORK_HORIZON {_uTicks ( 5ms)};
|
||||
Duration NOW_HORIZON {_uTicks (50us)};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -104,15 +157,20 @@ namespace gear {
|
|||
,IDLETIME ///< time to go to sleep
|
||||
};
|
||||
|
||||
Capacity
|
||||
classifyCapacity() const
|
||||
/** classification of time horizon for scheduling */
|
||||
static Capacity
|
||||
classifyCapacity (Offset off)
|
||||
{
|
||||
UNIMPLEMENTED ("establish a categorisation for available capacity");
|
||||
if (off > SLEEP_HORIZON) return IDLETIME;
|
||||
if (off > WORK_HORIZON) return WORKTIME;
|
||||
if (off > NOW_HORIZON) return NEARTIME;
|
||||
if (off > Time::ZERO) return SPINTIME;
|
||||
else return DISPATCH;
|
||||
}
|
||||
|
||||
|
||||
microseconds
|
||||
scatteredDelayTime()
|
||||
Time
|
||||
scatteredDelayTime (Capacity capacity)
|
||||
{
|
||||
UNIMPLEMENTED ("establish a randomised targeted delay time");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,10 @@ namespace gear {
|
|||
// using util::isnil;
|
||||
// using std::string;
|
||||
using std::move;
|
||||
using lib::time::Time;
|
||||
using lib::time::FSecs;
|
||||
using lib::time::Offset;
|
||||
using lib::time::Duration;
|
||||
|
||||
namespace { // Scheduler default config
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ namespace test {
|
|||
// using lib::time::FrameRate;
|
||||
// using lib::time::Offset;
|
||||
// using lib::time::Time;
|
||||
using Capacity = LoadController::Capacity;
|
||||
|
||||
|
||||
|
||||
|
|
@ -63,19 +64,59 @@ namespace test {
|
|||
run (Arg)
|
||||
{
|
||||
simpleUsage();
|
||||
classifyTimings();
|
||||
walkingDeadline();
|
||||
setupLalup();
|
||||
}
|
||||
|
||||
|
||||
/** @test TODO demonstrate a simple usage scenario
|
||||
* @todo WIP 10/23 ✔ define ⟶ 🔁 implement
|
||||
* @todo WIP 10/23 🔁 define ⟶ 🔁 implement
|
||||
*/
|
||||
void
|
||||
simpleUsage()
|
||||
{
|
||||
BlockFlowAlloc bFlow;
|
||||
LoadController lcontrl{bFlow};
|
||||
LoadController ctrl{bFlow};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test verify classification of time horizon for scheduling.
|
||||
* - if the next planned Activity lies beyond the SLEEP_HORIZON,
|
||||
* then the current thread can be considered part of the _idle capacity_
|
||||
* - in a similar way, WORK_HORIZON delineates the zone of repeated incoming
|
||||
* Activities from the zone considered part of current active operation
|
||||
* - Activities within the NOW_HORIZON can be awaited by yield-spinning
|
||||
* - and any event from current into the past will be scheduled right away
|
||||
* @todo WIP 10/23 ✔ define ⟶ ✔ implement
|
||||
*/
|
||||
void
|
||||
classifyTimings()
|
||||
{
|
||||
BlockFlowAlloc bFlow;
|
||||
LoadController ctrl{bFlow};
|
||||
|
||||
Time next{0,10};
|
||||
|
||||
Time ut{1,0};
|
||||
Time t1{0,9};
|
||||
Time t2{next - SLEEP_HORIZON};
|
||||
Time t21{t2 + ut};
|
||||
Time t3{next - WORK_HORIZON};
|
||||
Time t31{t3 + ut};
|
||||
Time t4{next - NOW_HORIZON};
|
||||
|
||||
CHECK (Capacity::IDLETIME == LoadController::classifyCapacity (Offset{next - ut }));
|
||||
CHECK (Capacity::IDLETIME == LoadController::classifyCapacity (Offset{next - t1 }));
|
||||
CHECK (Capacity::WORKTIME == LoadController::classifyCapacity (Offset{next - t2 }));
|
||||
CHECK (Capacity::WORKTIME == LoadController::classifyCapacity (Offset{next - t21}));
|
||||
CHECK (Capacity::NEARTIME == LoadController::classifyCapacity (Offset{next - t3 }));
|
||||
CHECK (Capacity::NEARTIME == LoadController::classifyCapacity (Offset{next - t31}));
|
||||
CHECK (Capacity::SPINTIME == LoadController::classifyCapacity (Offset{next - t4 }));
|
||||
|
||||
CHECK (Capacity::DISPATCH == LoadController::classifyCapacity (Offset::ZERO ));
|
||||
CHECK (Capacity::DISPATCH == LoadController::classifyCapacity (Offset{t4 - next }));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -81970,6 +81970,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="flag-pink"/>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1693172098402" ID="ID_671792975" MODIFIED="1697553002393" TEXT="Dependency-Injection">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1698019216343" ID="ID_1018117763" MODIFIED="1698019225152" TEXT="BlockFlow wird eine externe Komponente"/>
|
||||
<node CREATED="1698019231611" ID="ID_1147870240" MODIFIED="1698019236491" TEXT="EngineObserver ebenso"/>
|
||||
<node CREATED="1698019237891" ID="ID_323443926" MODIFIED="1698019244558" TEXT="alles andere wird Teil vom Scheduler"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1693841227130" ID="ID_1537960830" MODIFIED="1697818566052" TEXT="WorkForce einbinden">
|
||||
<arrowlink COLOR="#397cb2" DESTINATION="ID_987966047" ENDARROW="Default" ENDINCLINATION="-962;-41;" ID="Arrow_ID_818972822" STARTARROW="None" STARTINCLINATION="-609;73;"/>
|
||||
|
|
@ -81991,6 +81994,11 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1697810722994" HGAP="47" ID="ID_720864528" MODIFIED="1697810766219" TEXT="später wird hier eine globale Engine-Parametrisierung einfließen" VSHIFT="-6">
|
||||
<edge COLOR="#ffdaa4"/>
|
||||
<icon BUILTIN="hourglass"/>
|
||||
<node CREATED="1698019350177" ID="ID_1468925350" MODIFIED="1698020971330" TEXT="IDLE_WAIT = 20ms">
|
||||
<linktarget COLOR="#ffdad5" DESTINATION="ID_1468925350" ENDARROW="Default" ENDINCLINATION="-656;96;" ID="Arrow_ID_1849512128" SOURCE="ID_307944005" STARTARROW="None" STARTINCLINATION="1653;-193;"/>
|
||||
</node>
|
||||
<node CREATED="1698019358338" ID="ID_1036551796" MODIFIED="1698019358338" TEXT="DISMISS_CYCLES = 100"/>
|
||||
<node CREATED="1698019382514" ID="ID_583714412" MODIFIED="1698019387394" TEXT="POLL_WAIT_DELAY = 1ms"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697768205409" ID="ID_489957180" MODIFIED="1697768215224" TEXT="mit dem Load-Controller verbinden">
|
||||
|
|
@ -82436,6 +82444,30 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1697941881102" ID="ID_1281507935" MODIFIED="1697941890218" TEXT="else: switch to sleep"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1698020504097" ID="ID_1156275715" MODIFIED="1698020521449" TEXT="Bedeutung der Zeit-Ordnung">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1698020524734" ID="ID_1985773186" MODIFIED="1698020550679" TEXT="hier hilft eine probabilistische Betrachtung ⟶ Flow">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1698020552307" ID="ID_124426025" MODIFIED="1698020593813" TEXT="Worker melden sich regelmäßig ⟶ Kapazität fließt in bestimmte Kategorien"/>
|
||||
<node CREATED="1698020594533" ID="ID_56117621" MODIFIED="1698020625909" TEXT="nächste Activity nähert sich ⟹ Kapazität wandert in die aktiveren Phasen"/>
|
||||
<node CREATED="1698020660868" ID="ID_276531854" MODIFIED="1698020686861" TEXT="Verhältnis-Anteil der aktiven Phase ≡ Mischfaktor">
|
||||
<node CREATED="1698020747971" ID="ID_452695408" MODIFIED="1698020765281" TEXT="Sleep-Worker sind idealerweise gleichverteilt"/>
|
||||
<node CREATED="1698020696047" ID="ID_540079176" MODIFIED="1698020717690" TEXT="man extrahiert einen gewissen Anteil der Sleep-Phase"/>
|
||||
<node CREATED="1698020770133" ID="ID_1232823328" MODIFIED="1698020783240" TEXT="und verteilt sie um auf die aktiv-Phase hinter dem nächsten Termin"/>
|
||||
<node CREATED="1698020793617" ID="ID_990894590" MODIFIED="1698020839324" TEXT="das ist eine Heuristik in Erwartung weiterer Termine nahe dahinter"/>
|
||||
<node CREATED="1698020850043" ID="ID_1620028111" MODIFIED="1698020902221" TEXT="die Effizienz dürfte am Besten sein, wenn Termine kürzlich vergangen sind">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
....denn dann kommen die periodischen Worker sofort zum Zug
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#10425c" CREATED="1697979756658" ID="ID_373117026" MODIFIED="1697979894501" TEXT="Prinzipien">
|
||||
<font NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
|
|
@ -82483,13 +82515,95 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1697983183366" ID="ID_1016039063" MODIFIED="1697983192701" TEXT="Zugriff auf headTime und Vergleich"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697983155214" ID="ID_1677472042" MODIFIED="1697983174220" TEXT="classifyCapacity">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1697985093803" ID="ID_1553570724" MODIFIED="1697985096031" TEXT="enum">
|
||||
<node CREATED="1697985096625" ID="ID_1387570892" MODIFIED="1697985176660" TEXT="SPINTIME"/>
|
||||
<node CREATED="1697985096625" ID="ID_1218749290" MODIFIED="1697985105934" TEXT="NEARTIME"/>
|
||||
<node CREATED="1697985096625" ID="ID_1654025176" MODIFIED="1697985108469" TEXT="WORKTIME"/>
|
||||
<node CREATED="1697985096625" ID="ID_196379275" MODIFIED="1697985110981" TEXT="IDLETIME"/>
|
||||
<node COLOR="#338800" CREATED="1697983155214" ID="ID_1677472042" MODIFIED="1698026637409" TEXT="classifyCapacity">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1697985093803" ID="ID_1553570724" MODIFIED="1698019118162" TEXT="Enum">
|
||||
<icon BUILTIN="info"/>
|
||||
<node CREATED="1698019031467" ID="ID_341356297" MODIFIED="1698019058561" TEXT="DISPATCH">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
sent to work
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1698019039597" ID="ID_1951145257" MODIFIED="1698019068575" TEXT="TENDNEXT">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
reserved for next task
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1697985096625" ID="ID_1387570892" MODIFIED="1698019077986" TEXT="SPINTIME">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
awaiting imminent activities
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1697985096625" ID="ID_1218749290" MODIFIED="1698019089902" TEXT="NEARTIME">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
capacity for active processing required
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1697985096625" ID="ID_1654025176" MODIFIED="1698019099614" TEXT="WORKTIME">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
typical stable work task rhythm expected
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1697985096625" ID="ID_196379275" MODIFIED="1698019109349" TEXT="IDLETIME">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
time to go to sleep
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1698020940647" ID="ID_307944005" MODIFIED="1698026622294" TEXT="Konfig-Konstanten">
|
||||
<arrowlink COLOR="#ffdad5" DESTINATION="ID_1468925350" ENDARROW="Default" ENDINCLINATION="-656;96;" ID="Arrow_ID_1849512128" STARTARROW="None" STARTINCLINATION="1653;-193;"/>
|
||||
<node CREATED="1698019350177" ID="ID_1185583074" MODIFIED="1698021019755" TEXT="IDLE_WAIT = 20ms"/>
|
||||
<node CREATED="1698026586117" ID="ID_115206435" MODIFIED="1698026596761" TEXT="SLEEP_HORIZON = 20ms"/>
|
||||
<node CREATED="1698026600640" ID="ID_112350590" MODIFIED="1698026605947" TEXT="WORK_HORIZON = 5ms"/>
|
||||
<node CREATED="1698026607392" ID="ID_1582820099" MODIFIED="1698026618738" TEXT="NOW_NORIZON = 50µs"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697983292684" ID="ID_1923883572" MODIFIED="1697983303707" TEXT="scatteredDelay">
|
||||
|
|
@ -82517,6 +82631,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1698003871908" ID="ID_391492289" MODIFIED="1698003962732" TEXT="work-Function">
|
||||
<arrowlink COLOR="#7779a3" DESTINATION="ID_492054934" ENDARROW="Default" ENDINCLINATION="-814;62;" ID="Arrow_ID_817672667" STARTARROW="None" STARTINCLINATION="1393;-112;"/>
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1698019149574" HGAP="40" ID="ID_982468485" MODIFIED="1698019158970" TEXT="Fallunterscheidung" VSHIFT="21">
|
||||
<node CREATED="1698019164588" ID="ID_1369255451" MODIFIED="1698019165160" TEXT="incomingCapacity"/>
|
||||
<node CREATED="1698019170228" ID="ID_311501577" MODIFIED="1698019170871" TEXT="outgoingCapacity"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue