40 using std::atomic_bool;
45 using std::unique_ptr;
46 using std::make_unique;
47 using std::this_thread::yield;
48 using std::this_thread::sleep_for;
49 using std::chrono_literals::operator
""us;
54 const size_t REPETITIONS = 100;
113 Time now = detector.executionCtx.getSchedTime();
117 queue.instruct ({activity, when, dead});
123 CHECK (detector.verifyInvocation(
"CTX-tick").
arg(now));
124 CHECK (queue.empty());
139 auto myself = std::this_thread::get_id();
140 CHECK (not sched.holdsGroomingToken (myself));
142 CHECK (sched.acquireGoomingToken());
143 CHECK ( sched.holdsGroomingToken (myself));
145 sched.dropGroomingToken();
146 CHECK (not sched.holdsGroomingToken (myself));
154 auto myself = std::this_thread::get_id();
173 CHECK (sched.acquireGoomingToken());
174 CHECK (sched.holdsGroomingToken (
thisThread()));
177 CHECK (sched.holdsGroomingToken (
thisThread()));
179 CHECK (sched.holdsGroomingToken (
thisThread()));
182 sched.dropGroomingToken();
185 auto guard = sched.requireGroomingTokenHere();
186 CHECK (sched.holdsGroomingToken (
thisThread()));
188 CHECK (not sched.holdsGroomingToken (
thisThread()));
207 auto pause_and_sum = [&](
size_t i) ->
size_t 209 auto oldSum = checkSum;
211 checkSum = oldSum + i;
214 auto protected_sum = [&](
size_t i) ->
size_t 216 while (not sched.acquireGoomingToken())
219 sched.dropGroomingToken();
223 threadBenchmark<NUM_THREADS> (pause_and_sum, REPETITIONS);
225 size_t brokenSum = checkSum;
228 threadBenchmark<NUM_THREADS> (protected_sum, REPETITIONS);
230 CHECK (brokenSum < checkSum);
231 CHECK (checkSum =
NUM_THREADS * REPETITIONS*(REPETITIONS-1)/2);
237 atomic_bool stopTheHog_{
false};
238 unique_ptr<ThreadHookable> groomingHog_;
239 using Launch = ThreadHookable::Launch;
245 REQUIRE (not groomingHog_);
250 groomingHog_ = make_unique<ThreadHookable>(
253 do sleep_for (100us);
254 while (not stopTheHog_);
260 groomingHog_.reset();
262 .threadID(
"grooming-hog"));
264 ENSURE (groomingHog_);
292 CHECK (not sched.
findWork (queue, now));
298 queue.instruct ({a3, t3});
299 CHECK (not sched.
findWork (queue, now));
300 CHECK (t3 == queue.headTime());
302 queue.instruct ({a1, t1});
303 CHECK (isSameObject (a1, *sched.
findWork(queue, now)));
304 CHECK (not sched.
findWork (queue, now));
306 queue.instruct ({a2, t2});
307 CHECK (isSameObject (a2, *sched.
findWork(queue, now)));
308 CHECK (not sched.
findWork (queue, now));
309 CHECK (t3 == queue.headTime());
310 CHECK (not queue.empty());
312 CHECK (isSameObject (a3, *sched.
findWork(queue, t3)));
313 CHECK (not sched.
findWork (queue, t3));
314 CHECK ( queue.empty());
316 queue.instruct ({a2, t2});
317 queue.instruct ({a1, t1});
318 CHECK (isSameObject (a1, *sched.
findWork(queue, now)));
319 CHECK (t2 == queue.headTime());
320 CHECK (isSameObject (a2, *sched.
findWork(queue, now)));
321 CHECK (not sched.
findWork (queue, now));
322 CHECK ( queue.empty());
324 queue.instruct ({a2, t2});
326 CHECK (not sched.
findWork (queue, now));
327 CHECK (not queue.empty());
330 CHECK (isSameObject (a2, *sched.
findWork(queue, now)));
331 CHECK (queue.empty());
358 queue.instruct ({a2, t2, t2});
360 queue.instruct ({a4, t4, t4});
364 queue.feedPrioritisation();
365 CHECK (t1 == queue.headTime());
366 CHECK (isSameObject (a1, *queue.peekHead()));
367 CHECK (not queue.isMissed(t1));
368 CHECK (not queue.isOutdated(t1));
371 CHECK (t1 == queue.headTime());
372 CHECK (not queue.isMissed(t1));
373 CHECK ( queue.isOutdated(t1));
375 CHECK (not sched.
findWork(queue, t1));
376 CHECK (t2 == queue.headTime());
377 CHECK (isSameObject (a2, *queue.peekHead()));
378 CHECK (not queue.isMissed (t2));
379 CHECK (not queue.isOutdated(t2));
380 CHECK ( queue.isMissed (t3));
381 CHECK ( queue.isOutdated(t3));
384 CHECK (t3 == queue.headTime());
385 CHECK (isSameObject (a3, *queue.peekHead()));
386 CHECK (not queue.isMissed (t3));
387 CHECK (not queue.isOutdated (t3));
388 CHECK (not queue.isOutOfTime(t3));
389 CHECK ( queue.isMissed (t4));
390 CHECK ( queue.isOutdated (t4));
391 CHECK ( queue.isOutOfTime(t4));
393 CHECK (not sched.
findWork(queue, t4));
394 CHECK (t3 == queue.headTime());
395 CHECK (not queue.isMissed (t3));
396 CHECK (not queue.isOutdated (t3));
397 CHECK (not queue.isOutOfTime(t3));
398 CHECK ( queue.isMissed (t4));
399 CHECK ( queue.isOutdated (t4));
400 CHECK ( queue.isOutOfTime(t4));
403 CHECK (t3 == queue.headTime());
404 CHECK (not queue.isMissed (t3));
405 CHECK ( queue.isOutdated (t3));
406 CHECK (not queue.isOutOfTime(t3));
407 CHECK ( queue.isMissed (t4));
408 CHECK ( queue.isOutdated (t4));
409 CHECK (not queue.isOutOfTime(t4));
411 CHECK (isSameObject (a3, *queue.peekHead()));
412 CHECK (isSameObject (a4, *sched.
findWork(queue, t4)));
413 CHECK (queue.empty());
426 Activity& activity = detector.buildActivationProbe (
"testActivity");
432 Time now = detector.executionCtx.getSchedTime();
433 Time past {Time::ZERO};
434 Time future{now+now};
438 auto myself = std::this_thread::get_id();
442 CHECK (activity::PASS == sched.
postChain (makeEvent(past), queue));
443 CHECK (detector.ensureNoInvocation(
"testActivity"));
445 CHECK (not sched.
findWork (queue,now));
447 CHECK (queue.empty());
450 CHECK (activity::PASS == sched.
postChain (makeEvent(future), queue));
452 CHECK (not queue.empty());
453 CHECK (isSameObject (activity, *queue.
peekHead()));
458 CHECK (queue.empty());
461 CHECK (activity::PASS == sched.
postChain (makeEvent(future), queue));
464 CHECK (not queue.empty());
468 CHECK (activity::PASS == sched.
postChain (makeEvent(now), queue));
474 CHECK (detector.ensureNoInvocation(
"testActivity"));
482 CHECK (isSameObject (activity, *sched.
findWork(queue, now)));
485 CHECK (not queue.
isDue(now));
486 CHECK ( queue.
isDue(future));
487 CHECK (sched.
findWork(queue, future));
488 CHECK ( queue.empty());
506 Activity& activity = detector.buildActivationProbe (
"testActivity");
516 queue.
instruct ({activity, start, dead});
523 auto myself = std::this_thread::get_id();
528 auto getSchedTime = detector.executionCtx.getSchedTime;
540 CHECK (not queue.empty());
551 CHECK (queue.empty());
553 CHECK (detector.verifyInvocation(
"testActivity"));
578 Job testJob{detector.buildMockJob(
"testJob", nominal, 12345)};
584 Activity& anchor = activityLang.buildCalculationJob (testJob, start,dead)
588 detector.watchGate (anchor.
next,
"theGate");
597 auto myself = std::this_thread::get_id();
603 detector.executionCtx.getSchedTime = [&]{
return Time{now}; };
605 detector.executionCtx.work.implementedAs(
616 CHECK (detector.ensureNoInvocation(
"testJob"));
618 CHECK (not queue.empty());
627 CHECK (isSameObject(*act, anchor));
632 CHECK (queue.empty());
635 CHECK (detector.verifySeqIncrement(1)
636 .beforeInvocation(
"theGate").
arg(
"5.555 ⧐ Act(GATE")
637 .beforeInvocation(
"after-theGate").
arg(
"⧐ Act(WORKSTART")
638 .beforeInvocation(
"CTX-work").
arg(
"5.555",
"")
639 .beforeInvocation(
"testJob") .
arg(
"7.007",12345)
640 .beforeInvocation(
"CTX-done").
arg(
"5.555",
""));
a mutable time value, behaving like a plain number, allowing copy and re-accessing ...
activity::Proc postChain(ActivationEvent event, SchedulerInvocation &layer1)
This is the primary entrance point to the Scheduler.
Record to describe an Activity, to happen within the Scheduler's control flow.
auto threadBenchmark(FUN const &subject, const size_t repeatCnt=DEFAULT_RUNS)
perform a multithreaded microbenchmark.
void integratedWorkCycle()
bool holdsGroomingToken(ThreadID id) noexcept
check if the indicated thread currently holds the right to conduct internal state transitions...
void dropGroomingToken() noexcept
relinquish the right for internal state transitions.
void blockGroomingToken(SchedulerCommutator &sched)
void verify_GroomingToken()
Scheduler Layer-2 : execution of Scheduler Activities.
auto thisThread()
convenient short-notation, also used by SchedulerService
ActivationEvent findWork(SchedulerInvocation &layer1, Time now)
Look into the queues and possibly retrieve work due by now.
Functions to perform (multithreaded) timing measurement on a given functor.
void verify_Significance()
activity::Proc activate(Time now, EXE &executionCtx)
Core Operation: Activate and perform this Activity.
Lumiera's internal time value datatype.
static void ___ensureGroomingTokenReleased(SchedulerCommutator &sched)
Controller to coordinate resource usage related to the Scheduler.
void instruct(ActivationEvent actEvent)
Accept an ActivationEvent with an Activity for time-bound execution.
Abstract Base Class for all testcases.
Term builder and execution framework to perform chains of scheduler Activities.
Marker for current (and obsolete) manifestations of a CalcStream processed by the Render-Engine...
Diagnostic context to record and evaluate activations within the Scheduler.
#define MARK_TEST_FUN
Macro to mark the current test function in STDOUT.
void demonstrateSimpleUsage()
Simplistic test class runner.
void seedRand()
draw a new random seed from a common nucleus, and re-seed the default-Gen.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
void unblockGroomingToken()
Convenience front-end to simplify and codify basic thread handling.
void verify_GroomingGuard()
ActivationEvent peekHead()
boost::rational< int64_t > FSecs
rational representation of fractional seconds
uint incrementSeq()
increment the internal invocation sequence number
Activity * next
Activities are organised into chains to represent relations based on verbs.
Diagnostic setup to instrument and observe Activity activations.
Layer-2 of the Scheduler: coordination and interaction of activities.
void torture_GroomingToken()
static const Time NEVER
border condition marker value. NEVER >= any time value
Extended variant of the standard case, allowing to install callbacks (hook functions) to be invoked d...
ScopedGroomingGuard requireGroomingTokenHere()
a scope guard to force acquisition of the GroomingToken
static activity::Proc dispatchChain(Activity *chain, EXE &executionCtx)
Execution Framework: dispatch performance of a chain of Activities.
ActivationEvent pullHead()
Retrieve from the scheduling queue the entry with earliest start time.
Individual frame rendering task, forwarding to a closure.
a family of time value like entities and their relationships.
void feedPrioritisation()
Pick up all new events from the entrance queue and enqueue them to be retrieved ordered by start time...
ActivityMatch & arg(ARGS const &...args)
qualifier: additionally match the function arguments
Vault-Layer implementation namespace root.
bool isDue(Time now) const
Determine if there is work to do right now.
bool acquireGoomingToken() noexcept
acquire the right to perform internal state transitions.
Scheduler Layer-1 : time based dispatch.
activity::Proc dispatchCapacity(SchedulerInvocation &, LoadController &, DISPATCH, CLOCK)
Implementation of the worker-Functor:
void detach_thread_from_wrapper()
allow to detach explicitly — independent from thread-function's state.
bool isSameObject(A const &a, B const &b)
compare plain object identity, based directly on the referee's memory identities. ...