diff --git a/src/lib/incidence-count.hpp b/src/lib/incidence-count.hpp index 1ad7ed5ed..36814491e 100644 --- a/src/lib/incidence-count.hpp +++ b/src/lib/incidence-count.hpp @@ -212,7 +212,7 @@ namespace lib { * and then compute statistics evaluations to characterise observations. * @warning caller must ensure there was a barrier or visibility sync before invocation. */ - IncidenceCount::Statistic + inline IncidenceCount::Statistic IncidenceCount::evaluate() { Statistic stat; diff --git a/tests/library/incidence-count-test.cpp b/tests/library/incidence-count-test.cpp index 80fa64494..50052747d 100644 --- a/tests/library/incidence-count-test.cpp +++ b/tests/library/incidence-count-test.cpp @@ -26,7 +26,6 @@ #include "lib/test/run.hpp" -#include "lib/test/diagnostic-output.hpp"//////////////TODO RLY? #include "lib/test/microbenchmark.hpp" #include "lib/incidence-count.hpp" #include "lib/thread.hpp" @@ -76,7 +75,6 @@ namespace test{ /** @test watch time spent in code bracketed by measurement calls. - * @todo WIP 2/24 ✔ define ⟶ ✔ implement */ void demonstrate_usage() @@ -98,9 +96,7 @@ namespace test{ } - /** @test verify proper counting of possibly overlapping incidences - * @todo WIP 2/24 ✔ define ⟶ ✔ implement - */ + /** @test verify proper counting of possibly overlapping incidences. */ void verify_incidentCount() { @@ -126,56 +122,35 @@ namespace test{ watch.markLeave(1); auto stat = watch.evaluate(); -SHOW_EXPR(stat.cumulatedTime); -SHOW_EXPR(stat.coveredTime); -SHOW_EXPR(stat.activeTime); -SHOW_EXPR(stat.eventCnt); -SHOW_EXPR(stat.activationCnt); -SHOW_EXPR(stat.cntCase(0)); -SHOW_EXPR(stat.cntCase(1)); -SHOW_EXPR(stat.cntCase(2)); -SHOW_EXPR(stat.cntCase(3)); -SHOW_EXPR(stat.cntCase(4)); -SHOW_EXPR(stat.timeCase(0)); -SHOW_EXPR(stat.timeCase(1)); -SHOW_EXPR(stat.timeCase(2)); -SHOW_EXPR(stat.timeCase(3)); -SHOW_EXPR(stat.timeCase(4)); -SHOW_EXPR(stat.cntThread(0)); -SHOW_EXPR(stat.cntThread(1)); -SHOW_EXPR(stat.timeThread(0)); -SHOW_EXPR(stat.timeThread(1)); - CHECK (isLimited (15500, stat.cumulatedTime, 17800)); // ≈ 16ms - CHECK (isLimited ( 8500, stat.coveredTime, 10000)); // ≈ 9ms - CHECK (10== stat.eventCnt); - CHECK (5 == stat.activationCnt); - CHECK (0 == stat.cntCase(0)); - CHECK (2 == stat.cntCase(1)); - CHECK (1 == stat.cntCase(2)); - CHECK (2 == stat.cntCase(3)); - CHECK (0 == stat.cntCase(4)); - CHECK (0 == stat.timeCase(0)); - CHECK (isLimited ( 5500, stat.timeCase(1), 6800)); // ≈ 6ms - CHECK (isLimited ( 3500, stat.timeCase(2), 4500)); // ≈ 4ms - CHECK (isLimited ( 5500, stat.timeCase(3), 6800)); // ≈ 6ms - CHECK (0 == stat.timeCase(4)); - CHECK (5 == stat.cntThread(0)); - CHECK (0 == stat.cntThread(1)); - CHECK (stat.activeTime == stat.timeThread(0)); - CHECK (0 == stat.timeThread(1)); - CHECK (isNumEq (stat.activeTime, stat.coveredTime)); - CHECK (isNumEq (stat.cumulatedTime , stat.timeCase(1) + stat.timeCase(2) + stat.timeCase(3))); + + CHECK (isLimited (15500, stat.cumulatedTime, 17800)); // ≈ 16ms + CHECK (isLimited ( 8500, stat.coveredTime, 10000)); // ≈ 9ms + CHECK (10== stat.eventCnt); + CHECK (5 == stat.activationCnt); + CHECK (0 == stat.cntCase(0)); + CHECK (2 == stat.cntCase(1)); + CHECK (1 == stat.cntCase(2)); + CHECK (2 == stat.cntCase(3)); + CHECK (0 == stat.cntCase(4)); + CHECK (0 == stat.timeCase(0)); + CHECK (isLimited ( 5500, stat.timeCase(1), 6800)); // ≈ 6ms + CHECK (isLimited ( 3500, stat.timeCase(2), 4500)); // ≈ 4ms + CHECK (isLimited ( 5500, stat.timeCase(3), 6800)); // ≈ 6ms + CHECK (0 == stat.timeCase(4)); + CHECK (5 == stat.cntThread(0)); + CHECK (0 == stat.cntThread(1)); + CHECK (stat.activeTime == stat.timeThread(0)); + CHECK (0 == stat.timeThread(1)); + CHECK (isNumEq (stat.activeTime, stat.coveredTime)); + CHECK (isNumEq (stat.cumulatedTime , stat.timeCase(1) + stat.timeCase(2) + stat.timeCase(3))); } - /** @test verify observation of concurrency degree - * @todo WIP 2/24 ✔ define ⟶ ✔ implement - */ + + /** @test verify observation of concurrency degree. */ void verify_concurrencyStatistic() { - MARK_TEST_FUN - IncidenceCount watch; watch.expectThreads(2) .expectIncidents(2); @@ -202,31 +177,7 @@ SHOW_EXPR(stat.timeThread(1)); // join ensures visibility of all data changes from within threads, // which is a prerequisite for performing the data evaluation safely. auto stat = watch.evaluate(); -SHOW_EXPR(runTime) -SHOW_EXPR(stat.cumulatedTime); -SHOW_EXPR(stat.activeTime); -SHOW_EXPR(stat.coveredTime); -SHOW_EXPR(stat.eventCnt); -SHOW_EXPR(stat.activationCnt); -SHOW_EXPR(stat.cntCase(0)); -SHOW_EXPR(stat.cntCase(1)); -SHOW_EXPR(stat.cntCase(2)); -SHOW_EXPR(stat.cntCase(3)); -SHOW_EXPR(stat.timeCase(0)); -SHOW_EXPR(stat.timeCase(1)); -SHOW_EXPR(stat.timeCase(2)); -SHOW_EXPR(stat.timeCase(3)); -SHOW_EXPR(stat.cntThread(0)); -SHOW_EXPR(stat.cntThread(1)); -SHOW_EXPR(stat.cntThread(2)); -SHOW_EXPR(stat.timeThread(0)); -SHOW_EXPR(stat.timeThread(1)); -SHOW_EXPR(stat.timeThread(2)); -SHOW_EXPR(stat.avgConcurrency); -SHOW_EXPR(stat.timeAtConc(0)); -SHOW_EXPR(stat.timeAtConc(1)); -SHOW_EXPR(stat.timeAtConc(2)); -SHOW_EXPR(stat.timeAtConc(3)); + CHECK (runTime > stat.coveredTime); CHECK (stat.coveredTime < stat.cumulatedTime); CHECK (stat.activeTime <= stat.cumulatedTime); @@ -259,13 +210,11 @@ SHOW_EXPR(stat.timeAtConc(3)); } - /** @test TODO verify thread-safe operation under pressure - * @todo WIP 2/24 ✔ define ⟶ ✔ implement - */ + + /** @test verify thread-safe operation under pressure. */ void perform_multithreadStressTest() { - MARK_TEST_FUN constexpr size_t CONCURR = 16; const size_t REPETITIONS = 100; @@ -283,76 +232,32 @@ SHOW_EXPR(stat.timeAtConc(3)); watch.markLeave(); }; + // Invoke these two nested activations numerous times in several threads auto [runTime, sum] = test::threadBenchmark (act, REPETITIONS); -SHOW_EXPR(runTime) -SHOW_EXPR(sum) - CHECK (1600 == sum); + + CHECK (sum == CONCURR*REPETITIONS); // each invocation contributes +1 CHECK (isLimited (900, runTime, 1400)); // delay is 500µs on average + // compute statistics over recorded events auto stat = watch.evaluate(); -SHOW_EXPR(stat.cumulatedTime); -SHOW_EXPR(stat.activeTime); -SHOW_EXPR(stat.coveredTime); + + // on average two times 500µs per invocation CHECK (isLimited (900*REPETITIONS, stat.coveredTime, 1400*REPETITIONS)); - CHECK (stat.activeTime > 900 * REPETITIONS * CONCURR); -SHOW_EXPR(stat.eventCnt); -SHOW_EXPR(stat.activationCnt); + CHECK (stat.activeTime > 900 * REPETITIONS*CONCURR); CHECK (stat.activationCnt == 2*REPETITIONS*CONCURR); -SHOW_EXPR(stat.cntCase(0)); CHECK (stat.cntCase(0) == REPETITIONS*CONCURR); -SHOW_EXPR(stat.cntCase(1)); CHECK (stat.cntCase(1) == 0); -SHOW_EXPR(stat.cntCase(2)); CHECK (stat.cntCase(2) == REPETITIONS*CONCURR); -SHOW_EXPR(stat.cntCase(3)); -SHOW_EXPR(stat.timeCase(0)); -SHOW_EXPR(stat.timeCase(1)); -SHOW_EXPR(stat.timeCase(2)); -SHOW_EXPR(stat.timeCase(3)); -SHOW_EXPR(stat.cntThread(0)); -SHOW_EXPR(stat.cntThread(1)); -SHOW_EXPR(stat.cntThread(2)); -SHOW_EXPR(stat.cntThread(3)); -SHOW_EXPR(stat.cntThread(4)); -SHOW_EXPR(stat.cntThread(5)); -SHOW_EXPR(stat.cntThread(6)); -SHOW_EXPR(stat.cntThread(7)); -SHOW_EXPR(stat.cntThread(8)); -SHOW_EXPR(stat.cntThread(9)); -SHOW_EXPR(stat.timeThread(0)); -SHOW_EXPR(stat.timeThread(1)); -SHOW_EXPR(stat.timeThread(2)); -SHOW_EXPR(stat.timeThread(3)); -SHOW_EXPR(stat.timeThread(4)); -SHOW_EXPR(stat.timeThread(5)); -SHOW_EXPR(stat.timeThread(6)); -SHOW_EXPR(stat.timeThread(7)); -SHOW_EXPR(stat.timeThread(8)); -SHOW_EXPR(stat.timeThread(9)); -SHOW_EXPR(stat.avgConcurrency); + CHECK (isLimited(CONCURR/2, stat.avgConcurrency, CONCURR)); + // if there are enough cores, ∅ concurrency should even be close to CONCURR + for (uint i=0; i::Node; + using Watch = lib::IncidenceCount; Node* startNode_; ComputationalLoad* compuLoad_; + Watch* watch_; public: - RandomChainCalcFunctor(Node& startNode, ComputationalLoad* load =nullptr) + RandomChainCalcFunctor(Node& startNode, ComputationalLoad* load =nullptr, Watch* watch =nullptr) : startNode_{&startNode} , compuLoad_{load} + , watch_{watch} { } @@ -1564,6 +1568,7 @@ namespace test { void invokeJobOperation (JobParameter param) override { + if (watch_) watch_->markEnter(); size_t nodeIdx = decodeNodeID (param.invoKey); size_t level = decodeLevel (TimeValue{param.nominalTime}); Node& target = startNode_[nodeIdx]; @@ -1572,6 +1577,7 @@ namespace test { if (compuLoad_ and target.weight) compuLoad_->invoke (target.weight); target.calculate(); + if (watch_) watch_->markLeave(); } string diagnostic() const override @@ -1692,6 +1698,8 @@ namespace test { std::unique_ptr> calcFunctor_; std::unique_ptr> planFunctor_; + std::unique_ptr watchInvocations_; + /* ==== Callbacks from job planning ==== */ @@ -1752,7 +1760,7 @@ namespace test { size_t firstChunkEndNode = calcNextChunkEnd(0); schedule_.allocate (numNodes); compuLoad_->maybeCalibrate(); - calcFunctor_.reset (new RandomChainCalcFunctor{chainLoad_.nodes_[0], compuLoad_.get()}); + calcFunctor_.reset (new RandomChainCalcFunctor{chainLoad_.nodes_[0], compuLoad_.get(), watchInvocations_.get()}); planFunctor_.reset (new RandomChainPlanFunctor{chainLoad_.nodes_[0], chainLoad_.numNodes_ ,[this](size_t i, size_t l){ disposeStep(i,l); } ,[this](auto* p, auto* s) { setDependency(p,s);} @@ -1810,9 +1818,23 @@ namespace test { + Duration{nodeExpense_}*(chainLoad_.size()/stressFact_)); } + auto + getInvocationStatistic() + { + return watchInvocations_? watchInvocations_->evaluate() + : lib::IncidenceCount::Statistic{}; + } + /* ===== Setter / builders for custom configuration ===== */ + ScheduleCtx&& + withInstrumentation (bool doWatch =true) + { + watchInvocations_.reset (doWatch? new lib::IncidenceCount : nullptr); + return move(*this); + } + ScheduleCtx&& withPlanningStep (microseconds planningTime_per_node) { diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 937b70d77..30c45f042 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -110965,12 +110965,12 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + - + @@ -111115,15 +111115,15 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - - + + + + - - + + @@ -111141,8 +111141,58 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + + + + + + + + + + +

+ erster Versuch: überhaupt keinen Graph konstruieren +

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