Scheduler-test: rework handling of notifications in the Activity-Language

While the recent refactoring...
206c67cc

...was a step into the right direction, it pushed too hard,
overlooking the requirement to protect the scheduler contents
and thus all of the Activity-chains against concurrent modification.
Moreover, the recent solution still seems not quite orthogonal.

Thus the handling of notifications was thoroughly reworked:
- the explicit "double-dispatch" was removed, since actual usage
  of the language indicates that we only need notifications to
  Gate (and Hook), but not to any other conceivable Activity.
- thus it seems unnecessary to turn "notification" into some kind
  of secondary work mode. Rather, it is folded as special case
  into the regular dispatch.

This leads to new processing rules:
- a POST goes into λ-post (obviously... that's its meaning)
- a NOTIFY now passes its *target* into λ-post
- λ-post invokes ''dispatch''
- and **dispatching a Gate now implies to notify the Gate**

This greatly simplifies the »state machine« in the Activity-Language,
but also incurs some limitations (which seems adequate, since it is
now clear that we do not ''schedule'' or ''dispatch'' arbitrary
Activities — rather we'll do this only with POST and NOTIFY,
and all further processing happens by passing activation
along the chain, without involving the Scheduler)
This commit is contained in:
Fischlurch 2023-12-16 23:47:50 +01:00
parent 75b5eea2d3
commit 1cbb6b7371
8 changed files with 536 additions and 207 deletions

View file

@ -107,8 +107,8 @@ namespace gear {
+ util::toString(data_.timing.quality);
case NOTIFY:
return util::showAddr(data_.notification.target)
+ ", report="
+ util::toString(data_.notification.report);
+ ", timing:"
+ util::toString(Time{data_.notification.timing});
case GATE:
return "<"
+ util::toString(data_.condition.rest)

View file

@ -176,7 +176,7 @@ namespace gear {
REQUIRE (notificationSrc.is (Activity::NOTIFY));
setupGate();
gate_->incDependencies();
notificationSrc.setNotificationTarget (gate_);
notificationSrc.setNotificationTarget (gate_, Time{post_->data_.timeWindow.life});
return *this;
}

View file

@ -186,6 +186,8 @@ namespace gear {
, Time now
, void* executionCtx) =0;
virtual Time getDeadline() const =0;
virtual std::string
diagnostic() const
{
@ -204,8 +206,6 @@ namespace gear {
* The Execution Context need to be passed to any Activity _activation;_
* it provides the _bindings_ for functionality defined only on a conceptual
* level, and provided by an opaque implementation (actually the Scheduler)
* @remark `getWaitDelay` was once used for Gate, but is now an obscure
* fall-back for _other notifications_ (retained for future use)
*/
template<class EXE>
constexpr void
@ -216,7 +216,6 @@ namespace gear {
ASSERT_MEMBER_FUNCTOR (&EXE::done, void(Time, size_t));
ASSERT_MEMBER_FUNCTOR (&EXE::tick, Proc(Time));
ASSERT_MEMBER_FUNCTOR (&EXE::getWaitDelay, Offset());
ASSERT_MEMBER_FUNCTOR (&EXE::getSchedTime, Time());
}
@ -291,6 +290,7 @@ namespace gear {
bool isDead (Time now) const { return dead <= now;}
bool isHold () const { return rest > 0; }
bool isFree (Time now) const { return not (isHold() or isDead(now)); }
Time getDeadline() const { return Time{dead}; }
void incDependencies() { ++rest; }
Time
@ -320,7 +320,7 @@ namespace gear {
struct Notification
{
Activity* target;
size_t report;
Instant timing;
};
@ -367,10 +367,11 @@ namespace gear {
}
explicit
Activity (Activity* target) noexcept
Activity (Activity* target, Time limitWhen =Time::ANYTIME) noexcept
: Activity{NOTIFY}
{
data_.notification.target = target;
data_.notification.timing = limitWhen;
}
explicit
@ -424,13 +425,10 @@ namespace gear {
template<class EXE>
activity::Proc dispatch (Time now, EXE& executionCtx);
template<class EXE>
activity::Proc notify (Time now, EXE& executionCtx);
/* === special case access and manipulation === */
bool
is (Activity::Verb expectedVerb)
is (Activity::Verb expectedVerb) const
{
return expectedVerb == this->verb_;
}
@ -443,10 +441,11 @@ namespace gear {
}
void
setNotificationTarget (Activity* target)
setNotificationTarget (Activity* target, Time limitStart =Time::ANYTIME)
{
REQUIRE (is (NOTIFY));
data_.notification.target = target;
data_.notification.timing = limitStart;
}
Time
@ -532,15 +531,6 @@ namespace gear {
return activity::PASS;
}
template<class EXE>
activity::Proc
notifyTarget (Time now, EXE& executionCtx)
{
REQUIRE (NOTIFY == verb_);
REQUIRE (data_.notification.target);
return data_.notification.target->notify (now, executionCtx);
}
template<class EXE>
activity::Proc
checkGate (Time now, EXE&)
@ -554,9 +544,8 @@ namespace gear {
return activity::PASS;
}
template<class EXE>
activity::Proc
receiveGateNotification (Time now, EXE& executionCtx)
receiveGateNotification (Time now)
{
REQUIRE (GATE == verb_);
if (data_.condition.rest > 0)
@ -565,33 +554,39 @@ namespace gear {
// maybe the Gate has been opened by this notification?
if (data_.condition.isFree(now))
{//yes => activate gated chain but lock redundant invocations
Time dead = data_.condition.lockPermanently();
return postChain (now,dead, executionCtx);
data_.condition.lockPermanently();
return activity::PASS;
} }
return activity::PASS;
}
template<class EXE>
activity::Proc
dispatchSelf (Time when, Time dead, EXE& executionCtx)
{
return executionCtx.post (when, dead, this, executionCtx);
}
template<class EXE>
activity::Proc
dispatchSelfDelayed (Time now, Time dead, EXE& executionCtx)
{
dispatchSelf (now + executionCtx.getWaitDelay(), dead, executionCtx);
return activity::SKIP;
}
template<class EXE>
activity::Proc
postChain (Time when, Time dead, EXE& executionCtx)
postSelf (Time now, EXE& executionCtx)
{
REQUIRE (next);
return executionCtx.post (when, dead, next, executionCtx);
if (is(POST))
return executionCtx.post (Time{data_.timeWindow.life},Time{data_.timeWindow.dead}, this, executionCtx);
else
return executionCtx.post (now,Time::NEVER, this, executionCtx);
}
template<class EXE>
activity::Proc
postNotify (Time now, EXE& executionCtx)
{
REQUIRE (is(NOTIFY));
Activity* target = data_.notification.target;
REQUIRE (target);
REQUIRE (not target->is(HOOK) or target->data_.callback.hook);
Time startHint = target->is(GATE) or
target->is(HOOK)? Time{data_.notification.timing}
: now;
Time deadline = target->is(GATE)? target->data_.condition.getDeadline()
: target->is(HOOK)? target->data_.callback.hook->getDeadline()
: Time::NEVER;
// indirectly forward to Activity::dispatch()
return executionCtx.post (startHint,deadline, target, executionCtx);
}
template<class EXE>
@ -650,11 +645,11 @@ namespace gear {
case WORKSTOP:
return signalStop (now, executionCtx);
case NOTIFY:
return dispatch (now, executionCtx); //▷ special processing for the Notification
return postNotify (now, executionCtx);
case POST:
return postSelf (now, executionCtx);
case GATE:
return checkGate (now, executionCtx);
case POST:
return dispatchSelf (Time{data_.timeWindow.life},Time{data_.timeWindow.dead}, executionCtx);
case FEED:
return activity::PASS;
case HOOK:
@ -673,6 +668,11 @@ namespace gear {
* by invoking the `post`-λ on the \a executionCtx, or by _activating_
* a `POST`-Activity. Control flow passing here has acquired the `GroomingToken`
* and can thus assume single threaded execution until `WORKSTART`.
*
* Notably this entrance is used to implement _gating_ to wait for prerequisites;
* when a notification is passed to a `GATE`-Activity, the embedded counter is
* decremented; after all prerequisites are „checked off“ this way, the
* Activity-chain behind the Gate is activated.
* @param now the scheduler-time; assuming that a call through the `post`-λ will
* only be actually de-queued when scheduler-time equals the start time
* defined in the POST activity and passed through the `post`-λ as parameter.
@ -688,46 +688,18 @@ namespace gear {
activity::_verify_usable_as_ExecutionContext<EXE>();
switch (verb_) {
case NOTIFY:
return notifyTarget (now, executionCtx);
case POST:
case FEED: // signal just to proceed with next...
return activity::PASS;
case GATE:
return receiveGateNotification (now);
case HOOK:
return notifyHook (now, executionCtx);
default:
return activate (now, executionCtx);
}
}
/**
* Special operation to receive a message or trigger from some other Activity.
* Notably this is used to implement _gating_ to wait for prerequisites; when
* a notification is passed to a `GATE`-Activity, the embedded counter is
* decremented; after all prerequisites are „checked off“ this way, the
* Activity-chain behind the Gate is activated.
* @note this function is invoked from the context of the source, and
* thus any follow-up actions beyond that scope are re-POSTed,
* after possibly performing the GATE-check.
*/
template<class EXE>
activity::Proc
Activity::notify (Time now, EXE& executionCtx)
{
activity::_verify_usable_as_ExecutionContext<EXE>();
switch (verb_) {
case GATE:
return receiveGateNotification (now, executionCtx);
case HOOK:
return notifyHook (now, executionCtx);
case POST:
case FEED: // ▽▽▽▽▽ implies to use a deadline from the context
return postChain (now,Time::NEVER, executionCtx);
default:
return dispatchSelfDelayed (now,Time::NEVER, executionCtx);
} // Fallback: self-re-dispatch for async execution (-> getWaitDelay())
}
}} // namespace vault::gear
#endif /*SRC_VAULT_GEAR_ACTIVITY_H_*/

View file

@ -140,7 +140,6 @@ namespace gear {
const auto IDLE_WAIT = 20ms; ///< sleep-recheck cycle for workers deemed _idle_
const size_t DISMISS_CYCLES = 100; ///< number of wait cycles before an idle worker terminates completely
Offset POLL_WAIT_DELAY{FSecs(1,1000)}; ///< delay until re-evaluating after notification (obscure feature, retained for future use)
Offset DUTY_CYCLE_PERIOD{FSecs(1,20)}; ///< period of the regular scheduler »tick« for state maintenance.
Offset DUTY_CYCLE_TOLERANCE{FSecs(1,10)}; ///< maximum slip tolerated on duty-cycle start before triggering Scheduler-emergency
}
@ -559,12 +558,6 @@ namespace gear {
return activity::PASS;
}
Offset
getWaitDelay()
{
return POLL_WAIT_DELAY;
}
/** access high-resolution-clock, rounded to µ-Ticks */
Time
getSchedTime()

View file

@ -240,8 +240,8 @@ namespace test {
CHECK (detector.verifyInvocation(CTX_TICK).arg(t));
detector.incrementSeq();
ctx.tick.returning(activity::KILL);
CHECK (activity::KILL == ctx.tick(t));
ctx.tick.returning(activity::KICK);
CHECK (activity::KICK == ctx.tick(t));
CHECK (detector.verifyInvocation(CTX_TICK).timeArg(t));
CHECK (detector.verifyInvocation(CTX_WORK).timeArg(t)
@ -360,21 +360,28 @@ namespace test {
void
watch_notification()
{
Time tt{11,11}; // start time of the NOTIFY
Time ts{22,22}; // start time of the target-chain
Time td{33,33}; // deadline for the target-chain
ActivityDetector detector;
Activity chain;
Activity gate{1, Time{22,22}};
Activity gate{1, td};
gate.next = &chain;
Activity notification{&gate};
Activity notification{&gate, ts}; // note: follow-up start time `ts` injected here
CHECK (gate.data_.condition.rest == 1);
detector.insertActivationTap (notification.data_.notification.target);
Time tt{11,11};
notification.dispatch (tt, detector.executionCtx);
notification.activate (tt, detector.executionCtx); // dispatch time `tt` (is actually irrelevant here)
// activating the NOTIFY causes it to POST its target, thereby setting the deadline from the GATE
CHECK (detector.verifyInvocation("CTX-post").arg("22.022","33.033", "tap-GATE", "≺test::CTX≻"));
CHECK (detector.verifyInvocation("tap-GATE").arg("11.011 --notify-↯> Act(GATE")
.beforeInvocation("CTX-post").arg("11.011","22.022", "Act(TICK", "≺test::CTX≻"));
detector.incrementSeq();
// to see the effect of the instrumentation, we need to mimic the behaviour of λ-post,
// which is to call Activity::dispatch() on the given target
notification.data_.notification.target->dispatch (ts, detector.executionCtx); // note: using `ts` for the follow-up chain
CHECK (detector.verifyInvocation("tap-GATE").seq(1).arg("22.022 --notify-↯> Act(GATE"));
CHECK (gate.data_.condition.rest == 0);
}

View file

@ -102,6 +102,7 @@ namespace test {
using lib::time::FSecs;
using lib::time::Offset;
using lib::meta::RebindVariadic;
using util::unConst;
using util::isnil;
using std::forward;
using std::move;
@ -119,7 +120,6 @@ namespace test {
const string CTX_DONE{"CTX-done"};
const string CTX_TICK{"CTX-tick"};
Offset POLL_WAIT_DELAY{FSecs(1)};
Time SCHED_TIME_MARKER{555,5}; ///< marker value for "current scheduler time" used in tests
}
@ -355,61 +355,80 @@ namespace test {
{
Logger log_;
TimeVar invoked_{Time::ANYTIME};
Activity*
target()
{
return reinterpret_cast<Activity*> (data_.callback.arg);
}
Activity const*
target() const
{
return unConst(this)->target();
}
activity::Proc
activation ( Activity& thisHook
, Time now
, void* executionCtx) override
{
REQUIRE (thisHook.is (Activity::HOOK));
invoked_ = now;
if (data_.callback.arg == 0)
{// no adapted target; just record this activation
log_(util::toString(now) + " ⧐ ");
return activity::PASS;
}
else
{// forward activation to the adapted target Activity
Activity& target = *reinterpret_cast<Activity*> (data_.callback.arg);
auto ctx = *static_cast<FakeExecutionCtx*> (executionCtx);
log_(util::toString(now) + " ⧐ " + util::toString (target));
return target.activate (now, ctx);
}
}
{
REQUIRE (thisHook.is (Activity::HOOK));
invoked_ = now;
if (not target())
{// no adapted target; just record this activation
log_(util::toString(now) + " ⧐ ");
return activity::PASS;
}
else
{// forward activation to the adapted target Activity
auto ctx = *static_cast<FakeExecutionCtx*> (executionCtx);
log_(util::toString(now) + " ⧐ " + util::toString (*target()));
return target()->activate (now, ctx);
}
}
activity::Proc
notify ( Activity& thisHook
, Time now
, void* executionCtx) override
{
REQUIRE (thisHook.is (Activity::HOOK));
invoked_ = now;
if (data_.callback.arg == 0)
{// no adapted target; just record this notification
log_(util::toString(now) + " --notify-↯• ");
return activity::PASS;
}
else
{// forward notification-dispatch to the adapted target Activity
Activity& target = *reinterpret_cast<Activity*> (data_.callback.arg);
auto ctx = *static_cast<FakeExecutionCtx*> (executionCtx);
log_(util::toString(now) + " --notify-↯> " + util::toString (target));
return target.notify (now, ctx);
}
}
{
REQUIRE (thisHook.is (Activity::HOOK));
invoked_ = now;
if (not target())
{// no adapted target; just record this notification
log_(util::toString(now) + " --notify-↯• ");
return activity::PASS;
}
else
{// forward notification-dispatch to the adapted target Activity
auto ctx = *static_cast<FakeExecutionCtx*> (executionCtx);
log_(util::toString(now) + " --notify-↯> " + util::toString (*target()));
return target()->dispatch (now, ctx);
}
}
std::string
diagnostic() const override
{
return "Probe("+string{log_}+")";
}
Time
getDeadline() const override
{
if (target() and target()->is(Activity::GATE))
return target()->data_.condition.getDeadline();
else
return Time::NEVER;
}
std::string
diagnostic() const override
{
return "Probe("+string{log_}+")";
}
public:
ActivityProbe (string id, EventLog& masterLog, uint const& invocationSeqNr)
: Activity{*this, 0}
, log_{id, masterLog, invocationSeqNr}
{ }
ActivityProbe (Activity const& subject, string id, EventLog& masterLog, uint const& invocationSeqNr)
: Activity{*this, reinterpret_cast<size_t> (&subject)}
, log_{id, masterLog, invocationSeqNr}
@ -428,7 +447,7 @@ namespace test {
{
if (act and act->verb_ == HOOK)
{
ActivityProbe* probe = dynamic_cast<ActivityProbe*> (act->data_.callback.hook);
ActivityProbe* probe = dynamic_cast<ActivityProbe*> (act->data_.callback.hook);
if (probe)
return probe->invoked_;
}
@ -591,7 +610,6 @@ namespace test {
_DiagnosticFun<SIG_done>::Type done;
_DiagnosticFun<SIG_tick>::Type tick;
function<Offset()> getWaitDelay = [] { return POLL_WAIT_DELAY; };
function<Time()> getSchedTime = [this]{ return SCHED_TIME_MARKER;};
FakeExecutionCtx (ActivityDetector& detector)

View file

@ -60,11 +60,11 @@ namespace test {
verifyActivity_Post();
verifyActivity_Invoke();
verifyActivity_Notify_activate();
verifyActivity_Notify_dispatch();
verifyActivity_Notify();
verifyActivity_Gate_pass();
verifyActivity_Gate_dead();
verifyActivity_Gate_block();
verifyActivity_Gate_notify();
verifyActivity_Gate_opened();
termBuilder();
@ -157,16 +157,16 @@ namespace test {
/** @test behaviour of Activity::NOTIFY when _activated_
* - notification is dispatched as special message to an indicated target Activity
* - when activated, a `NOTIFY`-Activity _dispatches_ into the Activity::notify()
* of the target Activity
* - what happens then depends on the target
* - usually the target is a `GATE` (see below), but here for sake of simplicity,
* a `TICK`-Activity is used; on notification, this will _post_ itself as new task,
* with a delay retrieved from context (here configured to be +1sec), and without
* specifying a deadline (thus a deadline from the context will be used).
* - when activated, a `NOTIFY`-Activity invokes the λ-post _with its target,_
* - in the actual setup (Scheduler) this leads to [dispatching](\ref Activity::dispatch)
* of said target Activity
* - what happens then depends on the target; usually the target is a `GATE`
* - in first example here, we just use a `TICK`-Activity
* - for a `GATE` there is special treatment to inject the _timing window of the target_
* into the CTX-post invocation; this is essential to handle long notification-chains properly.
*/
void
verifyActivity_Notify_activate()
verifyActivity_Notify()
{
Activity chain;
Activity notify{&chain};
@ -174,27 +174,20 @@ namespace test {
ActivityDetector detector;
Time tt{111,11};
notify.activate (tt, detector.executionCtx);
CHECK (detector.verifyInvocation("CTX-post").arg("11.111", Time::NEVER, "Act(TICK", "≺test::CTX≻"));
CHECK (detector.verifyInvocation("CTX-post").arg("12.111", Time::NEVER, "Act(TICK", "≺test::CTX≻"));
}
/** @test behaviour of Activity::NOTIFY when activation leads to a _dispatch_
* - when _posting_ a `NOTIFY`, a dedicated _notification_ function is invoked on the chain
* - what actually happens then depends on the receiver; here we just activate a test-Tap
*/
void
verifyActivity_Notify_dispatch()
{
ActivityDetector detector;
// use a diagnostic Tap as chain to detect passing of notification
Activity notify{detector.buildActivationProbe("notifyTargetActivity")};
detector.incrementSeq();
// now we use a `GATE` as target
Time ts{333,33};
Time td{555,55};
Activity gate{1,td};
notify.data_.notification.target = &gate;
notify.data_.notification.timing = ts; // start time hint can be packaged into the notification
Time tt{111,11};
notify.dispatch (tt, detector.executionCtx);
CHECK (detector.verifyInvocation("notifyTargetActivity").arg("11.111"));
notify.activate (tt, detector.executionCtx);
CHECK (detector.verifySeqIncrement(1)
.beforeInvocation("CTX-post").arg("33.333", "55.555", "Act(GATE", "≺test::CTX≻"));
// NOTE: △△△ start △△△ deadline
}
@ -277,14 +270,39 @@ namespace test {
/** @test behaviour of Activity::GATE:
* - if it is _dispatched_ as new chain, instead of just _activating_
* it of part of an ongoing chain, the Gate will receive a *notification*
* - this results in _decrementing_ the prerequisite latch in the Gate
* - what happens then depends on current state; in this test case
* the Gate is decremented yet remains closed
*/
void
verifyActivity_Gate_notify()
{
Activity chain;
Activity gate{23};
gate.next = &chain;
ActivityDetector detector;
Activity& entrance = detector.buildGateWatcher (gate);
Time tt{333,33};
CHECK (activity::SKIP == entrance.dispatch (tt, detector.executionCtx));
CHECK (22 == gate.data_.condition.rest); // prerequisite-count decremented
CHECK (detector.verifyInvocation("tap-GATE").arg("33.333 --notify-↯> Act(GATE"));
}
/** @test behaviour of Activity::GATE on notification
* - Gate configured initially such that it blocks
* (without violating deadline)
* - thus a regular activation signals to skip the chain,
* but also re-schedules a further check into the future
* - thus a regular activation signals to skip the chain.
* - when receiving a notification, the latch is decremented
* - if this causes the Gate to open, the chain is immediately
* scheduled for activation, but the Gate also locked forever
* - if this causes the Gate to open, the follow-up chain will
* be activated immediately, but the Gate also locked forever
* - neither a further activation, nor a further notification
* has any effect after this point...
*/
@ -303,27 +321,26 @@ namespace test {
CHECK (gate.data_.condition.dead == td);
ActivityDetector detector;
Activity& wiring = detector.buildGateWatcher (gate);
Activity& entrance = detector.buildGateWatcher (gate);
// an attempt to activate blocks (returning SKIP, nothing else happens)
CHECK (activity::SKIP == wiring.activate (tt, detector.executionCtx));
CHECK (1 == gate.data_.condition.rest); // unchanged (and locked)...
CHECK (activity::SKIP == entrance.activate (tt, detector.executionCtx));
CHECK (1 == gate.data_.condition.rest); // unchanged (and locked)...
CHECK (detector.verifyInvocation("tap-GATE").arg("33.333 ⧐ Act(GATE"));
detector.incrementSeq();
// Gate receives a notification from some prerequisite Activity
CHECK (activity::PASS == wiring.notify(tt, detector.executionCtx));
CHECK (activity::PASS == entrance.dispatch(tt, detector.executionCtx));
CHECK (0 == gate.data_.condition.rest); // condition has been decremented...
CHECK (detector.verifyInvocation("tap-GATE").seq(0).arg("33.333 ⧐ Act(GATE")
.beforeInvocation("tap-GATE").seq(1).arg("33.333 --notify-↯> Act(GATE")
.beforeInvocation("CTX-post").seq(1).arg(tt,td, "after-GATE", "≺test::CTX≻"));
.beforeInvocation("tap-GATE").seq(1).arg("33.333 --notify-↯> Act(GATE"));
CHECK (gate.data_.condition.dead == Time::MIN);
detector.incrementSeq();
Time ttt{444,44};
// when another activation happens later, it is blocked to prevent double activation
CHECK (activity::SKIP == wiring.activate (ttt, detector.executionCtx));
CHECK (activity::SKIP == entrance.activate (ttt, detector.executionCtx));
CHECK (detector.verifyInvocation("tap-GATE").seq(2).arg("44.444 ⧐ Act(GATE"));
CHECK (detector.ensureNoInvocation("CTX-post").seq(2)
.afterInvocation("tap-GATE").seq(2));
@ -331,14 +348,13 @@ namespace test {
detector.incrementSeq();
// even a further notification has no effect now....
wiring.notify(ttt, detector.executionCtx);
CHECK (activity::SKIP == entrance.dispatch (ttt, detector.executionCtx));
// conditionals were not touched:
CHECK (gate.data_.condition.dead == Time::MIN);
CHECK (gate.data_.condition.rest == 0);
// the log shows the further notification (at Seq=3) but no dispatch happens anymore
CHECK (detector.verifySeqIncrement(3)
.beforeInvocation("tap-GATE").seq(3).arg("44.444 --notify-↯> Act(GATE"));
CHECK (detector.ensureNoInvocation("CTX-post").seq(3).arg(tt, "after-GATE", "≺test::CTX≻"));
// cout << detector.showLog()<<endl; // HINT: use this for investigation...
}
@ -435,15 +451,12 @@ namespace test {
.afterInvocation("Gate").seq(1));
detector.incrementSeq();
Activity notify{post.next}; // Notification via instrumented connection to the Gate
CHECK (activity::PASS == ActivityLang::dispatchChain (&notify, detector.executionCtx)); // dispatch a notification (case/seq == 2)
CHECK (detector.verifyInvocation("Gate") .seq(2).arg("1.011 --notify-↯> Act(GATE") // ...notification dispatched towards the Gate
.beforeInvocation("CTX-post").seq(2).arg("1.011","2.022","after-Gate","≺test::CTX≻")); // ...this opened the Gate and posted follow-up chain
CHECK (detector.ensureNoInvocation("after-Gate").seq(2) // verify that activation was not passed out directly
.afterInvocation("CTX-post").seq(2));
CHECK (detector.ensureNoInvocation("CTX-tick").seq(2) // verify also the λ-tick was not invoked directly
.afterInvocation("CTX-post").seq(2));
// Notification via instrumented connection to the Gate (activate(NOTIFY) -> λ-post(target) -> notify GATE
CHECK (activity::PASS == ActivityLang::dispatchChain (post.next, detector.executionCtx)); // dispatch a notification (case/seq == 2)
CHECK (0 == gate.data_.condition.rest); // Effect of the notification is to decrement the latch
CHECK (detector.verifyInvocation("Gate") .seq(2).arg("1.011 --notify-↯> Act(GATE") // ...notification dispatched towards the Gate
.beforeInvocation("after-Gate").seq(2).arg("1.011 ⧐ Act(TICK") // ...this opened the Gate, passing activation...
.beforeInvocation("CTX-tick") .seq(2).arg("1.011")); // ...to the chain, finally invoking λ-tick
}
@ -536,17 +549,15 @@ namespace test {
// rig the λ-post to forward dispatch as expected in real usage
detector.executionCtx.post.implementedAs(
[&](Time when, Time, Activity* postedAct, auto& ctx)
[&](Time, Time, Activity* postedAct, auto& ctx)
{
if (when == ctx.getSchedTime()) // only for POST to run „right now“
return ActivityLang::dispatchChain (postedAct, ctx);
else
return activity::PASS;
return ActivityLang::dispatchChain (postedAct, ctx);
});
///// Case-1 : send a notification from prerequisite, but prior to activating primary-chain
CHECK (activity::PASS == ActivityLang::dispatchChain (&trigger, detector.executionCtx));
CHECK (detector.verifyInvocation("trigger") .seq(0).arg("5.555 --notify-↯> Act(GATE") // notification dispatched to the Gate
CHECK (detector.verifyInvocation("CTX-post").seq(0).arg("01.000","10.000","trigger","≺test::CTX≻") // notification is POSTed (with time and deadline from target)
.beforeInvocation("trigger") .seq(0).arg("5.555 --notify-↯> Act(GATE") // notification dispatched to the Gate (note: now using curr-sched-time 5.555)
.arg("<2, until 0:00:10.000")); // Note: the Gate-latch expects 2 notifications
CHECK (detector.ensureNoInvocation("testJob") // ==> the latch was decremented but no invocation yet
.afterInvocation("trigger"));
@ -554,9 +565,9 @@ namespace test {
///// Case-2 : now activate the primary-chain
detector.incrementSeq();
CHECK (activity::PASS == ActivityLang::dispatchChain (&anchor, detector.executionCtx));
CHECK (detector.verifyInvocation("deBlock") .seq(1).arg("5.555 --notify-↯> Act(GATE") // immediately at begin, the internal self-notification is dispatched towards the Gate
.arg("<1, until 0:00:10.000") // Note: at this point, the Gate-latch expects 1 notifications
.beforeInvocation("CTX-post").seq(1).arg("5.555","10.0","after-theGate","≺test::CTX≻") //==> latch was decremented, Gate OPENS, posting the tail-chain with Deadline from Gate
CHECK (detector.verifyInvocation("CTX-post").seq(1).arg("01.000","10.000","deBlock","≺test::CTX≻") // at begin, the internal self-notification is POSTed (with time and deadline this chain)
.beforeInvocation("deBlock") .seq(1).arg("5.555 --notify-↯> Act(GATE") // and this call is immediately dispatched towards the Gate (using curr-sched-time 5.555)
.arg("<1, until 0:00:10.000") // Note: at this point, the Gate-latch expects 1 notifications ==> latch decremented, Gate OPENS
.beforeInvocation("after-theGate") .arg("5.555 ⧐ Act(WORKSTART") // ...causing the activation to pass behind the Gate
.beforeInvocation("CTX-work").seq(1).arg("5.555","") // ...through WORKSTART
.beforeInvocation("testJob") .seq(1).arg("7.007",12345) // ...then invoke the JobFunctor itself (with the nominal Time{7,7})
@ -568,8 +579,9 @@ namespace test {
detector.incrementSeq();
CHECK (activity::PASS == ActivityLang::dispatchChain (&trigger, detector.executionCtx)); // and any further external trigger is likewise blocked:
CHECK (detector.verifyInvocation("trigger") .seq(2).arg("5.555 --notify-↯> Act(GATE") // ... it reaches the Gate
.arg("<0, until -85401592:56:01.825")); // ... but the Gate has been closed permanently (by setting the deadline to Time::MIN)
CHECK (detector.verifyInvocation("CTX-post").seq(2).arg("01.000",Time::NEVER,"trigger","≺test::CTX≻") // notification is POSTed (in the real Scheduler the deadline will block already here)
.beforeInvocation("trigger") .seq(2).arg("5.555 --notify-↯> Act(GATE") // ... but even if it would reach the Gate...
.arg("<0, until -85401592:56:01.825")); // ... the Gate has been closed permanently (by setting the deadline to Time::MIN)
CHECK (detector.ensureNoInvocation("testJob") // ==> no further invocation
.afterInvocation("trigger").seq(2));
@ -618,6 +630,13 @@ namespace test {
CHECK (notify.next->data_.notification.target == followup.post().next); // was wired to the GATE of the follow-up activity Term
CHECK (followup.post().next->is (Activity::GATE));
// rig the λ-post to forward dispatch as expected in real usage
detector.executionCtx.post.implementedAs(
[&](Time, Time, Activity* postedAct, auto& ctx)
{
return ActivityLang::dispatchChain (postedAct, ctx);
});
///// Case-1 : trigger off the async IO job
CHECK (activity::PASS == ActivityLang::dispatchChain (&anchor, detector.executionCtx));
@ -631,7 +650,10 @@ namespace test {
detector.incrementSeq();
CHECK (activity::PASS == ActivityLang::dispatchChain (&notify, detector.executionCtx));
CHECK (detector.verifyInvocation("CTX-done").seq(1).arg("5.555", "") // activation of WORKSTOP via callback
.beforeInvocation("CTX-post").seq(1).arg("5.555","10.0","WORKSTART","≺test::CTX≻"));// the attached chain is activated, POSTing the second Activity
.beforeInvocation("CTX-post").seq(1).arg("01.00","10.00","GATE","≺test::CTX≻") // the notification posts the GATE of the follow-up chain
.beforeInvocation("CTX-work").seq(1).arg("5.555", "") // GATE passes -> activation of the follow-up work commences
.beforeInvocation("calcJob") .seq(1)
.beforeInvocation("CTX-done").seq(1).arg("5.555", ""));
}

View file

@ -80833,7 +80833,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<arrowlink COLOR="#e3fddf" DESTINATION="ID_229335349" ENDARROW="Default" ENDINCLINATION="46;-190;" ID="Arrow_ID_382638651" STARTARROW="None" STARTINCLINATION="-301;39;"/>
<linktarget COLOR="#dae9fa" DESTINATION="ID_1532008023" ENDARROW="Default" ENDINCLINATION="-184;505;" ID="Arrow_ID_61418953" SOURCE="ID_1073489318" STARTARROW="None" STARTINCLINATION="630;34;"/>
<node CREATED="1690069222750" ID="ID_276634248" MODIFIED="1690494867733" TEXT="&#x3bb;-post">
<node CREATED="1690736737684" FOLDED="true" ID="ID_1359419273" MODIFIED="1697930193115" TEXT="(Time, Activity, ExecutionCtx) &#x27fc; activity::Proc">
<node CREATED="1690736737684" FOLDED="true" ID="ID_1359419273" MODIFIED="1702599896296" TEXT="(Time,Time, Activity, ExecutionCtx) &#x27fc; activity::Proc">
<node COLOR="#435e98" CREATED="1697929874025" ID="ID_1875907326" MODIFIED="1697930180261" TEXT="warum hier der ExecutionCtx (nochmal) als Argument?">
<linktarget COLOR="#87a6b3" DESTINATION="ID_1875907326" ENDARROW="Default" ENDINCLINATION="543;939;" ID="Arrow_ID_1742040512" SOURCE="ID_1585090015" STARTARROW="None" STARTINCLINATION="271;21;"/>
<font NAME="SansSerif" SIZE="11"/>
@ -80982,7 +80982,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="ksmiletris"/>
</node>
</node>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1693316943383" FOLDED="true" ID="ID_816321833" MODIFIED="1702432330779" TEXT="Redundanz in den Deadline-Angaben">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1693316943383" FOLDED="true" ID="ID_816321833" MODIFIED="1702599768360" TEXT="Redundanz in den Deadline-Angaben">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -81267,9 +81267,138 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node COLOR="#338800" CREATED="1702440166840" ID="ID_880220704" MODIFIED="1702441899698" TEXT="stattdessen direkt NOTIFY.activate() &#x27f6; dispatch gehen">
<arrowlink COLOR="#72949f" DESTINATION="ID_1566309423" ENDARROW="Default" ENDINCLINATION="169;0;" ID="Arrow_ID_942543086" STARTARROW="None" STARTINCLINATION="184;9;"/>
<arrowlink COLOR="#85c5af" DESTINATION="ID_1861186167" ENDARROW="Default" ENDINCLINATION="683;22;" ID="Arrow_ID_1560412883" STARTARROW="None" STARTINCLINATION="275;13;"/>
<arrowlink COLOR="#85c5af" DESTINATION="ID_1861186167" ENDARROW="Default" ENDINCLINATION="683;22;" ID="Arrow_ID_1560412883" STARTARROW="None" STARTINCLINATION="539;27;"/>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1702577370950" ID="ID_650472693" MODIFIED="1702600287956" TEXT="Fehler in der Vereinfachung: Concurrency &#xfc;bersehen">
<arrowlink COLOR="#5b2e58" DESTINATION="ID_1696260440" ENDARROW="Default" ENDINCLINATION="664;-27;" ID="Arrow_ID_1904329782" STARTARROW="None" STARTINCLINATION="420;245;"/>
<linktarget COLOR="#ad0013" DESTINATION="ID_650472693" ENDARROW="Default" ENDINCLINATION="-796;37;" ID="Arrow_ID_1470263046" SOURCE="ID_599055156" STARTARROW="None" STARTINCLINATION="193;-386;"/>
<icon BUILTIN="broken-line"/>
<node CREATED="1702577545878" ID="ID_1574266507" MODIFIED="1702577600295">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
<i>vor </i>dem Zugang zum <font face="Monospaced" color="#542418">GATE</font>&#160;mu&#223; das <b>Grooming-Token</b>&#160; erlangt werden
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1702577675716" ID="ID_427980935" MODIFIED="1702577682880" TEXT="Daten&#xe4;nderung: count-down-Latch"/>
<node CREATED="1702577684769" ID="ID_1888418957" MODIFIED="1702577707778" TEXT="k&#xf6;nnte theoretisch zu Fehlentscheidungen wegen (un)Sichtbarkeit f&#xfc;hren">
<icon BUILTIN="clanbomber"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1702577718673" ID="ID_401029061" MODIFIED="1702577764896" TEXT="&#x21af; widerspricht dem Prinzip: Ablaufsteuerung nur im &#xbb;management-Modus&#xab;"/>
</node>
<node CREATED="1702577613141" ID="ID_1657872854" MODIFIED="1702577648692" TEXT="(im R&#xfc;ckblick k&#xf6;nnte das der Grund f&#xfc;r die doppelte Indirektion durch &#x3bb;-post gewesen sein)">
<icon BUILTIN="idea"/>
</node>
<node COLOR="#5b280f" CREATED="1702602291539" ID="ID_1914905944" MODIFIED="1702602435718">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
zweimaliger &#955;-post w&#228;re die <b>sauberste L&#246;sung</b>&#160;&#8212; bedingt aber inakzeptablen <b>Overhead</b>
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="closed"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1702602438725" ID="ID_1887124069" MODIFIED="1702602464551" TEXT="in einen &#x3bb;-post kombinieren">
<icon BUILTIN="yes"/>
<node CREATED="1702602467423" ID="ID_975246504" MODIFIED="1702602501393" TEXT="die Platzierung dieses Aufrufs ist limitiert">
<node CREATED="1702602502495" ID="ID_1400223035" MODIFIED="1702602543154" TEXT="es mu&#xdf; die &#xbb;Markierung&#xab; als NOTIFY mitgegeben werden"/>
<node CREATED="1702602544283" ID="ID_1348984098" MODIFIED="1702602559537" TEXT="im Grunde w&#xfc;rden wir zwei verschiedene &#x3bb;-Eing&#xe4;nge brauchen"/>
<node CREATED="1702603270638" ID="ID_1296023821" MODIFIED="1702603278030" TEXT="allerdings nur f&#xfc;r GATE und HOOK">
<node CREATED="1702604288353" ID="ID_683517628" MODIFIED="1702604315094" TEXT="formal ist es ein double-dispatch &#x2014; der aber nur in wenigen F&#xe4;llen auftritt"/>
<node CREATED="1702604317714" ID="ID_1505479076" MODIFIED="1702604338195" TEXT="man k&#xf6;nnte diese F&#xe4;lle in die Bedeutung von &#xbb;POST&#xab; einfalten">
<node CREATED="1702604346422" ID="ID_612274060" MODIFIED="1702604353025" TEXT="weil es zu keiner Kollision kommt"/>
<node CREATED="1702604353791" ID="ID_245763948" MODIFIED="1702604365437" TEXT="weil die meisten Activities gar nicht gePOSTet werden"/>
<node CREATED="1702604396352" ID="ID_1049603188" MODIFIED="1702604429647" TEXT="weil &#x3bb;-post selber den Charakter des &#xbb;Signalisierens&#xab; hat"/>
</node>
<node CREATED="1702605173602" ID="ID_1094490055" MODIFIED="1702605309570" TEXT="hab dabei aber ein schlechtes Gef&#xfc;hl">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node>
</node>
</node>
<node CREATED="1702604567601" ID="ID_1021845654" MODIFIED="1702604585404" TEXT="Zugang zum Timing-Window ist ebenfalls problematisch">
<node CREATED="1702604659955" ID="ID_1418126303" MODIFIED="1702604683978" TEXT="weil diese Info auf Activity-Ebene meist nicht vorliegt"/>
<node CREATED="1702604989888" ID="ID_147783305" MODIFIED="1702605023744" TEXT="auch aus Platzgr&#xfc;nden">
<node CREATED="1702605024836" ID="ID_1727350374" MODIFIED="1702605026331" TEXT="sie wird nur zum Scheduling gebraucht"/>
<node CREATED="1702605027180" ID="ID_891601423" MODIFIED="1702605038563" TEXT="Scheduling hat inzwischen seine eigene Datenstruktur"/>
<node CREATED="1702605039282" ID="ID_892450996" MODIFIED="1702605051735" TEXT="Activity beschreibt Ausf&#xfc;hrungs-Logik"/>
</node>
<node CREATED="1702605512819" ID="ID_1007164080" MODIFIED="1702605584773" TEXT="im NOTIFY-Fall mu&#xdf; man einen Kniff anwenden">
<node CREATED="1702605614645" ID="ID_404496788" MODIFIED="1702605631111" TEXT="ein Hint auf den Zeitpunkt k&#xf6;nnte im NOTIFY untergebracht werden"/>
<node CREATED="1702605632651" ID="ID_559967093" MODIFIED="1702605644853" TEXT="eine spezielle Deadline kann man dem GATE entnehmen"/>
</node>
</node>
<node CREATED="1702605660894" ID="ID_1205243179" MODIFIED="1702605670658" TEXT="damit zeichnet sich folgende L&#xf6;sung ab....">
<node CREATED="1702605687260" ID="ID_1998074267" MODIFIED="1702605713588" TEXT="ein &#xbb;POST-from-Activity&#xab; mu&#xdf; stets eigens vorbereitet werden"/>
<node CREATED="1702605748956" ID="ID_812540974" MODIFIED="1702605764921" TEXT="die angezeigte Traget-Activity bestimmt was geschieht">
<node CREATED="1702605766273" ID="ID_1665629824" MODIFIED="1702605779451" TEXT="POST &#x27f6; activate chain"/>
<node CREATED="1702605840622" ID="ID_1623162924" MODIFIED="1702605857560" TEXT="GATE &#x27f6; notifyGate"/>
<node CREATED="1702605863196" ID="ID_1280842359" MODIFIED="1702605869407" TEXT="HOOK &#x27f6; notifyHook"/>
<node CREATED="1702605875634" ID="ID_1029394228" MODIFIED="1702605925638" TEXT="else &#x27f6; activate"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1702610771036" ID="ID_785523016" MODIFIED="1702610777206" TEXT="TODO: offen">
<icon BUILTIN="flag-pink"/>
<node CREATED="1702610778957" ID="ID_1196414966" MODIFIED="1702610785877" TEXT="der Umgang mit dem Hook">
<node CREATED="1702767308131" ID="ID_931273066" MODIFIED="1702767330240" TEXT="das ist ein &#xbb;Lackmus-Test&#xab; f&#xfc;r das Design..."/>
<node CREATED="1702767352010" ID="ID_1029846387" MODIFIED="1702767369837">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
wie gut ist es <i>self-composable?</i>
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1702767461236" ID="ID_1489450472" MODIFIED="1702767480525" TEXT="der Hook soll offen bleiben und verschiedenenen Zwecken dienen k&#xf6;nnen">
<node CREATED="1702767481917" ID="ID_1061078866" MODIFIED="1702767495875" TEXT="ein konkret bekannter Zweck: Instrumentierung"/>
<node CREATED="1702767496655" ID="ID_229116438" MODIFIED="1702767548514">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
aber der Hook kann auch die Rolle jedes<i>&#160;activate/notify </i>&#252;bernehmen
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node CREATED="1702767586803" ID="ID_737616449" MODIFIED="1702767614579" TEXT="&#x27f9; Schlu&#xdf;folgerung: f&#xfc;r &#xbb;notify&#xab; braucht es eine Vorab-Kanal: getDeadline()"/>
</node>
<node COLOR="#5b280f" CREATED="1702610797904" ID="ID_1129530768" MODIFIED="1702767389086" TEXT="kann in dem Fall nicht die Startzeit durchreichen">
<icon BUILTIN="button_cancel"/>
<node CREATED="1702767404708" ID="ID_1124188477" MODIFIED="1702767409584" TEXT="warum nicht?"/>
<node CREATED="1702767411220" ID="ID_1325784626" MODIFIED="1702767417625" TEXT="springt nichts dagegen"/>
<node CREATED="1702767433823" ID="ID_805853765" MODIFIED="1702767454074" TEXT="Hook bekommt ja die gew&#xe4;hlte Zeit &#x201e;in die Hand&#x201c;"/>
</node>
<node CREATED="1702610969672" ID="ID_1632101586" MODIFIED="1702610978779" TEXT="ansonsten &quot;sollte&quot; es schon fertig sein...">
<node CREATED="1702610981163" ID="ID_1295589775" MODIFIED="1702610990648" TEXT="is eigentlich einfacher geworden"/>
<node CREATED="1702610991285" ID="ID_967899840" MODIFIED="1702611000392" TEXT="bis auf die Asymertrien">
<node CREATED="1702611001140" ID="ID_1030909980" MODIFIED="1702611004224" TEXT="mit dem TimeWindow"/>
<node CREATED="1702611004693" ID="ID_648606411" MODIFIED="1702611007201" TEXT="mit dem Hook"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
<node CREATED="1702438679407" ID="ID_1796428489" MODIFIED="1702440355290" TEXT="semantisch">
@ -81499,6 +81628,11 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1690495433254" ID="ID_1805822057" MODIFIED="1692569069328" TEXT="aus Konsistenz-Gr&#xfc;nden indirekter Dispatch (u.U asynchron)">
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1702599990156" ID="ID_1696260440" MODIFIED="1702600277173" TEXT="re-scheduling: Zeitpunkt und Deadline gem&#xe4;&#xdf; NOTIFY-target setzen">
<linktarget COLOR="#a3385d" DESTINATION="ID_1696260440" ENDARROW="Default" ENDINCLINATION="-1273;54;" ID="Arrow_ID_458002858" SOURCE="ID_226925697" STARTARROW="None" STARTINCLINATION="-900;-46;"/>
<linktarget COLOR="#5b2e58" DESTINATION="ID_1696260440" ENDARROW="Default" ENDINCLINATION="664;-27;" ID="Arrow_ID_1904329782" SOURCE="ID_650472693" STARTARROW="None" STARTINCLINATION="420;245;"/>
<icon BUILTIN="flag-yellow"/>
</node>
<node CREATED="1690069846556" ID="ID_681493814" MODIFIED="1690495242907" TEXT="&#x3bb;-post">
<arrowlink COLOR="#8897a9" DESTINATION="ID_817512371" ENDARROW="Default" ENDINCLINATION="-175;61;" ID="Arrow_ID_847368059" STARTARROW="None" STARTINCLINATION="-262;0;"/>
</node>
@ -85461,7 +85595,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="idea"/>
</node>
</node>
<node COLOR="#338800" CREATED="1697982818498" FOLDED="true" ID="ID_136482882" MODIFIED="1702431643920" TEXT="Deadline ber&#xfc;cksichtigen ">
<node COLOR="#338800" CREATED="1697982818498" FOLDED="true" ID="ID_136482882" MODIFIED="1702599821631" TEXT="Deadline ber&#xfc;cksichtigen ">
<linktarget COLOR="#47a6ef" DESTINATION="ID_136482882" ENDARROW="Default" ENDINCLINATION="69;-169;" ID="Arrow_ID_63115321" SOURCE="ID_337384722" STARTARROW="None" STARTINCLINATION="-285;-30;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1697982844409" ID="ID_1374530988" MODIFIED="1697982854041" TEXT="im Datenrecord mitf&#xfc;hren"/>
@ -103270,8 +103404,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node COLOR="#435e98" CREATED="1702441785767" ID="ID_720337177" MODIFIED="1702495206270" TEXT="Ma&#xdf;nahmen">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="forward"/>
<node COLOR="#338800" CREATED="1702441683718" ID="ID_1861186167" MODIFIED="1702443370493" TEXT="Vereinfachung in der Sprachauswertung beseitigt viele redundante &#x3bb;-post">
<linktarget COLOR="#85c5af" DESTINATION="ID_1861186167" ENDARROW="Default" ENDINCLINATION="683;22;" ID="Arrow_ID_1560412883" SOURCE="ID_880220704" STARTARROW="None" STARTINCLINATION="275;13;"/>
<node COLOR="#338800" CREATED="1702441683718" ID="ID_1861186167" MODIFIED="1702577486299" TEXT="Vereinfachung in der Sprachauswertung beseitigt viele redundante &#x3bb;-post">
<arrowlink COLOR="#ac316f" DESTINATION="ID_1174594521" ENDARROW="Default" ENDINCLINATION="-475;-22;" ID="Arrow_ID_358088244" STARTARROW="None" STARTINCLINATION="-246;9;"/>
<linktarget COLOR="#85c5af" DESTINATION="ID_1861186167" ENDARROW="Default" ENDINCLINATION="683;22;" ID="Arrow_ID_1560412883" SOURCE="ID_880220704" STARTARROW="None" STARTINCLINATION="539;27;"/>
<linktarget COLOR="#51a8aa" DESTINATION="ID_1861186167" ENDARROW="Default" ENDINCLINATION="358;14;" ID="Arrow_ID_926842783" SOURCE="ID_1209140162" STARTARROW="None" STARTINCLINATION="-197;8;"/>
<icon BUILTIN="button_ok"/>
</node>
@ -103423,7 +103558,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node COLOR="#338800" CREATED="1702524831355" ID="ID_369134711" MODIFIED="1702524854572" TEXT="bestehende Funktionalit&#xe4;t vom Activity-Term herausgef&#xfc;hrt">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1702524859081" ID="ID_203571442" MODIFIED="1702524877503" TEXT="Test &#x2014; wirksam?">
<node COLOR="#435e98" CREATED="1702524859081" ID="ID_203571442" MODIFIED="1702589541901" TEXT="Test &#x2014; wirksam?">
<icon BUILTIN="help"/>
<node CREATED="1702525345416" ID="ID_392109929" MODIFIED="1702525366979" TEXT="ja .... denke schon">
<icon BUILTIN="smiley-oh"/>
@ -103440,8 +103575,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
die von einem einzigen Worker durchgearbeietet werden
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1702525401353" ID="ID_1274653458" MODIFIED="1702525416941" TEXT="die meisten Invocations passieren jetzt nahe / kurz nach der nominellen Zeit"/>
<node CREATED="1702525417791" ID="ID_917292675" MODIFIED="1702525427159" TEXT="viel mehr Wechsel zwischen den Workern"/>
@ -103455,10 +103589,193 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
w&#228;re ja so zu erwarten gem&#228;&#223; Topologie...
</p>
</body>
</html></richcontent>
</node>
</node>
<node CREATED="1702574866457" ID="ID_124353574" MODIFIED="1702574886053" TEXT="dieser Graph ist kein gutes Beispiel">
<node CREATED="1702574888411" ID="ID_197928028" MODIFIED="1702574896469" TEXT="er hat &#xbb;Knoten&#xab; am Ende"/>
<node CREATED="1702574904784" ID="ID_1387954804" MODIFIED="1702576637786" TEXT="eine Ketten-Berechnung ganz am Ende ist unvermeidbar">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
weil es stets ein <i>letztes Prerequisite </i>gibt, das dann die ganze Lawine an Berechnungen lostritt; der relevante Knoten ist Node-Nr.34(L20) &#8212; und die wiederum hat drei Vorl&#228;ufer-Ketten der L&#228;nge 2, d.h. der <i>finale Trigger liegt auf Level 18 oder gar 17.</i>
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node COLOR="#5b280f" CREATED="1702576639336" ID="ID_1556246282" MODIFIED="1702578705819" TEXT="auff&#xe4;llig: &#xbb;schwere&#xab; Knoten laufen excessiv lang">
<icon BUILTIN="button_cancel"/>
<node CREATED="1702576685969" ID="ID_1582564429" MODIFIED="1702576695636" TEXT="habe jetzt vier Beispiele gesehen"/>
<node CREATED="1702576696354" ID="ID_1866923525" MODIFIED="1702576718501" TEXT="Node hatte jeweils weight=3 und war ein &#xbb;Knoten&#xab;"/>
<node CREATED="1702576720420" ID="ID_426903156" MODIFIED="1702576797497" TEXT="Laufzeit war etwa doppelt so lang wie erwartet">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
~3ms &#8212; aber 3&#183;400&#181;s &#8776; 1.5ms + 100&#181;s h&#228;tte ich erwartet
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1702577920263" ID="ID_360094217" MODIFIED="1702577924991" TEXT="weitere Beobachtungen">
<node CREATED="1702577926003" ID="ID_1121143187" MODIFIED="1702578005428" TEXT="Node-62: Gewicht&#x2261;0 aber starker Fan-In &#x27f6; unauff&#xe4;llig (100&#xb5;s)"/>
<node CREATED="1702578258486" ID="ID_1691270037" MODIFIED="1702578648844" TEXT="Node-38: Gewicht&#x2261;3 aber starker Fan-Out&#x2261;4&#xa0;&#x27f6; unauff&#xe4;llig&#xa0; (1.5ms)"/>
<node CREATED="1702578652335" ID="ID_980355200" MODIFIED="1702578670131" TEXT="Node-40: analog und &#xa0;&#x27f6; unauff&#xe4;llig&#xa0; (1.5ms)"/>
<node CREATED="1702579171582" ID="ID_830629839" MODIFIED="1702579251909" TEXT="Kette 23&#x27f6;24&#x27f6;29: Gewicht&#x2261;5 &#xd83e;&#xdc32; auff&#xe4;llig (4ms statt 2.5)"/>
</node>
<node COLOR="#5b280f" CREATED="1702578681160" ID="ID_969532050" MODIFIED="1702578700935" TEXT="inkonclusiv">
<icon BUILTIN="yes"/>
</node>
<node COLOR="#435e98" CREATED="1702579291988" ID="ID_1769177398" MODIFIED="1702589548348" TEXT="unklar: wo steckt da die Zeit?">
<icon BUILTIN="help"/>
<node CREATED="1702579936527" ID="ID_936172430" MODIFIED="1702579954285" TEXT="weiterer Lauf mit Zeit-Log im invoke..."/>
<node CREATED="1702579958724" ID="ID_201523785" MODIFIED="1702580074488" TEXT="Node-62: 25&#xb5;s in Node + 25&#xb5;s bis POST"/>
<node CREATED="1702580218401" ID="ID_375694770" MODIFIED="1702580241884" TEXT="Node-38: 1.5ms iN + 35 bis POST"/>
<node CREATED="1702580277764" ID="ID_1085217550" MODIFIED="1702580403446" TEXT="Node-40: 1.4ms +38&#xb5;s"/>
<node CREATED="1702580405587" ID="ID_1590478428" MODIFIED="1702581627794" TEXT="Node-23: 1.8ms + 31&#xb5;s &#xd83e;&#xdc32; leicht auff&#xe4;llig"/>
<node CREATED="1702580751786" ID="ID_1360589841" MODIFIED="1702580766927" TEXT="Node-24: 27&#xb5;s + 27&#xb5;s"/>
<node CREATED="1702580859812" ID="ID_1310894097" MODIFIED="1702581638456" TEXT="Node-29: 1.26ms +33&#xb5;s (weight&#x2261;2) &#xd83e;&#xdc32; leicht auff&#xe4;llig"/>
<node CREATED="1702581052260" ID="ID_1861306020" MODIFIED="1702581098265" TEXT="Kette zusammen 3.2ms"/>
<node CREATED="1702581424784" ID="ID_429500585" MODIFIED="1702581651798" TEXT="Node-34: 2ms +10&#xb5;s in + 10&#xb5;s out &#xd83e;&#xdc32; auff&#xe4;llig"/>
<node CREATED="1702582029351" ID="ID_306805740" MODIFIED="1702582106370" TEXT="Node-19: 3ms +30&#xb5;s in + 29&#xb5;s out &#xd83e;&#xdc32; stark auff&#xe4;llig (weight&#x2261;2)"/>
<node CREATED="1702582314449" ID="ID_1060550440" MODIFIED="1702582349376" TEXT="Node-20: 2ms +26&#xb5;s in + 120&#xb5;s out &#xd83e;&#xdc32; interessant auff&#xe4;llig"/>
<node CREATED="1702582817918" ID="ID_208903662" MODIFIED="1702582844319" TEXT="Node-15: 1.5ms aber (weight&#x2261;1) &#xd83e;&#xdc32; stark auff&#xe4;llig"/>
<node CREATED="1702581133914" HGAP="-6" ID="ID_26188132" MODIFIED="1702581161202" TEXT="Fazit" VSHIFT="8">
<icon BUILTIN="forward"/>
<node CREATED="1702581142071" ID="ID_1009579756" MODIFIED="1702581528026" TEXT="unklar">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
bei genauerer Betrachtung l&#246;st sich die Feststellung auf....
</p>
<p>
ja, irgendwo geht hier Zeit verloren, aber im 2.Lauf ist alles nicht so stark ausgepr&#228;gt
</p>
</body>
</html>
</richcontent>
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node>
<node CREATED="1702581144757" ID="ID_481007131" MODIFIED="1702581589603" TEXT="vermutlich im CPU-Load">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
im 2.Lauf mit genauerer Instrumentierung sind die auff&#228;lligen Abweichungen <i>innerhalb</i>&#160;der Node-Invocation, nicht im administrativen Teil
</p>
</body>
</html>
</richcontent>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1702576822348" ID="ID_403805566" MODIFIED="1702577266690">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
beim Durchdenken nebenbei aufgefallen:<i>&#160;unprotected concurrenct acccess</i>
</p>
</body>
</html>
</richcontent>
<arrowlink COLOR="#fd3f95" DESTINATION="ID_8315180" ENDARROW="Default" ENDINCLINATION="28;-93;" ID="Arrow_ID_229684447" STARTARROW="None" STARTINCLINATION="-396;15;"/>
<icon BUILTIN="broken-line"/>
</node>
</node>
<node COLOR="#338800" CREATED="1702589592702" ID="ID_1170956866" MODIFIED="1702589611834" TEXT="best&#xe4;tigt: im entscheidenden Abschnitt wird parallelisiert">
<icon BUILTIN="button_ok"/>
<node CREATED="1702589617758" ID="ID_1138924507" MODIFIED="1702589627221" TEXT="damit ist das wichtigste Ziel erreicht"/>
<node CREATED="1702589628097" ID="ID_1191934434" MODIFIED="1702589750209" TEXT="das Durchmarschieren nutzt n&#xe4;mlich die Ressourcen nicht effizient">
<arrowlink DESTINATION="ID_1865116529" ENDARROW="Default" ENDINCLINATION="120;0;" ID="Arrow_ID_1653871320" STARTARROW="None" STARTINCLINATION="120;0;"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1702589556547" ID="ID_1028242300" MODIFIED="1702589671064" TEXT="Beobachtung: Priorit&#xe4;ten werden effektiv falsch gesetzt">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1702589690943" ID="ID_21620276" MODIFIED="1702589708900" TEXT="Falls eine Continuation re-scheduled wird">
<icon BUILTIN="info"/>
<node CREATED="1702589717677" ID="ID_1865116529" MODIFIED="1702589750209" TEXT="sofern eine Kette durchl&#xe4;uft, ist sie (nun garantiert) im Verzug">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_1865116529" ENDARROW="Default" ENDINCLINATION="120;0;" ID="Arrow_ID_1653871320" SOURCE="ID_1191934434" STARTARROW="None" STARTINCLINATION="120;0;"/>
</node>
<node CREATED="1702589757128" ID="ID_1991098320" MODIFIED="1702589773548" TEXT="wenn sie dabei aber wegen Contention unterbrochen wird...."/>
<node CREATED="1702589774357" ID="ID_450376387" MODIFIED="1702589788431" TEXT="dann reiht sie sich in die aktuelle (versp&#xe4;tete) Zeit ein"/>
<node CREATED="1702589808425" ID="ID_1970025813" MODIFIED="1702589824394" TEXT="und wartet erst mal die Folgen des aktuellen Levels ab"/>
<node CREATED="1702589825360" ID="ID_1200779225" MODIFIED="1702589854771" TEXT="...welche aber schlimmstenfalls indirekt auf die versp&#xe4;tete Kette angewiesen w&#xe4;ren"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1702589992304" ID="ID_463167560" MODIFIED="1702590019098" TEXT="das hat strukturelle &#xc4;hnlichkeit mit einer Priority-Inversion">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1702590023012" ID="ID_1246665906" MODIFIED="1702590120782" TEXT="...diese kann bei unserem Ansatz direkt nicht auftreten">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...weil wir Priorit&#228;ten gar nicht auf der Ebene des Schedulers repr&#228;sentieren, sondern in den &#252;bergreifenden Plan einarbeiten k&#246;nnen; der Scheduler mu&#223; also nur im Bezug auf diesen Plan priorisieren
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1702590037058" ID="ID_1545617475" MODIFIED="1702590283499" TEXT="...aber aus logischen Gr&#xfc;nden sollte die zugrundeliegende Struktur sich irgendwo zeigen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...denn diese zugrundeliegende Struktur ist durch einen vorgelagerten Plan grunds&#228;tzlich nicht aus der Welt zu schaffen, denn es geht dabei um eine Diskrepanz zwischen einer plan&#228;&#223;igen Codifizierung der Priorit&#228;t und einer <i>real (sachbezogen) gegebenen </i>Priorit&#228;t
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node CREATED="1702589858274" ID="ID_226925697" MODIFIED="1702600233715" TEXT="Korrekt w&#xe4;re: Scheduing mit der Zeit des Notification-Empf&#xe4;ngers">
<arrowlink COLOR="#a3385d" DESTINATION="ID_1696260440" ENDARROW="Default" ENDINCLINATION="-1273;54;" ID="Arrow_ID_458002858" STARTARROW="None" STARTINCLINATION="-900;-46;"/>
<icon BUILTIN="idea"/>
<node CREATED="1702589914451" ID="ID_765655284" MODIFIED="1702589946767" TEXT="denn nur dadurch w&#xfc;rde der Sinn des &#x3bb;-post realisiert"/>
<node CREATED="1702589956149" ID="ID_181976158" MODIFIED="1702589979157" TEXT="wenn der Empf&#xe4;nger bereits f&#xe4;llig w&#xe4;re, dann sollte die Notification Vorrang bekommen"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1702576882672" ID="ID_8315180" MODIFIED="1702577283363" TEXT="Bugfix: concurrency f&#xfc;r vereinfachtes NOTIFY">
<linktarget COLOR="#fd3f95" DESTINATION="ID_8315180" ENDARROW="Default" ENDINCLINATION="28;-93;" ID="Arrow_ID_229684447" SOURCE="ID_403805566" STARTARROW="None" STARTINCLINATION="-396;15;"/>
<icon BUILTIN="broken-line"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1702576947842" ID="ID_1174594521" LINK="#ID_1805822057" MODIFIED="1702600107582" TEXT="hab bei meinen Vereinfachungen vorgestern die Concurrency &#xfc;bersehen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...ich hatte dabei ein ungutes Gef&#252;hl, weil ich mir nicht erkl&#228;ren konnte, warum um urspr&#252;nglichen Code diese doppelte Indirektion drinnen war; hab das dann vom Tisch gewischt mit der Vermutung, es sei aus formalen Gr&#252;nden eingebaut. Jetzt sehe ich, hier gibt es auch einen Gefahren&#252;bergang bez&#252;glich Concurrency, der mich wahrscheinlich damals bewogen hat &#8222;vorsichtshalber&#8220; einen POST zu machen...
</p>
</body>
</html>
</richcontent>
<linktarget COLOR="#ac316f" DESTINATION="ID_1174594521" ENDARROW="Default" ENDINCLINATION="-475;-22;" ID="Arrow_ID_358088244" SOURCE="ID_1861186167" STARTARROW="None" STARTINCLINATION="-246;9;"/>
<icon BUILTIN="smiley-oh"/>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1702577323141" ID="ID_599055156" MODIFIED="1702589940778" TEXT="mu&#xdf; deshalb den (nun einzigen) &#x3bb;-post h&#xf6;her im Callgraphen platzieren">
<arrowlink COLOR="#ad0013" DESTINATION="ID_650472693" ENDARROW="Default" ENDINCLINATION="-796;37;" ID="Arrow_ID_1470263046" STARTARROW="None" STARTINCLINATION="193;-386;"/>
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
</node>