Scheduler-test: fix deficiencies in search control mechanism

In binary search, in order to establish the invariant initially,
a loop is necessary, since a single step might not be sufficient.

Moreover, the ongoing adjustments jeopardise detection of the
statistical breaking point condition, by causing a negative delta
due to gradually approaching the point of convergence -- leading
to an ongoing search in a region beyond the actual breaking point.
This commit is contained in:
Fischlurch 2024-02-19 15:58:05 +01:00
parent ff39aed7ea
commit 2d1bd2b765
4 changed files with 61 additions and 19 deletions

View file

@ -90,9 +90,11 @@ namespace lib {
binarySearch_upper (FUN&& fun, PAR lower, PAR upper, PAR epsilon)
{
REQUIRE (lower <= upper);
bool hit = fun(upper);
if (not hit)
{// the upper end breaks contract => search above
while (true)
{
bool hit = fun(upper);
if (hit) break;
// the upper end breaks contract => search above
PAR len = (upper-lower);
lower = upper - len/10;
upper = lower + 14*len/10;
@ -106,9 +108,11 @@ namespace lib {
binarySearch (FUN&& fun, PAR lower, PAR upper, PAR epsilon)
{
REQUIRE (lower <= upper);
bool hit = fun(lower);
if (hit)
{// the lower end breaks contract => search below
while (true)
{
bool hit = fun(lower);
if (not hit) break;
// the lower end breaks contract => search below
PAR len = (upper-lower);
upper = lower + len/10;
lower = upper - 14*len/10;

View file

@ -155,6 +155,8 @@ namespace test {
double expTime{0};
};
double adjustmentFac{1.0};
/** prepare the ScheduleCtx for a specifically parametrised test series */
void
configureTest (TestSetup& testSetup, double stressFac)
@ -164,7 +166,7 @@ namespace test {
.withSchedNotify (CONF::SCHED_NOTIFY)
.withSchedDepends(CONF::SCHED_DEPENDS)
.withInstrumentation(CONF::INSTRUMENTATION) // side-effect: clear existing statistics
.withAdaptedSchedule(stressFac, CONF::CONCURRENCY);
.withAdaptedSchedule(stressFac, CONF::CONCURRENCY, adjustmentFac);
}
/** perform a repetition of test runs and compute statistics */
@ -181,6 +183,7 @@ namespace test {
runTime[i] = testSetup.launch_and_wait() / 1000;
avgT += runTime[i];
testSetup.adaptEmpirically (stressFac, CONF::CONCURRENCY);
this->adjustmentFac = testSetup.getStressFac() / stressFac;
}
expT = testSetup.getExpectedEndTime() / 1000;
avgT /= CONF::REPETITIONS;

View file

@ -1707,10 +1707,10 @@ namespace test {
FrameRate levelSpeed_{1, SCHEDULE_LEVEL_STEP};
FrameRate planSpeed_{1, SCHEDULE_PLAN_STEP};
TimeVar nodeExpense_{SCHEDULE_NODE_STEP};
double stressFact_{1.0};
double stressFac_{1.0};
bool schedNotify_{SCHED_NOTIFY};
bool schedDepends_{SCHED_DEPENDS};
uint blockLoadFactor_{2};
uint blockLoadFac_{2};
size_t chunkSize_{DEFAULT_CHUNKSIZE};
TimeVar startTime_{Time::ANYTIME};
microseconds deadline_{STANDARD_DEADLINE};
@ -1842,7 +1842,7 @@ namespace test {
getExpectedEndTime()
{
return _raw(startTimes_.back() - startTimes_.front()
+ Duration{nodeExpense_}*(chainLoad_.size()/stressFact_));
+ Duration{nodeExpense_}*(chainLoad_.size()/stressFac_));
}
auto
@ -1852,6 +1852,9 @@ namespace test {
: lib::IncidenceCount::Statistic{};
}
double getStressFac() { return stressFac_; }
/* ===== Setter / builders for custom configuration ===== */
@ -1986,7 +1989,7 @@ namespace test {
ScheduleCtx&&
withAnnouncedLoadFactor (uint factor_on_levelSpeed)
{
blockLoadFactor_ = factor_on_levelSpeed;
blockLoadFac_ = factor_on_levelSpeed;
return move(*this);
}
@ -2084,7 +2087,7 @@ namespace test {
FrameRate
calcLoadHint()
{
return FrameRate{levelSpeed_ * blockLoadFactor_};
return FrameRate{levelSpeed_ * blockLoadFac_};
}
size_t
@ -2112,7 +2115,7 @@ namespace test {
fillDefaultSchedule()
{
size_t numPoints = chainLoad_.topLevel()+2;
stressFact_ = 1.0;
stressFac_ = 1.0;
startTimes_.clear();
startTimes_.reserve (numPoints);
for (size_t level=0; level<numPoints; ++level)
@ -2123,13 +2126,13 @@ namespace test {
fillAdaptedSchedule (double stressFact, uint concurrency)
{
REQUIRE (stressFact > 0);
stressFact_ = stressFact;
stressFac_ = stressFact;
size_t numPoints = chainLoad_.topLevel()+2;
startTimes_.clear();
startTimes_.reserve (numPoints);
startTimes_.push_back (Time::ZERO);
chainLoad_.levelScheduleSequence (concurrency)
.transform([&](double scheduleFact){ return (scheduleFact/stressFact_) * Offset{1,levelSpeed_};})
.transform([&](double scheduleFact){ return (scheduleFact/stressFac_) * Offset{1,levelSpeed_};})
.effuse(startTimes_);
}
@ -2138,7 +2141,7 @@ namespace test {
{
ENSURE (level < startTimes_.size());
return startTimes_[level]
+ nodeExpense_ * (nodeIDX/stressFact_);
+ nodeExpense_ * (nodeIDX/stressFac_);
}
auto

View file

@ -111617,7 +111617,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1708349491714" ID="ID_761985075" MODIFIED="1708349513895" TEXT="Nachjustieren st&#xf6;rt die Ablaufsteuerung">
<node COLOR="#435e98" CREATED="1708349491714" ID="ID_761985075" MODIFIED="1708354204131" TEXT="Nachjustieren st&#xf6;rt die Ablaufsteuerung">
<icon BUILTIN="broken-line"/>
<node CREATED="1708349515240" ID="ID_310788329" MODIFIED="1708349569666" TEXT="Zeiten nehmen innerhalb der Testserie jeweils zu"/>
<node CREATED="1708349570374" ID="ID_1868657338" MODIFIED="1708349595735" TEXT="die &#xbb;expected time&#xab; wird vom letztlich erreichten Schedule abgenommen"/>
@ -111630,8 +111630,40 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1708352301762" ID="ID_1952936030" MODIFIED="1708352316052" TEXT="die Vor-Phase hat nur einmal gepr&#xfc;ft und nachjustiert"/>
<node CREATED="1708352316775" ID="ID_507913615" MODIFIED="1708352327465" TEXT="damit war die Invariante schon zu Beginn verletzt"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1708352337965" ID="ID_872133168" MODIFIED="1708352355731" TEXT="Idee: den zuletzt verwendeten Form-Faktor als Startpunkt merken">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1708352337965" ID="ID_872133168" MODIFIED="1708354202022" TEXT="Idee: den zuletzt verwendeten Form-Faktor als Startpunkt merken">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1708353494162" ID="ID_1417741022" MODIFIED="1708353524083" TEXT="Fraglich ob Einrechnen der Concurrency sinnvoll ist">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1708353529389" ID="ID_1264074130" MODIFIED="1708353581342">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
denn das Schedule wird ja auf eine <i>nominelle </i>Concurrency ausgelegt
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1708353549722" ID="ID_739919619" MODIFIED="1708353588560">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
und diese wird ggfs aus <i>strukturellen Gr&#252;nden </i>nicht ausgesch&#246;pft
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1708353589901" ID="ID_753673138" MODIFIED="1708353635590" TEXT="was dann mithin nicht als Leistungsreserve gedeutet werden darf">
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
</node>