140 #ifndef VAULT_GEAR_TEST_STRESS_TEST_RIG_H 141 #define VAULT_GEAR_TEST_STRESS_TEST_RIG_H 154 #include "lib/stat/statistic.hpp" 169 using std::make_tuple;
181 template<
size_t maxFan =DEFAULT_FAN>
208 bool INSTRUMENTATION =
true;
220 static uint constexpr REPETITIONS{20};
242 .withLevelDuration(200us)
243 .withJobDeadline(500ms)
244 .withUpfrontPlanning();
250 template<
template<
class>
class TOOL,
typename...ARGS>
252 perform (ARGS&& ...args)
254 return TOOL<CONF>{}.perform (std::forward<ARGS> (args)...);
279 using TestLoad =
typename CONF::TestLoad;
280 using TestSetup =
typename TestLoad::ScheduleCtx;
285 double percentOff{0};
296 testSetup.withInstrumentation(CONF::INSTRUMENTATION)
297 .withAdaptedSchedule(stressFac, CONF::CONCURRENCY, adjustmentFac);
304 auto sqr = [](
auto n){
return n*n; };
306 auto& [sf,pf,sdev,avgD,avgT,expT] = res;
308 std::array<double, CONF::REPETITIONS> runTime;
309 for (uint i=0; i<CONF::REPETITIONS; ++i)
311 runTime[i] = testSetup.launch_and_wait() / 1000;
313 maybeAdaptScaleEmpirically (testSetup, stressFac);
315 expT = testSetup.getExpectedEndTime() / 1000;
316 avgT /= CONF::REPETITIONS;
318 for (uint i=0; i<CONF::REPETITIONS; ++i)
320 sdev += sqr (runTime[i] - avgT);
321 double delta = (runTime[i] - expT);
322 bool fail = (delta > CONF::FAIL_LIMIT);
325 showRun(i, delta, runTime[i], runTime[i] > avgT, fail);
327 pf /= CONF::REPETITIONS;
328 sdev = sqrt (sdev/CONF::REPETITIONS);
337 return res.percentOff > 0.99
338 or( res.percentOff > CONF::TRIGGER_FAIL
339 and res.stdDev > CONF::TRIGGER_SDEV
340 and res.avgDelta > CONF::TRIGGER_DELTA);
352 , 0.0, CONF::UPPER_STRESS
354 uint s = results.size();
357 auto& [sf,pf,sdev,avgD,avgT,expT] = res;
359 uint points = min (results.size(), 3u);
360 for (uint i=results.size()-points; i<results.size(); ++i)
362 Res const& resx = results[i];
363 pf += resx.percentOff;
365 avgD += resx.avgDelta;
366 avgT += resx.avgTime;
367 expT += resx.expTime;
379 double adjustmentFac{1.0};
380 size_t gaugeProbes = 3 * CONF::REPETITIONS;
395 if (not gaugeProbes)
return;
396 double gain = util::limited (0, pow(stressFac, 9), 1);
397 if (gain < 0.2)
return;
399 double formFac = testSetup.determineEmpiricFormFactor (CONF::CONCURRENCY);
400 adjustmentFac = gain*formFac + (1-gain)*adjustmentFac;
401 testSetup.withAdaptedSchedule(stressFac, CONF::CONCURRENCY, adjustmentFac);
406 _Fmt fmtRun_ {
"....·%-2d: Δ=%4.1f t=%4.1f %s %s"};
407 _Fmt fmtStep_{
"%4.2f| : ∅Δ=%4.1f±%-4.2f ∅t=%4.1f %s %%%-3.0f -- expect:%4.1fms"};
408 _Fmt fmtResSDv_{
"%9s= %5.2f ±%4.2f%s"};
409 _Fmt fmtResVal_{
"%9s: %5.2f%s"};
412 showRun(uint i,
double delta,
double t,
bool over,
bool fail)
415 cout << fmtRun_ % i % delta % t % (over?
"+":
"-") % (fail?
"●":
"○")
423 cout << fmtStep_ % res.stressFac % res.avgDelta % res.stdDev % res.avgTime
424 % (decideBreakPoint(res)?
"—◆—":
"—◇—")
425 % (100*res.percentOff) % res.expTime
434 cout << fmtResVal_ %
"stresFac" % res.stressFac %
"" <<endl;
435 cout << fmtResVal_ %
"fail" %(res.percentOff * 100) %
'%' <<endl;
436 cout << fmtResSDv_ %
"delta" % res.avgDelta % res.stdDev %
"ms"<<endl;
437 cout << fmtResVal_ %
"runTime" % res.avgTime %
"ms"<<endl;
438 cout << fmtResVal_ %
"expected" % res.expTime %
"ms"<<endl;
446 cout << fmtResVal_ %
"refTime" 447 % (testSetup.calcRuntimeReference() /1000)
463 TestLoad
testLoad = CONF::testLoad().buildTopology();
464 TestSetup testSetup = CONF::testSetup (testLoad);
466 vector<Res> observations;
467 auto performEvaluation = [&](
double stressFac)
469 configureTest (testSetup, stressFac);
470 auto res = runProbes (testSetup, stressFac);
471 observations.push_back (res);
472 return decideBreakPoint(res);
475 Res res = conductBinarySearch (move(performEvaluation), observations);
478 return make_tuple (res.stressFac, res.avgDelta, res.avgTime);
495 using TestLoad =
typename CONF::TestLoad;
496 using TestSetup =
typename TestLoad::ScheduleCtx;
499 using Param =
typename CONF::Param;
500 using Table =
typename CONF::Table;
504 runTest (Param param, Table& data)
506 TestLoad
testLoad = CONF::testLoad(param).buildTopology();
507 TestSetup
testSetup = CONF::testSetup (testLoad)
508 .withInstrumentation();
509 double millis = testSetup.launch_and_wait() / 1000;
510 auto stat = testSetup.getInvocationStatistic();
511 CONF::collectResult (data, param, millis, stat);
525 Param dist = upper - lower;
526 uint cnt = CONF::REPETITIONS;
527 vector<Param> points;
528 points.reserve (cnt);
529 Param minP{upper}, maxP{lower};
530 for (uint i=0; i<cnt; ++i)
532 auto random = double(rand())/RAND_MAX;
533 Param pos = lower + Param(floor (random*dist + 0.5));
534 points.push_back(pos);
535 minP = min (pos, minP);
536 maxP = max (pos, maxP);
539 if (maxP < upper) points[cnt-2] = upper;
540 if (minP > lower) points[cnt-1] = lower;
543 for (Param point : points)
544 runTest (point, results);
563 template<
typename F,
typename G>
567 lib::stat::RegressionData points;
568 size_t cnt = min (x.data.size(), y.data.size());
569 points.reserve (cnt);
570 for (
size_t i=0; i < cnt; ++i)
571 points.emplace_back (x.data[i], y.data[i]);
572 return lib::stat::computeLinearRegression (points);
586 using Param = size_t;
597 {
return std::tie(param
616 data.jobtime = stat.
activeTime / stat.activationCnt;
617 data.impeded = (stat.timeAtConc(1) + stat.timeAtConc(0))/stat.activationCnt;
622 avgConcurrency (
Table const& results)
628 renderGnuplot (
Table const& results)
631 string csv = results.renderCSV();
632 Param maxParam = * std::max_element (results.param.data.begin(), results.param.data.end());
633 Param xtics = maxParam > 500? 50
639 .
set (KEY_TermSize,
"600,600")
640 .
set (KEY_Xtics, int64_t(xtics))
641 .
set (KEY_Xlabel,
"load size ⟶ number of jobs")
642 .
set (KEY_Ylabel,
"active time ⟶ ms")
643 .
set (KEY_Y2label,
"concurrent threads ⟶")
644 .
set (KEY_Y3label,
"avg job time ⟶ µs")
Res runProbes(TestSetup &testSetup, double stressFac)
perform a repetition of test runs and compute statistics
bool showRuns
print a line for each individual run
double TRIGGER_SDEV
in ms : criterion-2 standard derivation
double TRIGGER_DELTA
in ms : criterion-3 average delta above this limit
#define TRANSIENTLY(_OO_)
Macro to simplify capturing assignments.
Wrapper to simplify notation in tests.
auto testSetup(TestLoad &testLoad)
(optional) extension point: base configuration of the test ScheduleCtx
bool showRef
calculate single threaded reference time
Any copy and copy construction prohibited.
Preconfigured setup for data visualisation with Gnuplot.
auto linearRegression(Column< F > const &x, Column< G > const &y)
Calculate a linear regression model for two table columns.
auto testLoad(size_t nodes=64)
Extension point: build the computation topology for this test.
Configurable template framework for running Scheduler Stress tests Use to build a custom setup class...
Generate synthetic computation load for Scheduler performance tests.
string scatterRegression(ParamRecord params)
Generate a (X,Y)-scatter plot with regression line.
Res conductBinarySearch(FUN &&runTestCase, vector< Res > const &results)
invoke a binary search to produce a sequence of test series with the goal to narrow down the stressFa...
double FAIL_LIMIT
delta-limit when to count a run as failure
A Generator for synthetic Render Jobs for Scheduler load testing.
A front-end for using printf-style formatting.
bool showStep
print a line for each binary search step
double UPPER_STRESS
starting point for the upper limit, likely to fail
void maybeAdaptScaleEmpirically(TestSetup &testSetup, double stressFac)
Attempt to factor out some observable properties, which are considered circumstantial and not a direc...
Read-only view into a segment within a sequence of data.
ScheduleCtx setupSchedule(Scheduler &scheduler)
establish and configure the context used for scheduling computations.
double EPSILON
error bound to abort binary search
double avgConcurrency
amortised concurrency in timespan
»Scheduler-Service« : coordinate render activities.
Service for coordination and dispatch of render activities.
Metaprogramming tools for transforming functor types.
Manage a table with data records, stored persistently as CSV.
Specific test scheme to perform a Scheduler setup over a given control parameter range to determine c...
auto binarySearch_upper(FUN &&fun, PAR lower, PAR upper, PAR epsilon)
entrance point to binary search to ensure the upper point indeed fulfils the test.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
double coveredTime
overall timespan of observation
Table with data values, stored persistently as CSV file.
Test helper to perform temporary manipulations within a test scope.
Descriptor and Accessor for a data column within a DataTable table.
Mix-in for setup of a #ParameterRange evaluation to watch the processing of a single load peak...
double activeTime
compounded time of thread activity
bool showRes
print result data
Table perform(Param lower, Param upper)
Launch a measurement sequence running the Scheduler with a varying parameter value to investigate (x...
Textbook implementation of the classical binary search over continuous domain.
Setup and wiring for a test run to schedule a computation structure as defined by this TestChainLoad ...
static size_t COMPUTATION_CAPACITY
Nominal »full size« of a pool of concurrent workers.
double TRIGGER_FAIL
%-fact: criterion-1 failures above this rate
static auto with()
Entrance Point: build a stress test measurement setup using a dedicated TOOL class, takes the configuration CONF as template parameter and which is assumed to inherit (indirectly) from StressRig.
void configureTest(TestSetup &testSetup, double stressFac)
prepare the ScheduleCtx for a specifically parametrised test series
a family of time value like entities and their relationships.
Vault-Layer implementation namespace root.
Collector and aggregator for performance data.
Specific stress test scheme to determine the »breaking point« where the Scheduler starts to slip...
static size_t getDefaultComputationCapacity()
default value for full computing capacity is to use all (virtual) cores.
bool decideBreakPoint(Res &res)
criterion to decide if this test series constitutes a slipped schedule
auto perform()
Launch a measurement sequence to determine the »breaking point« for the configured test load and para...