From ba82a446fdae46725762f346df576000aaf2d6b1 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 17 Dec 2023 23:46:44 +0100 Subject: [PATCH] Scheduler-test: address follow-up problem with depth-first MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rework from yesterday turned out to be effective ... unfortunately a bit to much: since now late follow-up notifications take precedence, a single worker tends to process the complete chain depth-first, because the first chain will be followed and processed, even before the worker was able to post the tasks for the other branches. Thus this single worker is the only one to get a chance to proceed. After some consideration, I am now leaning towards a fundamental change, instead of just fixing some unfavourable behaviour pattern: while the language semantics remains the same, the scheduler should no longer directly dispatch into the next chain **from λ-post**. That is, whenever a POST / NOTIFY is issued from the Activity-chain, the scheduler goes through prioritisation. This has further ramifications: we do not need a self-inhibition mechanism any more (since now NOTIFY picks up the schedule time of the target). With these changes, processing seems to proceed more smoothly, albeit still with lots of contention on the Grooming token, at least in the example structure tested here. --- src/vault/gear/scheduler-commutator.hpp | 16 +- src/vault/gear/scheduler.hpp | 4 +- tests/vault/gear/scheduler-service-test.cpp | 2 +- wiki/thinkPad.ichthyo.mm | 893 ++++++++++++++++++-- 4 files changed, 861 insertions(+), 54 deletions(-) diff --git a/src/vault/gear/scheduler-commutator.hpp b/src/vault/gear/scheduler-commutator.hpp index ea54cb449..4d144944a 100644 --- a/src/vault/gear/scheduler-commutator.hpp +++ b/src/vault/gear/scheduler-commutator.hpp @@ -262,10 +262,18 @@ namespace gear { if (decideDispatchNow (event.startTime(), now)) return ActivityLang::dispatchChain (event, executionCtx); else - if (holdsGroomingToken (thisThread())) - layer1.feedPrioritisation (move (event)); - else - layer1.instruct (move (event)); + instructFollowUp (event,layer1); + return activity::PASS; + } + + activity::Proc + instructFollowUp (ActivationEvent event + ,SchedulerInvocation& layer1 ) + { + if (holdsGroomingToken (thisThread())) + layer1.feedPrioritisation (move (event)); + else + layer1.instruct (move (event)); return activity::PASS; } }; diff --git a/src/vault/gear/scheduler.hpp b/src/vault/gear/scheduler.hpp index 6d304a254..8f48cbb63 100644 --- a/src/vault/gear/scheduler.hpp +++ b/src/vault/gear/scheduler.hpp @@ -526,8 +526,8 @@ namespace gear { chainEvent.activity = chain; chainEvent.starting = _raw(chain->constrainedStart (when)); chainEvent.deadline = _raw(chain->constrainedDeath (dead.isRegular()? dead:chainEvent.deathTime())); - ExecutionCtx subCtx{scheduler_, chainEvent}; - return scheduler_.layer2_.postDispatch (chainEvent, subCtx, scheduler_.layer1_); +// ExecutionCtx subCtx{scheduler_, chainEvent}; + return scheduler_.layer2_.instructFollowUp (chainEvent, scheduler_.layer1_); } /** diff --git a/tests/vault/gear/scheduler-service-test.cpp b/tests/vault/gear/scheduler-service-test.cpp index 1ceec6410..6d9b3f2c0 100644 --- a/tests/vault/gear/scheduler-service-test.cpp +++ b/tests/vault/gear/scheduler-service-test.cpp @@ -583,7 +583,7 @@ SHOW_EXPR(referenceTime) testLoad.setupSchedule(scheduler) .withLoadTimeBase(LOAD_BASE) .withJobDeadline(100ms) - .requireSchedule() +// .requireSchedule() .launch_and_wait(); // invocation through Scheduler has reproduced all node hashes diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index fd0ec5fb9..38c51736f 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -80277,12 +80277,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - + + @@ -80296,6 +80297,12 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + @@ -80307,8 +80314,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + @@ -80337,6 +80345,70 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + +

+ ansonsten bekommen wir nämlich zwei λ-post-Übergänge +

+ + +
+
+ + + + + + + + + + + + +

+ ⟹ all das zusammen legt nahe, direkt die Bedingungen des Target zu beachten +

+ + +
+
+ + + + + + +

+ ...denn das ist ein trickreicher Mechanismus, der zwar sehr einfach umzusetzen, aber nicht leicht zu verstehen ist; einerseits bin ich froh, das notfalls auch noch zur Verfügung zu haben, andererseits ist mir eine direkte Unterstützung im Mechanismus lieber +

+ + +
+ + + + + + +

+ da es zusätzliche λ-post für jeden Aufruf verursacht, selbst wenn dieser Aufruf danach gleich am GATE scheitert — während der Zeit hält der Thread das Grooming-Token +

+ + +
+ +
+
+
@@ -81265,14 +81337,19 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + - + + + + - + + + @@ -81284,8 +81361,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
vor dem Zugang zum GATE muß das Grooming-Token  erlangt werden

- -
+ @@ -81306,11 +81382,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
zweimaliger λ-post wäre die sauberste Lösung — bedingt aber inakzeptablen Overhead

- - +
- + @@ -81342,13 +81417,12 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ - - @@ -81361,8 +81435,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
wie gut ist es self-composable?

- - + + + +
@@ -81376,25 +81452,23 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
aber der Hook kann auch die Rolle jedes activate/notify übernehmen

- - +
+
+ + + + + - - - - - - - @@ -81443,9 +81517,29 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + + + +

+ activate-NOTIFY: macht λ-post mit target +

+ +
+
+ + + + +

+ dispatch-GATE:  ⟶ Spezialbehandlung NOTIFY Gate +

+ +
+ +
+
@@ -81592,7 +81686,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -81629,9 +81723,88 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + + + + + + + + + + + +

+ unklar: ist das gut? +

+

+ fällt damit eine Ausdrucks-Variante weg? +

+

+ oder doch nicht? +

+ +
+ + + + + + + + +

+ aber nur sofern man die Start-Zeit als Constraint deutet +

+ +
+
+ + + + + + + + + + + + + +

+ es geht hier um Regel/Ausnahme +

+ + +
+ + + + + + + + +

+ wenn etwas „sofort“ starten kann, setze ich die Startzeit auf jetzt +

+ +
+
+
+
+
+ + + + + + + @@ -103604,8 +103777,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
weil es stets ein letztes Prerequisite gibt, das dann die ganze Lawine an Berechnungen lostritt; der relevante Knoten ist Node-Nr.34(L20) — und die wiederum hat drei Vorläufer-Ketten der Länge 2, d.h. der finale Trigger liegt auf Level 18 oder gar 17.

- - +
@@ -103622,8 +103794,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
~3ms — aber 3·400µs ≈ 1.5ms + 100µs hätte ich erwartet

- - +
@@ -103663,8 +103834,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
ja, irgendwo geht hier Zeit verloren, aber im 2.Lauf ist alles nicht so stark ausgeprägt

- - +
@@ -103677,8 +103847,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
im 2.Lauf mit genauerer Instrumentierung sind die auffälligen Abweichungen innerhalb der Node-Invocation, nicht im administrativen Teil

- - +
@@ -103692,8 +103861,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
beim Durchdenken nebenbei aufgefallen: unprotected concurrenct acccess

- - +
@@ -103730,8 +103898,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
...weil wir Prioritäten gar nicht auf der Ebene des Schedulers repräsentieren, sondern in den übergreifenden Plan einarbeiten können; der Scheduler muß also nur im Bezug auf diesen Plan priorisieren

- - +
@@ -103743,8 +103910,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
...denn diese zugrundeliegende Struktur ist durch einen vorgelagerten Plan grundsätzlich nicht aus der Welt zu schaffen, denn es geht dabei um eine Diskrepanz zwischen einer planäßigen Codifizierung der Priorität und einer real (sachbezogen) gegebenen Priorität

- -
+
@@ -103755,7 +103921,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -103768,15 +103934,648 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
...ich hatte dabei ein ungutes Gefühl, weil ich mir nicht erklären konnte, warum um ursprünglichen Code diese doppelte Indirektion drinnen war; hab das dann vom Tisch gewischt mit der Vermutung, es sei aus formalen Gründen eingebaut. Jetzt sehe ich, hier gibt es auch einen Gefahrenübergang bezüglich Concurrency, der mich wahrscheinlich damals bewogen hat „vorsichtshalber“ einen POST zu machen...

- - +
- + + + + + + + + + + + + + + + + +

+ wir haben jetzt nur die Priorisierung verbessert, aber auch vorher konnte ein Thread depth-first durchmarschieren... +

+ + +
+
+
+ + + + + + + + + +

+ und außerdem bin ich mit der Gesamtsituation unzufrieden +

+ + +
+
+ + + + + + + + + + + + + + + + + + +

+ eine POST-Activity in der Mitte eines Chain; das wird derzeit nie benötigt, und am Anfang des Chain steigen wir ja anders ein, nämlich über ActivityLang::dispatch() -> POST.dispatch() -> activate(next) +

+ + +
+
+ + + + + + +
+
+ + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + +

+    ·‖ 0B: @14133 HT:14000  -> ▶ 13000 +

+

+ ‖PST‖ 72: @14173 ◒ start=13000⧐14000 dead:100000 +

+

+    ·‖ 51: @14194 HT:14000  -> ∘ +

+

+    ·‖ 72: @14193 HT:15000  -> ▶ 14000 +

+

+ +

+

+ !◆!   0B: @14188  ⚙  calc(i=18, lev:13) +

+

+ ‖PST‖ 72: @14253 ◒ start=14000⧐14000 dead:100000 +

+

+ +

+

+ !◆!   72: @14272  ⚙  calc(i=19, lev:14) +

+

+    ·‖ 51: @15064 HT:16000  -> ▶ 15000 +

+

+ ‖PST‖ 51: @15095 ◒ start=15000⧐15000 dead:100000 +

+

+ ..!   0B: @15109  ⤴       (i=18) +

+

+ ‖PST‖ 0B: @15177 ◒ start=13000⧐14000 dead:100000 +

+

+ +

+

+ !◆!   0B: @15205  ⚙  calc(i=20, lev:14) +

+

+ ..!   72: @15847  ⤴       (i=19) +

+

+ ‖PST‖ 72: @15887 ◒ start=14000⧐15000 dead:100000 +

+

+    ·‖ 5E: @16030 HT:17000  -> ▶ 16000 +

+

+ ‖PST‖ 5E: @16074 ◒ start=16000⧐16000 dead:100000 +

+

+    ·‖ 5E: @17068 HT:18000  -> ▶ 17000 +

+

+ ‖PST‖ 5E: @17103 ◒ start=17000⧐17000 dead:100000 +

+

+ ..!   0B: @17251  ⤴       (i=20) +

+

+ ‖PST‖ 0B: @17313 ◒ start=14000⧐15000 dead:100000 +

+

+ +

+

+ !◆!   0B: @17336  ⚙  calc(i=21, lev:15) +

+

+ ..!   0B: @17389  ⤴       (i=21) +

+

+ ‖PST‖ 0B: @17431 ◒ start=15000⧐16000 dead:100000 +

+

+ +

+

+ !◆!   0B: @17451  ⚙  calc(i=22, lev:16) +

+

+    ·‖ 5E: @18070 HT:18000  -> ▶ 18000 +

+

+ ‖PST‖ 5E: @18111 ◒ start=18000⧐18000 dead:100000 +

+

+    ·‖ 5E: @18134 HT:18000  -> ▶ 18000 +

+

+ ‖PST‖ 5E: @18163 ◒ start=18000⧐18000 dead:100000 +

+

+    ·‖ 5E: @18185 HT:18000  -> ▶ 18000 +

+

+ ‖PST‖ 5E: @18215 ◒ start=18000⧐18000 dead:100000 +

+

+    ·‖ 72: @18187 HT:18000  -> ∘ +

+

+    ·‖ 72: @18264 HT:18000  -> ∘ +

+

+    ·‖ 5E: @18259 HT:18000  -> ▶ 18000 +

+

+    ·‖ 72: @18278 HT:18000  -> ∘ +

+

+    ·‖ 72: @18298 HT:18000  -> ∘ +

+

+ ‖PST‖ 5E: @18296 ◒ start=18000⧐18000 dead:100000 +

+

+    ·‖ 72: @18313 HT:18000  -> ∘ +

+

+    ·‖ 72: @18335 HT:19000  -> ∘ +

+

+    ·‖ 5E: @18333 HT:19000  -> ▶ 18000 +

+

+ ‖PST‖ 5E: @18364 ◒ start=18000⧐18000 dead:100000 +

+

+ ..!   0B: @18509  ⤴       (i=22) +

+

+ ‖PST‖ 0B: @18564 ◒ start=16000⧐17000 dead:100000 +

+

+ +

+

+ !◆!   0B: @18586  ⚙  calc(i=23, lev:17) +

+

+    ·‖ DE: @19065 HT:19000  -> ▶ 19000 +

+

+    ·‖ 5E: @19071 HT:19000  -> ∘ +

+

+ ‖PST‖ DE: @19105 ◒ start=19000⧐19000 dead:100000 +

+

+    ·‖ 5E: @19116 HT:19000  -> ∘ +

+

+    ·‖ 5E: @19140 HT:19000  -> ∘ +

+

+    ·‖ DE: @19123 HT:19000  -> ▶ 19000 +

+

+    ·‖ 5E: @19162 HT:19000  -> ∘ +

+

+ ‖PST‖ DE: @19179 ◒ start=19000⧐19000 dead:100000 +

+

+    ·‖ 5E: @19184 HT:19000  -> ∘ +

+

+    ·‖ DE: @19198 HT:19000  -> ▶ 19000 +

+

+    ·‖ 5E: @19207 HT:19000  -> ∘ +

+

+ ‖PST‖ DE: @19220 ◒ start=19000⧐19000 dead:100000 +

+

+    ·‖ 5E: @19229 HT:19000  -> ∘ +

+

+    ·‖ DE: @19238 HT:19000  -> ▶ 19000 +

+

+    ·‖ 5E: @19251 HT:19000  -> ∘ +

+

+ ‖PST‖ DE: @19259 ◒ start=19000⧐19000 dead:100000 +

+

+    ·‖ 5E: @19276 HT:19000  -> ∘ +

+

+    ·‖ DE: @19288 HT:20000  -> ▶ 19000 +

+

+ ‖PST‖ DE: @19309 ◒ start=19000⧐19000 dead:100000 +

+

+    ·‖ DE: @20088 HT:20000  -> ▶ 20000 +

+

+ ‖PST‖ DE: @20120 ◒ start=20000⧐20000 dead:100000 +

+

+    ·‖ DE: @20139 HT:21000  -> ▶ 20000 +

+

+ ‖PST‖ DE: @20159 ◒ start=20000⧐20000 dead:100000 +

+

+    ·‖ DE: @21063 HT:21000  -> ▶ 21000 +

+

+ ‖PST‖ DE: @21092 ◒ start=21000⧐21000 dead:100000 +

+

+    ·‖ DE: @21108 HT:21000  -> ▶ 21000 +

+

+ ‖PST‖ DE: @21128 ◒ start=21000⧐21000 dead:100000 +

+

+    ·‖ DE: @21144 HT:22000  -> ▶ 21000 +

+

+ ‖PST‖ DE: @21163 ◒ start=21000⧐21000 dead:100000 +

+

+ ..!   0B: @21639  ⤴       (i=23) +

+

+ ‖PST‖ 0B: @21699 ◒ start=17000⧐18000 dead:100000 +

+

+    ·‖ EE: @22030 HT:22000  -> ▶ 22000 +

+

+ ‖PST‖ 0B: @118578 ◒ start=17000⧐18000 dead:100000 +

+

+ ‖PST‖ EE: @118603 ◒ start=22000⧐22000 dead:100000 +

+

+ ‖PST‖ 0B: @118637 ◒ start=17000⧐18000 dead:100000   ·‖ 5E: @26364 HT:22000  -> ∘ +

+

+    ·‖ DE: @22063 HT:22000  -> ∘ +

+

+    ·‖ 5E: @118727 HT:18000  -> ∘ +

+

+    ·‖ EE: @118732 HT:22000  -> ▶ 22000 +

+

+    ·‖ 51: @30823 HT:22000  -> ∘ +

+

+    ·‖ 51: @118831 HT:22000  -> ∘ +

+

+    ·‖ DE: @118778 HT:22000  -> ∘ +

+

+    ·‖ 51: @118852 HT:22000  -> ∘ +

+

+    ·‖ DE: @118863 HT:22000  -> ∘ +

+

+ ‖PST‖ EE: @118784 ◒ start=22000⧐22000 dead:100000 +

+

+    ·‖ 99: @23758 HT:22000  -> ∘   ·‖ 72: @22141 HT:22000  -> ∘ +

+

+ +

+

+    ·‖ 99: @118940 HT:22000  -> ∘ +

+

+    ·‖ 72: @118952 HT:22000  -> ∘ +

+

+    ·‖ 99: @118964 HT:22000  -> ∘ +

+

+    ·‖ 5E: @118756 HT:22000  -> ∘ +

+

+    ·‖ 99: @118987 HT:22000  -> ∘ +

+

+    ·‖ EE: @118929 HT:22000  -> ▶ 22000 +

+

+    ·‖ 99: @119009 HT:22000  -> ∘ +

+

+    ·‖ 51: @118870 HT:22000  -> ∘ +

+

+    ·‖ 99: @119031 HT:22000  -> ∘ +

+

+    ·‖ CB: @23660 HT:22000  -> ∘ +

+

+    ·‖ 99: @119054 HT:22000  -> ∘ +

+

+    ·‖ 99: @119077 HT:22000  -> ∘ +

+

+    ·‖ 51: @119089 HT:22000  -> ∘ +

+

+    ·‖ 99: @119100 HT:22000  -> ∘ +

+

+    ·‖ 51: @119109 HT:22000  -> ∘ +

+

+ +

+

+    ·‖ DE: @118889 HT:22000  -> ∘   ·‖ 5E: @119082 HT:22000  -> ∘   ·‖ CB: @119145 HT:22000  -> ∘ +

+

+ ‖PST‖ 0B: @119165 ◒ start=17000⧐18000 dead:100000 +

+

+ +

+

+ +

+

+    ·‖ 5E: @119196 HT:22000  -> ∘ +

+

+ ‖PST‖ EE: @119204 ◒ start=22000⧐22000 dead:100000   ·‖ 51: @119150 HT:22000  -> ∘ +

+

+    ·‖ 5E: @119225 HT:22000  -> ∘ +

+

+    ·‖ 51: @119235 HT:22000  -> ∘ +

+

+    ·‖ 5E: @119244 HT:22000  -> ∘ +

+

+    ·‖ 51: @119255 HT:22000  -> ∘ +

+

+    ·‖ 5E: @119275 HT:22000  -> ∘ +

+

+    ·‖ DE: @119208 HT:22000  -> ∘ +

+

+    ·‖ 5E: @119298 HT:22000  -> ∘ +

+

+    ·‖ CB: @119169 HT:22000  -> ∘   ·‖ DE: @119310 HT:22000  -> ∘ +

+

+    ·‖ 72: @118970 HT:22000  -> ∘   ·‖ DE: @119342 HT:22000  -> ∘ +

+

+ +

+

+ ‖PST‖ 0B: @119295 ◒ start=17000⧐18000 dead:100000 +

+

+    ·‖ 0B: @119416 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119433 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119449 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119466 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119484 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119500 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119517 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119535 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119552 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119568 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119585 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119602 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119619 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119637 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119653 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119671 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119688 HT:22000  -> ∘ +

+ + +
+ + + + + + + +

+    ·‖ 0B: @14133 HT:14000  -> ▶ 13000 +

+

+ !◆!   0B: @14188  ⚙  calc(i=18, lev:13) +

+

+ ..!   0B: @15109  ⤴       (i=18) +

+

+ ‖PST‖ 0B: @15177 ◒ start=13000⧐14000 dead:100000 +

+

+ !◆!   0B: @15205  ⚙  calc(i=20, lev:14) +

+

+ ..!   0B: @17251  ⤴       (i=20) +

+

+ ‖PST‖ 0B: @17313 ◒ start=14000⧐15000 dead:100000 +

+

+ !◆!   0B: @17336  ⚙  calc(i=21, lev:15) +

+

+ ..!   0B: @17389  ⤴       (i=21) +

+

+ ‖PST‖ 0B: @17431 ◒ start=15000⧐16000 dead:100000 +

+

+ !◆!   0B: @17451  ⚙  calc(i=22, lev:16) +

+

+ ..!   0B: @18509  ⤴       (i=22) +

+

+ ‖PST‖ 0B: @18564 ◒ start=16000⧐17000 dead:100000 +

+

+ !◆!   0B: @18586  ⚙  calc(i=23, lev:17) +

+

+ ..!   0B: @21639  ⤴       (i=23) +

+

+ ‖PST‖ 0B: @21699 ◒ start=17000⧐18000 dead:100000 +

+

+ ‖PST‖ 0B: @118578 ◒ start=17000⧐18000 dead:100000 +

+

+ ‖PST‖ 0B: @118637 ◒ start=17000⧐18000 dead:100000   ·‖ 5E: @26364 HT:22000  -> ∘ +

+

+ ‖PST‖ 0B: @119165 ◒ start=17000⧐18000 dead:100000 +

+

+ ‖PST‖ 0B: @119295 ◒ start=17000⧐18000 dead:100000 +

+

+    ·‖ 0B: @119416 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119433 HT:22000  -> ∘ +

+

+    ·‖ 0B: @119449 HT:22000  -> ∘ +

+ + +
+
+
+ + + + + + + + + +

+ der Thread, aber auch andere warten warten endlos auf das Grooming-Token (wer hat das zu der Zeit?) +

+ +
+