Scheduler: integrate sanity check on timings

...especially to prevent a deadline way too far into the future,
since this would provoke the BlockFlow (epoch based) memory manager
to run out of space.

Just based on gut feeling, I am now imposing a limit of 20seconds,
which, given current parametrisation, with a minimum spacing of 6.6ms
and 500 Activities per Block would at maximum require 360 MiB for
the Activities, or 3000 Blocks. With *that much* blocks, the
linear search would degrade horribly anyway...
This commit is contained in:
Fischlurch 2023-11-07 18:37:20 +01:00
parent 0ed7dba641
commit 892099412c
4 changed files with 101 additions and 21 deletions

View file

@ -76,6 +76,7 @@
#include "vault/gear/scheduler-invocation.hpp"
#include "vault/gear/activity-lang.hpp"
#include "lib/time/timevalue.hpp"
#include "lib/format-string.hpp"
#include "lib/nocopy.hpp"
#include <thread>
@ -85,12 +86,19 @@
namespace vault{
namespace gear {
using lib::time::Offset;
using lib::time::FSecs;
using lib::time::Time;
using std::atomic;
using std::memory_order::memory_order_relaxed;
using std::memory_order::memory_order_acquire;
using std::memory_order::memory_order_release;
namespace { // Configuration / Scheduling limit
Offset FUTURE_PLANNING_LIMIT{FSecs{20}}; ///< limit timespan of deadline into the future (~360 MiB max)
}
/*************************************************************//**
@ -156,6 +164,21 @@ namespace gear {
}
void
sanityCheck (ActivationEvent const& event, Time now)
{
if (event.startTime() == Time::ANYTIME)
throw error::Fatal ("Attempt to schedule an Activity without valid start time");
if (event.deathTime() == Time::NEVER)
throw error::Fatal ("Attempt to schedule an Activity without valid deadline");
Offset toDeadline{now, event.deathTime()};
if (toDeadline > FUTURE_PLANNING_LIMIT)
throw error::Fatal (util::_Fmt{"Attempt to schedule Activity %s "
"with a deadline by %s into the future"}
% *event.activity
% toDeadline);
}
/**
* Decide if Activities shall be performed now and in this thread.
* @param when the indicated time of start of the first Activity
@ -224,6 +247,7 @@ namespace gear {
if (!event) return activity::SKIP;
Time now = executionCtx.getSchedTime();
sanityCheck (event, now);
if (decideDispatchNow (event.startTime(), now))
return ActivityLang::dispatchChain (event, executionCtx);
else

View file

@ -112,14 +112,16 @@ namespace test {
SchedulerInvocation queue;
SchedulerCommutator sched;
Activity activity;
Time when{1,2};
Time when{3,4};
Time dead{5,6};
// use the ActivityDetector for test instrumentation...
ActivityDetector detector;
Time now = detector.executionCtx.getSchedTime();
CHECK (now < dead);
// prepare scenario: some activity is enqueued
queue.instruct ({activity, when});
queue.instruct ({activity, when, dead});
sched.postDispatch (sched.findWork(queue,now), detector.executionCtx,queue);
CHECK (detector.verifyInvocation("CTX-tick").arg(now));
@ -438,7 +440,8 @@ namespace test {
// rigged execution environment to detect activations--------------
ActivityDetector detector;
Activity& activity = detector.buildActivationProbe ("testActivity");
auto makeEvent = [&](Time start) { return ActivationEvent{activity, start, start+Time{0,1}}; };
// set a dummy deadline to pass the sanity check
SchedulerInvocation queue;
SchedulerCommutator sched;
@ -456,14 +459,14 @@ namespace test {
CHECK (not sched.holdsGroomingToken (myself));
// Activity immediately dispatched when on time and GroomingToken can be acquired
CHECK (activity::PASS == sched.postDispatch (ActivationEvent{activity, past}, detector.executionCtx, queue));
CHECK (activity::PASS == sched.postDispatch (makeEvent(past), detector.executionCtx, queue));
CHECK (detector.verifyInvocation("testActivity").timeArg(now)); // was invoked immediately
CHECK ( sched.holdsGroomingToken (myself));
CHECK ( queue.empty());
detector.incrementSeq(); // Seq-point-1 in the detector log
// future Activity is enqueued by short-circuit directly into the PriorityQueue if possible
CHECK (activity::PASS == sched.postDispatch (ActivationEvent{activity, future}, detector.executionCtx, queue));
CHECK (activity::PASS == sched.postDispatch (makeEvent(future), detector.executionCtx, queue));
CHECK ( sched.holdsGroomingToken (myself));
CHECK (not queue.empty());
CHECK (isSameObject (activity, *queue.peekHead())); // appears at Head, implying it's in Priority-Queue
@ -474,14 +477,14 @@ namespace test {
CHECK (queue.empty());
// ...but GroomingToken is not acquired explicitly; Activity is just placed into the Instruct-Queue
CHECK (activity::PASS == sched.postDispatch (ActivationEvent{activity, future}, detector.executionCtx, queue));
CHECK (activity::PASS == sched.postDispatch (makeEvent(future), detector.executionCtx, queue));
CHECK (not sched.holdsGroomingToken (myself));
CHECK (not queue.peekHead()); // not appearing at Head this time,
CHECK (not queue.empty()); // rather waiting in the Instruct-Queue
blockGroomingToken(sched);
CHECK (activity::PASS == sched.postDispatch (ActivationEvent{activity, now}, detector.executionCtx, queue));
CHECK (activity::PASS == sched.postDispatch (makeEvent(now), detector.executionCtx, queue));
CHECK (not sched.holdsGroomingToken (myself));
CHECK (not queue.peekHead()); // was enqueued, not executed

View file

@ -111,7 +111,7 @@ namespace test {
void
postNewTask (Scheduler& scheduler, Activity& chain, Time start)
{
ActivationEvent actEvent{chain, start};
ActivationEvent actEvent{chain, start, start + Time{50,0}}; // add dummy deadline +50ms
Scheduler::ExecutionCtx ctx{scheduler, actEvent};
scheduler.layer2_.postDispatch (actEvent, ctx, scheduler.layer1_);
}

View file

@ -82080,21 +82080,74 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1697756908166" ID="ID_1142273023" MODIFIED="1699300683254" TEXT="Wrapper-Builder um den Activity-Term legen">
<linktarget COLOR="#f4336b" DESTINATION="ID_1142273023" ENDARROW="Default" ENDINCLINATION="-737;663;" ID="Arrow_ID_891496003" SOURCE="ID_175313196" STARTARROW="None" STARTINCLINATION="1218;-76;"/>
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1698945250261" ID="ID_780386157" MODIFIED="1698946166942" TEXT="Zusatz-Angaben zur Relevanz">
<node COLOR="#338800" CREATED="1698945250261" ID="ID_780386157" MODIFIED="1699376300350" TEXT="Zusatz-Angaben zur Relevanz">
<linktarget COLOR="#3d3aa9" DESTINATION="ID_780386157" ENDARROW="Default" ENDINCLINATION="86;143;" ID="Arrow_ID_103420327" SOURCE="ID_1778628995" STARTARROW="None" STARTINCLINATION="317;25;"/>
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1699376305031" ID="ID_65587622" MODIFIED="1699376321708" TEXT="ManifestationID"/>
<node COLOR="#435e98" CREATED="1699376312965" ID="ID_730592934" MODIFIED="1699376321709" TEXT="isCompulsory"/>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1698947287399" ID="ID_391005911" LINK="#ID_1426746639" MODIFIED="1698947345862" TEXT="Job-Deadline auf API verpflichtend">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1698947287399" FOLDED="true" ID="ID_391005911" LINK="#ID_1426746639" MODIFIED="1699376270521" TEXT="Job-Deadline auf API verpflichtend">
<icon BUILTIN="messagebox_warning"/>
<node COLOR="#5b280f" CREATED="1699310594544" ID="ID_1072047412" MODIFIED="1699310620293" TEXT="mit dem Builder-API nicht darstellbar">
<icon BUILTIN="button_cancel"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1699310605911" ID="ID_169718532" MODIFIED="1699310630268" TEXT="kann nur eine Assertion einbauen">
<icon BUILTIN="flag-pink"/>
<node COLOR="#338800" CREATED="1699310605911" ID="ID_169718532" MODIFIED="1699372921757" TEXT="aber einen Check mit Exception kann man einbauen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Nicht am falschen Ende sparen hier! Das kostet nur ein paar Nanosekunden...
(und ein paar Fixes in den Tests, damit die am sanityCheck vorbeikommen)
</p>
</body>
</html></richcontent>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1699373956162" ID="ID_1098257299" MODIFIED="1699376259965" TEXT="ebenso einen Check gegen Deadlines zu weit in der Zukunft">
<icon BUILTIN="button_ok"/>
<node CREATED="1699373969470" ID="ID_396517654" MODIFIED="1699373978929" TEXT="sinnvoll dimensionieren?"/>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1699373980509" ID="ID_1475597715" MODIFIED="1699373990484" TEXT="man k&#xf6;nnte hier auf den BlockFlow zugreifen">
<icon BUILTIN="hourglass"/>
</node>
<node CREATED="1699373991478" ID="ID_167847312" MODIFIED="1699376244923" TEXT="erst mal fest verdrahten">
<icon BUILTIN="yes"/>
<node CREATED="1699373997383" ID="ID_680337402" MODIFIED="1699374014940" TEXT="Block-Size: 500 &#x27f9; Frames pro Block"/>
<node CREATED="1699374069953" ID="ID_987216063" MODIFIED="1699374077213" TEXT="initial Framerate: 5 * 25"/>
<node CREATED="1699374241946" ID="ID_854095581" MODIFIED="1699374250957" TEXT="&#x27f9; initial Epoch-Step 0.4sec"/>
<node CREATED="1699374286828" ID="ID_1273383304" MODIFIED="1699374296403" TEXT="&#x27f9; Limit bei 6666&#xb5;s"/>
<node CREATED="1699374536778" ID="ID_1215862863" MODIFIED="1699374571890" TEXT="sizeof(Activity) = 4*64byte = 256byte"/>
<node CREATED="1699374595111" ID="ID_838506431" MODIFIED="1699374610445" TEXT="&#x27f9; ein Block: 125KiB"/>
<node CREATED="1699374690327" ID="ID_1827252278" MODIFIED="1699374702912" TEXT="bei kleinstem Spacing &#x27f9; max 3000 Bl&#xf6;cke"/>
<node CREATED="1699374703645" ID="ID_870259225" MODIFIED="1699374725707">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
<b>20</b>sec &#10233; 366 MiB
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1699374714149" ID="ID_1607589409" MODIFIED="1699374716762" TEXT="das pack ma!"/>
</node>
<node CREATED="1699374728785" ID="ID_211476282" MODIFIED="1699376256811">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
also auf <b>20 Sekunden</b>&#160;in die Zukunft limitieren
</p>
</body>
</html></richcontent>
<icon BUILTIN="forward"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1699245520392" ID="ID_1677467445" MODIFIED="1699310561557" TEXT="Builder-Funktionen">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1699373933315" ID="ID_501195368" MODIFIED="1699376262879" TEXT="eingebaut in Layer-2 .postDispatch()">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1699245520392" ID="ID_1677467445" MODIFIED="1699376290830" TEXT="Builder-Funktionen">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1699245533215" ID="ID_1666620904" MODIFIED="1699310551449" TEXT="relative Zeitangabe">
<icon BUILTIN="button_ok"/>
</node>
@ -82104,14 +82157,14 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<font ITALIC="true" NAME="SansSerif" SIZE="9"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1699245538409" ID="ID_1074993324" MODIFIED="1699246017064" TEXT="hier auch schon mal std::chrono mit integrieren (f&#xfc;r Tests)">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1699245538409" ID="ID_1074993324" MODIFIED="1699376286627" TEXT="hier auch schon mal std::chrono mit integrieren (f&#xfc;r Tests)">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1699245552636" ID="ID_1654937511" MODIFIED="1699246017063" TEXT="relative Deadline">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1699245552636" ID="ID_1654937511" MODIFIED="1699376287980" TEXT="relative Deadline">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1699245562635" ID="ID_1277275368" MODIFIED="1699246017063" TEXT="weitere Setter">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1699245562635" ID="ID_1277275368" MODIFIED="1699376289016" TEXT="weitere Setter">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1699245577969" ID="ID_1964298619" MODIFIED="1699310570096" TEXT="post() ausf&#xfc;hren">