diff --git a/src/vault/gear/scheduler.hpp b/src/vault/gear/scheduler.hpp
index 3b49d1189..dc5125413 100644
--- a/src/vault/gear/scheduler.hpp
+++ b/src/vault/gear/scheduler.hpp
@@ -147,6 +147,46 @@ namespace gear {
+ class ScheduleSpec
+ {
+ Job job_;
+
+ public:
+ ScheduleSpec (Job job)
+ : job_{job}
+ { }
+
+ ScheduleSpec
+ startOffset (microseconds microTicks)
+ {
+ UNIMPLEMENTED ("start offset");
+ return move(*this);
+ }
+
+ ScheduleSpec
+ lifeWindow (microseconds microTicks)
+ {
+ UNIMPLEMENTED ("deadline relative to starts");
+ return move(*this);
+ }
+
+ ScheduleSpec
+ manifestation (ManifestationID manID)
+ {
+ UNIMPLEMENTED ("store manifestation-ID");
+ return move(*this);
+ }
+
+ ScheduleSpec
+ post()
+ {
+ UNIMPLEMENTED ("build chain and hand-over into queue");
+ return move(*this);
+ }
+ };
+
+
+
/******************************************************//**
* »Scheduler-Service« : coordinate render activities.
* @todo WIP-WIP 10/2023
@@ -248,8 +288,8 @@ namespace gear {
/**
*
*/
- void
- buildJob()
+ ScheduleSpec
+ defineSchedule (Job job)
{
UNIMPLEMENTED("wrap the ActivityTerm");
}
diff --git a/src/vault/gear/work-force.hpp b/src/vault/gear/work-force.hpp
index 88debd675..9f7978a53 100644
--- a/src/vault/gear/work-force.hpp
+++ b/src/vault/gear/work-force.hpp
@@ -73,7 +73,9 @@ namespace gear {
using std::atomic;
using util::unConst;
using std::chrono::milliseconds;
+ using std::chrono::microseconds;
using std::chrono_literals::operator ""ms;
+ using std::chrono_literals::operator ""us;
using std::this_thread::sleep_for;
diff --git a/tests/vault/gear/scheduler-commutator-test.cpp b/tests/vault/gear/scheduler-commutator-test.cpp
index 160056691..be1acc820 100644
--- a/tests/vault/gear/scheduler-commutator-test.cpp
+++ b/tests/vault/gear/scheduler-commutator-test.cpp
@@ -368,7 +368,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
queue.instruct ({a1, t1, t4, ManifestationID{5}});
queue.instruct ({a2, t2, t2});
queue.instruct ({a3, t3, t3, ManifestationID{23}, true});
@@ -497,7 +497,7 @@ namespace test {
queue.feedPrioritisation();
CHECK (now == queue.headTime());
CHECK (isSameObject (activity, *sched.findWork(queue, now)));
- CHECK (sched.holdsGroomingToken (myself));
+ CHECK (sched.holdsGroomingToken (myself)); // findWork() acquired the token
CHECK (future == queue.headTime());
CHECK (not queue.isDue(now));
CHECK ( queue.isDue(future));
diff --git a/tests/vault/gear/scheduler-service-test.cpp b/tests/vault/gear/scheduler-service-test.cpp
index e16cb1589..69aa211af 100644
--- a/tests/vault/gear/scheduler-service-test.cpp
+++ b/tests/vault/gear/scheduler-service-test.cpp
@@ -80,10 +80,11 @@ namespace test {
virtual void
run (Arg)
{
-// simpleUsage();
-// verify_StartStop();
+ simpleUsage();
+ verify_StartStop();
verify_LoadFactor();
-// invokeWorkFunction();
+ invokeWorkFunction();
+ scheduleRenderJob();
walkingDeadline();
}
@@ -137,7 +138,7 @@ namespace test {
/** @test verify the scheduler processes scheduled events,
* indicates current load and winds down automatically
* when falling empty.
- * - placing short bursts of single FEED-Activities
+ * - schedule short bursts of single FEED-Activities
* - these actually do nothing and can be processed typically < 5µs
* - placing them spaced by 1µs, so the scheduler will build up congestion
* - since this Activity does not drop the »grooming-token«, actually only
@@ -146,12 +147,14 @@ namespace test {
* - when reaching the scheduler »tick«, the queue should be empty
* and the scheduler will stop active processing
* - the main thread (this test) polls every 50µs to observe the load
+ * - after 2 seconds of idle-sleeping, the WorkForce is disengaged
* - verify the expected load pattern
* @todo WIP 10/23 ✔ define ⟶ ✔ implement
*/
void
verify_LoadFactor()
{
+ MARK_TEST_FUN
BlockFlowAlloc bFlow;
EngineObserver watch;
Scheduler scheduler{bFlow, watch};
@@ -284,19 +287,20 @@ namespace test {
* + after dispatching an Activity in a situation with no follow-up work,
* the work-function inserts a targeted sleep of random duration,
* to re-shuffle the rhythm of sleep cycles
- * + when the next planned Activity has already be »tended for« (by placing
+ * + when the next planned Activity was already »tended for« (by placing
* another worker into a targeted sleep), further workers entering the
* work-function will be re-targeted by a random sleep to focus capacity
* into a time zone behind the next entry.
- * @note Invoke the Activity probe itself can take 50..150µs, due to the EventLog,
+ * @note Invoking the Activity probe itself can take 50..150µs, due to the EventLog,
* which is not meant to be used in performance critical paths but only for tests,
* because it performs lots of heap allocations and string operations. Moreover,
* we see additional cache effects after an extended sleep period.
- * @todo WIP 10/23 🔁 define ⟶ implement
+ * @todo WIP 10/23 ✔ define ⟶ ✔ implement
*/
void
invokeWorkFunction()
{
+ MARK_TEST_FUN
BlockFlowAlloc bFlow;
EngineObserver watch;
Scheduler scheduler{bFlow, watch};
@@ -310,7 +314,7 @@ namespace test {
activity::Proc res;
auto post = [&](Time start)
- { // this test class is declared friend to get a backdoor to Scheduler internals...
+ { // this test class is declared friend to get a backdoor into Scheduler internals...
scheduler.layer2_.acquireGoomingToken();
scheduler.postChain(ActivationEvent{probe, start});
};
@@ -436,6 +440,47 @@ namespace test {
+ /** @test TODO schedule a render job through the high-level Job-builder API.
+ * - use the mock Job-Functor provided by the ActivityDetector
+ * @todo WIP 11/23 ✔ define ⟶ 🔁 implement
+ */
+ void
+ scheduleRenderJob()
+ {
+ MARK_TEST_FUN
+ BlockFlowAlloc bFlow;
+ EngineObserver watch;
+ Scheduler scheduler{bFlow, watch};
+
+ Time nominal{7,7};
+ Time start{0,1};
+ Time dead{0,10};
+
+ ActivityDetector detector;
+ Job testJob{detector.buildMockJob("testJob", nominal, 1337)};
+
+ CHECK (scheduler.empty());
+ scheduler.defineSchedule(testJob)
+ .startOffset(200us)
+ .lifeWindow (1ms)
+ .manifestation(ManifestationID{55})
+ .post();
+
+ CHECK (not scheduler.empty());
+ CHECK (detector.ensureNoInvocation("testJob"));
+
+ sleep_for(400us);
+ CHECK (detector.ensureNoInvocation("testJob"));
+
+ CHECK (activity::PASS == scheduler.getWork());
+ CHECK (scheduler.empty());
+
+ cout << detector.showLog()<
- ....das hat sich allerdings schon aus der Analyse des Pull-Processing im Node-Network so ergeben, denn dort geht man von der ExitNode rückwärts; damals konnte ich nicht vorhersehen, wie die Situation im Scheduler sich darstellen wird — möglicherweise verbirg sich eine tiefere, strukturelle Konvergenz dahinter, daß das jetzt so schön aufgeht + ....das hat sich allerdings schon aus der Analyse des Pull-Processing im Node-Network so ergeben, denn dort geht man von der ExitNode rückwärts; damals konnte ich nicht vorhersehen, wie die Situation im Scheduler sich darstellen wird — möglicherweise verbirgt sich eine tiefere, strukturelle Konvergenz dahinter, daß das jetzt so schön aufgeht