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;
53 const size_t NUM_THREADS = 20;
54 const size_t REPETITIONS = 100;
117 queue.instruct ({activity, when, dead});
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()));
176 auto guard = sched.requireGroomingTokenHere();
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);
253 do sleep_for (100us);
262 .threadID(
"grooming-hog"));
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();
434 Time future{now+now};
438 auto myself = std::this_thread::get_id();
443 CHECK (detector.ensureNoInvocation(
"testActivity"));
445 CHECK (not sched.
findWork (queue,now));
447 CHECK (queue.
empty());
452 CHECK (not queue.
empty());
453 CHECK (isSameObject (activity, *queue.
peekHead()));
458 CHECK (queue.
empty());
464 CHECK (not queue.
empty());
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"));
584 Activity& anchor = activityLang.buildCalculationJob (testJob, start,dead)
597 auto myself = std::this_thread::get_id();
618 CHECK (not queue.
empty());
627 CHECK (isSameObject(*act, anchor));
632 CHECK (queue.
empty());
Diagnostic setup to instrument and observe Activity activations.
Extended variant of the standard case, allowing to install callbacks (hook functions) to be invoked d...
a mutable time value, behaving like a plain number, allowing copy and re-accessing
Lumiera's internal time value datatype.
static const Time NEVER
border condition marker value. NEVER >= any time value
Abstract Base Class for all testcases.
void seedRand()
draw a new random seed from a common nucleus, and re-seed the default-Gen.
Term builder and execution framework to perform chains of scheduler Activities.
static activity::Proc dispatchChain(Activity *chain, EXE &executionCtx)
Execution Framework: dispatch performance of a chain of Activities.
Record to describe an Activity, to happen within the Scheduler's control flow.
activity::Proc activate(Time now, EXE &executionCtx)
Core Operation: Activate and perform this Activity.
Activity * next
Activities are organised into chains to represent relations based on verbs.
Individual frame rendering task, forwarding to a closure.
Controller to coordinate resource usage related to the Scheduler.
Marker for current (and obsolete) manifestations of a CalcStream processed by the Render-Engine.
Scheduler Layer-2 : execution of Scheduler Activities.
bool holdsGroomingToken(ThreadID id) noexcept
check if the indicated thread currently holds the right to conduct internal state transitions.
activity::Proc postChain(ActivationEvent event, SchedulerInvocation &layer1)
This is the primary entrance point to the Scheduler.
bool acquireGoomingToken() noexcept
acquire the right to perform internal state transitions.
void dropGroomingToken() noexcept
relinquish the right for internal state transitions.
activity::Proc dispatchCapacity(SchedulerInvocation &, LoadController &, DISPATCH, CLOCK)
Implementation of the worker-Functor:
ActivationEvent findWork(SchedulerInvocation &layer1, Time now)
Look into the queues and possibly retrieve work due by now.
Scheduler Layer-1 : time based dispatch.
void instruct(ActivationEvent actEvent)
Accept an ActivationEvent with an Activity for time-bound execution.
bool isDue(Time now) const
Determine if there is work to do right now.
void feedPrioritisation()
Pick up all new events from the entrance queue and enqueue them to be retrieved ordered by start time...
ActivationEvent pullHead()
Retrieve from the scheduling queue the entry with earliest start time.
ActivationEvent peekHead()
Diagnostic context to record and evaluate activations within the Scheduler.
ActivityMatch verifySeqIncrement(uint seqNr)
ActivityMatch ensureNoInvocation(string fun)
FakeExecutionCtx executionCtx
Job buildMockJob(string id="", Time nominal=lib::test::randTime(), size_t extra=rani())
Activity & watchGate(Activity *&wiring, string id="")
ActivityMatch verifyInvocation(string fun)
uint incrementSeq()
increment the internal invocation sequence number
ActivityMatch & arg(ARGS const &...args)
qualifier: additionally match the function arguments
ActivityMatch & beforeInvocation(string match)
void verify_GroomingToken()
void unblockGroomingToken()
ThreadHookable::Launch Launch
void demonstrateSimpleUsage()
void torture_GroomingToken()
static void ___ensureGroomingTokenReleased(SchedulerCommutator &sched)
unique_ptr< ThreadHookable > groomingHog_
void verify_GroomingGuard()
void integratedWorkCycle()
void blockGroomingToken(SchedulerCommutator &sched)
void verify_Significance()
Functions to perform (multithreaded) timing measurement on a given functor.
auto threadBenchmark(FUN const &subject, const size_t repeatCnt=DEFAULT_RUNS)
perform a multithreaded microbenchmark.
boost::rational< int64_t > FSecs
rational representation of fractional seconds
Test runner and basic definitions for tests.
bool isSameObject(A const &a, B const &b)
compare plain object identity, based directly on the referee's memory identities.
@ PASS
pass on the activation down the chain
@ KICK
back pressure; get out of the way but be back soon
Vault-Layer implementation namespace root.
Simplistic test class runner.
#define LAUNCHER(_TEST_CLASS_, _GROUPS_)
Layer-2 of the Scheduler: coordination and interaction of activities.
void detach_thread_from_wrapper()
allow to detach explicitly — independent from thread-function's state.
function< Time()> getSchedTime
_DiagnosticFun< SIG_work >::Type work
#define MARK_TEST_FUN
Macro to mark the current test function in STDOUT.
Convenience front-end to simplify and codify basic thread handling.
a family of time value like entities and their relationships.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...