Scheduler-test: settle definition of specific test setup and data
After a lot of further tinkering, seemingly arriving at a somewhat satisfactory solution for the layout and arrangement of test definitions and especially the table for measurement series. While the complete setup remains fragile indeed, and complexity is more hidden than reduced — the pragmatic compromise established yesterday at least allows to reduce the amount of boilerplate in the test or measurement setup to make the actual specifics stand out clearly. ---- As an aside, the usage of the `DataFile` type imported from Yoshimi-test recently was re-shaped more towards a generic handling of tabular data with CSV storage option; thus renaming the type now into `DataTable`. Persistent storage is now just one option, while another usage pattern compounds observation data into table rows, which are then directly rendered into a CSV string, e.g. for visualisation as Gnuplot graph.
This commit is contained in:
parent
10fa0aaa79
commit
8e33194882
6 changed files with 278 additions and 108 deletions
|
|
@ -39,7 +39,7 @@
|
|||
** - only quoted fields may contain whitespace or comma
|
||||
** - no escaping of quotes, i.e. no quotes within quotes
|
||||
** [RFC 4180]: https://datatracker.ietf.org/doc/html/rfc4180
|
||||
** @see lib::stat::DataFile
|
||||
** @see lib::stat::DataTable
|
||||
**
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
** the most recent row of data can be accessed directly through these sub-components.
|
||||
**
|
||||
** # Usage
|
||||
** Create an actual instantiation of the DataFile template, passing a structure
|
||||
** Create an actual instantiation of the DataTable template, passing a structure
|
||||
** with util::Column descriptors. You may then directly access the values of the
|
||||
** _actual column_ or save/load from a persistent CSV file.
|
||||
** @note mandatory to define a method `allColumns()`
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
** auto allColumns(){ return std::tie(name,n,x,y); }
|
||||
** };
|
||||
**
|
||||
** using Dataz = lib::stat::DataFile<Storage>;
|
||||
** using Dataz = lib::stat::DataTable<Storage>;
|
||||
**
|
||||
** Dataz daz("filename.csv");
|
||||
**
|
||||
|
|
@ -74,7 +74,7 @@
|
|||
** \par Variations
|
||||
** The standard case is to have a table backed by persistent file storage,
|
||||
** which can be initially empty. Under some conditions, especially for tests
|
||||
** - the DataFile can be created without filename
|
||||
** - the DataTable can be created without filename
|
||||
** - it can be created from a CSVData, which is a `std::vector` of CSV-strings
|
||||
** - it can be [rendered into CSV strings](\ref #renderCSV)
|
||||
** - a (new) storage file name can be [given later](\ref saveAs)
|
||||
|
|
@ -122,7 +122,7 @@ namespace stat{
|
|||
|
||||
|
||||
/**
|
||||
* Descriptor and Accessor for a data column within a DataFile table.
|
||||
* Descriptor and Accessor for a data column within a DataTable table.
|
||||
* @tparam VAL type of values contained within this column;
|
||||
* this type must be _default constructible_ and _copyable._
|
||||
*/
|
||||
|
|
@ -191,20 +191,20 @@ namespace stat{
|
|||
* within the table and persistent CSV storage.
|
||||
*/
|
||||
template<class TAB>
|
||||
class DataFile
|
||||
class DataTable
|
||||
: public TAB
|
||||
, util::MoveOnly
|
||||
{
|
||||
fs::path filename_;
|
||||
|
||||
public:
|
||||
DataFile(fs::path csvFile ="")
|
||||
DataTable(fs::path csvFile ="")
|
||||
: filename_{fs::consolidated (csvFile)}
|
||||
{
|
||||
loadData();
|
||||
}
|
||||
|
||||
DataFile (CSVData const& csv)
|
||||
DataTable (CSVData const& csv)
|
||||
: filename_{}
|
||||
{
|
||||
appendFrom (csv);
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ namespace test{
|
|||
}
|
||||
};
|
||||
|
||||
using TestTab = DataFile<TableForm>;
|
||||
using TestTab = DataTable<TableForm>;
|
||||
|
||||
}//(End)Test setup
|
||||
|
||||
|
|
@ -221,7 +221,7 @@ namespace test{
|
|||
}
|
||||
|
||||
|
||||
/** @test validate the simple CSV conversion functions used by DataFile */
|
||||
/** @test validate the simple CSV conversion functions used by DataTable */
|
||||
void
|
||||
verify_CSV_Format()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -397,13 +397,11 @@ namespace test {
|
|||
.printTopologyDOT()
|
||||
.printTopologyStatistics();
|
||||
|
||||
struct Setup : StressRig
|
||||
struct Setup
|
||||
: StressRig, bench::LoadPeak_ParamRange_Evaluation
|
||||
{
|
||||
uint CONCURRENCY = 4;
|
||||
|
||||
using Param = size_t;
|
||||
using Table = bench::DataTable<Param>;
|
||||
|
||||
auto testLoad(Param nodes)
|
||||
{
|
||||
TestLoad testLoad{nodes};
|
||||
|
|
@ -415,17 +413,6 @@ namespace test {
|
|||
return StressRig::testSetup(testLoad)
|
||||
.withLoadTimeBase(500us);
|
||||
}
|
||||
|
||||
void
|
||||
collectResult(Table& data, Param param, double millis, bench::IncidenceStat const& stat)
|
||||
{
|
||||
data.newRow();
|
||||
data.param = param;
|
||||
data.time = stat.coveredTime / 1000;
|
||||
data.conc = stat.avgConcurrency;
|
||||
data.jobtime = stat.activeTime/stat.activationCnt;
|
||||
data.overhead = stat.timeAtConc(1) / stat.activationCnt; ////OOO not really clear if sensible
|
||||
}
|
||||
};
|
||||
|
||||
auto results = StressRig::with<Setup>()
|
||||
|
|
|
|||
|
|
@ -45,15 +45,68 @@
|
|||
** indicated by an increasing variance of the overall runtime, and a departure from
|
||||
** the nominal runtime of the executed schedule.
|
||||
**
|
||||
** Another, complimentary observation method is to inject a defined and homogeneous
|
||||
** load peak into the scheduler and then watch the time it takes to process, the
|
||||
** processing overhead and achieved degree of concurrency. The actual observation
|
||||
** using this measurement setup attempts to establish a single _control parameter_
|
||||
** as free variable, allowing to look for correlations and to build a linear
|
||||
** regression model to characterise a supposed functional dependency. Simply put,
|
||||
** given a number of fixed sizes jobs (not further correlated) as input, this
|
||||
** approach yields a »number of jobs per time unit« and »socked overhead« —
|
||||
** thereby distilling a _behaviour model_ to describe the actual stochastic data.
|
||||
**
|
||||
** ## Setup
|
||||
** To perform this test scheme, an operational Scheduler is required, and an instance
|
||||
** of the TestChainLoad must be provided, configured with desired load properties.
|
||||
** The _stressFactor_ of the corresponding generated schedule will be the active parameter
|
||||
** of this test, performing a binary search for the _breaking point._ The Measurement
|
||||
** attempts to narrow down to the point of massive failure, when the ability to somehow
|
||||
** cope with the schedule completely break down. Based on watching the Scheduler in
|
||||
** operation, the detection was linked to three conditions, which typically will
|
||||
** be triggered together, and within a narrow and reproducible parameter range:
|
||||
** Moreover, the actual measurement setup requires to perform several test executions,
|
||||
** controlling some parameters in accordance to the observation scheme. The control
|
||||
** parameters and the specifics of the actual setup should be clearly visible, while
|
||||
** hiding the complexities of measurement execution.
|
||||
**
|
||||
** This can be achieved by a »Toolbench«, which is a framework with building blocks,
|
||||
** providing a pre-arranged _measurement rig_ for the various kinds of measurement setup.
|
||||
** The implementation code is arranged as a »sandwich« structure...
|
||||
** - StressTestRig, which is also the framework class, acts as _bottom layer_ to
|
||||
** provide an anchor point, some common definitions implying an invocation scheme
|
||||
** ** first a TestChainLoad topology is constructed, based on test parameters
|
||||
** ** this is used to create a TestChainLoad::SchedulerCtx, which is then
|
||||
** outfitted specifically for each test run
|
||||
** - the _middle layer_ is a custom `Setup` class, which inherits from the bottom
|
||||
** layer and fills in the actual topology and configuration for the desired test
|
||||
** - the test performance is then initiated by layering a specific _test tool_ on
|
||||
** top of the compound, which in turn picks up the parametrisation from the Setup
|
||||
** and base configuration, visible as base class (template param) \a CONF
|
||||
** Together, this leads to the following code scheme, which aims to simplify experimentation:
|
||||
** \code
|
||||
** using StressRig = StressTestRig<16>;
|
||||
**
|
||||
** struct Setup : StressRig
|
||||
** {
|
||||
** uint CONCURRENCY = 4;
|
||||
** //// more definitions
|
||||
**
|
||||
** auto testLoad()
|
||||
** {....define a Test-Chain-Load topology....}
|
||||
**
|
||||
** auto testSetup (TestLoad& testLoad)
|
||||
** { return StressRig::testSetup(testLoad)
|
||||
** .withLoadTimeBase(500us)
|
||||
** // ....more customisation here
|
||||
** }
|
||||
** };
|
||||
**
|
||||
** auto result = StressRig::with<Setup>()
|
||||
** .perform<bench::SpecialToolClass>();
|
||||
** \endcode
|
||||
**
|
||||
** ## Breaking Point search
|
||||
** The bench::BreakingPoint tool typically uses a complex interwoven job plan, which is
|
||||
** tightened until the timing breaks. The _stressFactor_ of the generated schedule will be
|
||||
** the active parameter of this test, performing a _binary search_ for the _breaking point._
|
||||
** The Measurement attempts to narrow down to the point of massive failure, when the ability
|
||||
** to somehow cope with the schedule completely break down. Based on watching the Scheduler
|
||||
** in operation, the detection was linked to three conditions, which typically will be
|
||||
** triggered together, and within a narrow and reproducible parameter range:
|
||||
** - an individual run counts as _accidentally failed_ when the execution slips
|
||||
** away by more than 2ms with respect to the defined overall schedule. When more
|
||||
** than 55% of all observed runs are considered as failed, the first condition is met
|
||||
|
|
@ -63,18 +116,24 @@
|
|||
** - the third condition is that the ''averaged delta'' has surpassed 4ms,
|
||||
** which is 2 times the basic failure indicator.
|
||||
**
|
||||
** ## Observation tools
|
||||
** As a complement to the bench::BreakingPoint tool, another tool is provided to
|
||||
** run a specific Scheduler setup while varying a single control parameter within
|
||||
** defined limits. This produces a set of (x,y) data, which can be used to search
|
||||
** for correlations or build a linear regression model to describe the Scheduler's
|
||||
** behaviour as function of the control parameter. The typical use case would be
|
||||
** to use the input length (number of Jobs) as control parameter, leading to a
|
||||
** model for the Scheduler's expense.
|
||||
** ## Parameter Correlation
|
||||
** As a complement, the bench::ParameterRange tool is provided to run a specific Scheduler setup
|
||||
** while varying a single control parameter within defined limits. This produces a set of (x,y) data,
|
||||
** which can be used to search for correlations or build a linear regression model to describe the
|
||||
** Scheduler's behaviour as function of the control parameter. The typical use case would be to use
|
||||
** the input length (number of Jobs) as control parameter, leading to a model for Scheduling expense.
|
||||
**
|
||||
** ## Observation tools
|
||||
** The TestChainLoad, together with its helpers and framework, already offers some tools to visualise
|
||||
** the generated topology and to calculate statistics, and to watch an performance with instrumentation.
|
||||
** In addition, the individual tools provide some debugging output to watch the measurement scheme.
|
||||
** Result data is either a tuple of values (in case of bench::BreakingPoint), or a table of result
|
||||
** data as function of the control parameter (for bench::ParameterRange). Result data, when converted
|
||||
** to CSV, can be visualised as Gnuplot diagram.
|
||||
** @see TestChainLoad_test
|
||||
** @see SchedulerStress_test
|
||||
** @see binary-search.hpp
|
||||
** @see gnuplot-gen.hpp
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -109,40 +168,18 @@ namespace vault{
|
|||
namespace gear {
|
||||
namespace test {
|
||||
|
||||
using util::_Fmt;
|
||||
using util::min;
|
||||
using util::max;
|
||||
// using util::isnil;
|
||||
// using util::limited;
|
||||
// using util::unConst;
|
||||
// using util::toString;
|
||||
// using util::isLimited;
|
||||
// using lib::time::Time;
|
||||
// using lib::time::TimeValue;
|
||||
// using lib::time::FrameRate;
|
||||
// using lib::time::Duration;
|
||||
// using lib::test::Transiently;
|
||||
// using lib::meta::_FunRet;
|
||||
|
||||
// using std::string;
|
||||
// using std::function;
|
||||
using std::make_pair;
|
||||
using std::make_tuple;
|
||||
// using std::forward;
|
||||
// using std::string;
|
||||
// using std::swap;
|
||||
using std::vector;
|
||||
using std::move;
|
||||
|
||||
namespace err = lumiera::error; //////////////////////////TODO RLY?
|
||||
|
||||
namespace { // Default definitions ....
|
||||
|
||||
}
|
||||
using std::forward;
|
||||
|
||||
|
||||
|
||||
/** configurable template framework for running Scheduler Stress tests */
|
||||
/**
|
||||
* Configurable template framework for running Scheduler Stress tests
|
||||
* Use to build a custom setup class, which is then [injected](\ref StressTestRig::with)
|
||||
* to [perform](\ref StressTestRig::Launcher::perform) a _specific measurement tool._
|
||||
* Several tools and detailed customisations are available in `namespace bench`
|
||||
* - bench::BreakingPoint conducts a binary search to _break a schedule_
|
||||
* - bench::ParameterRange performs a randomised series of parametrised test runs
|
||||
*/
|
||||
template<size_t maxFan =DEFAULT_FAN>
|
||||
class StressTestRig
|
||||
: util::NonCopyable
|
||||
|
|
@ -226,6 +263,10 @@ namespace test {
|
|||
|
||||
namespace bench { ///< Specialised tools to investigate scheduler performance
|
||||
|
||||
using util::_Fmt;
|
||||
using util::min;
|
||||
using util::max;
|
||||
using std::vector;
|
||||
using std::declval;
|
||||
|
||||
|
||||
|
|
@ -417,33 +458,6 @@ namespace test {
|
|||
|
||||
|
||||
|
||||
using lib::stat::Column;
|
||||
using lib::stat::DataFile;
|
||||
using lib::stat::CSVData;
|
||||
using IncidenceStat = lib::IncidenceCount::Statistic;
|
||||
|
||||
template<typename PAR>
|
||||
struct DataRow
|
||||
{
|
||||
Column<PAR> param {"test param"}; // independent variable / control parameter
|
||||
Column<double> time {"result time"};
|
||||
Column<double> conc {"concurrency"};
|
||||
Column<double> jobtime {"avg jobtime"};
|
||||
Column<double> overhead{"overhead"};
|
||||
|
||||
auto allColumns()
|
||||
{ return std::tie(param
|
||||
,time
|
||||
,conc
|
||||
,jobtime
|
||||
,overhead
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename PAR>
|
||||
using DataTable = DataFile<DataRow<PAR>>;
|
||||
|
||||
|
||||
|
||||
/**************************************************//**
|
||||
|
|
@ -455,12 +469,13 @@ namespace test {
|
|||
class ParameterRange
|
||||
: public CONF
|
||||
{
|
||||
using Table = typename CONF::Table;
|
||||
using Param = typename CONF::Param;
|
||||
|
||||
using TestLoad = typename CONF::TestLoad;
|
||||
using TestSetup = typename TestLoad::ScheduleCtx;
|
||||
|
||||
// Type binding for data evaluation
|
||||
using Param = typename CONF::Param;
|
||||
using Table = typename CONF::Table;
|
||||
|
||||
|
||||
void
|
||||
runTest (Param param, Table& data)
|
||||
|
|
@ -507,6 +522,61 @@ namespace test {
|
|||
return results;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* ====== Preconfigured ParamRange-Evaluations ====== */
|
||||
|
||||
using lib::stat::Column;
|
||||
using lib::stat::DataTable;
|
||||
using lib::stat::CSVData;
|
||||
using IncidenceStat = lib::IncidenceCount::Statistic;
|
||||
|
||||
/**
|
||||
* Mix-in for setup of a #ParameterRange evaluation to watch
|
||||
* the processing of a single load peak, using the number of
|
||||
* added job as independent parameter.
|
||||
* @remark inject this definition (by inheritance) into the
|
||||
* Setup, which should then also define a TestChainLoad
|
||||
* graph with an overall size controlled by the #Param
|
||||
* @see SchedulerStress_test#watch_expenseFunction()
|
||||
*/
|
||||
struct LoadPeak_ParamRange_Evaluation
|
||||
{
|
||||
using Param = size_t;
|
||||
|
||||
struct DataRow
|
||||
{
|
||||
Column<Param> param {"load size"}; // independent variable / control parameter
|
||||
Column<double> time {"result time"};
|
||||
Column<double> conc {"concurrency"};
|
||||
Column<double> jobtime {"avg jobtime"};
|
||||
Column<double> overhead{"overhead"};
|
||||
|
||||
auto allColumns()
|
||||
{ return std::tie(param
|
||||
,time
|
||||
,conc
|
||||
,jobtime
|
||||
,overhead
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
using Table = DataTable<DataRow>;
|
||||
|
||||
void
|
||||
collectResult(Table& data, Param param, double millis, bench::IncidenceStat const& stat)
|
||||
{
|
||||
(void)millis;
|
||||
data.newRow();
|
||||
data.param = param;
|
||||
data.time = stat.coveredTime / 1000;
|
||||
data.conc = stat.avgConcurrency;
|
||||
data.jobtime = stat.activeTime/stat.activationCnt;
|
||||
data.overhead = stat.timeAtConc(1) / stat.activationCnt; ////OOO not really clear if sensible
|
||||
}
|
||||
};
|
||||
//
|
||||
}// namespace bench
|
||||
}}}// namespace vault::gear::test
|
||||
|
|
|
|||
|
|
@ -114732,7 +114732,7 @@ std::cout << tmpl.render({"what", "World"}) << s
|
|||
<node CREATED="1712183753046" ID="ID_1287892532" MODIFIED="1712183793104" TEXT="DataFile als RVO-Parameter einführen"/>
|
||||
<node CREATED="1712183793908" ID="ID_1299689687" MODIFIED="1712183813221" TEXT="Referenz darauf anstatt dem Tupel in die runTest(data) geben"/>
|
||||
</node>
|
||||
<node CREATED="1712183881848" ID="ID_277756370" MODIFIED="1712190772873" TEXT="Probleme dabei...">
|
||||
<node BACKGROUND_COLOR="#c8b6b6" COLOR="#690f14" CREATED="1712183881848" ID="ID_277756370" MODIFIED="1712539750718" TEXT="Probleme dabei...">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1712183893055" ID="ID_1518548729" MODIFIED="1712183902505" TEXT="Table-Def muß öffentlich werden"/>
|
||||
<node CREATED="1712183903573" ID="ID_1522610699" MODIFIED="1712183933315" TEXT="der »offen gelassene« Parameter-Typ PAR macht das alles etwas kniffelig"/>
|
||||
|
|
@ -114935,7 +114935,7 @@ std::cout << tmpl.render({"what", "World"}) << s
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1712370539491" ID="ID_1967428575" MODIFIED="1712370557205" TEXT="Layered Setup wird zunehmend problematisch">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1712370539491" ID="ID_1967428575" MODIFIED="1712539460762" TEXT="Layered Setup wird zunehmend problematisch">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1712370558825" ID="ID_1505316994" MODIFIED="1712370586641" TEXT="Widerspruch virtuell ⟷ generisch"/>
|
||||
<node CREATED="1712370587541" ID="ID_1522410406" MODIFIED="1712370603477" TEXT="was ich eigentlich möchte: »hier zur Hand«">
|
||||
|
|
@ -114947,7 +114947,8 @@ std::cout << tmpl.render({"what", "World"}) << s
|
|||
<node CREATED="1712370655378" ID="ID_205661748" MODIFIED="1712370660087" TEXT="rein formal-technisch">
|
||||
<node CREATED="1712370665227" ID="ID_1870575473" MODIFIED="1712370678645" TEXT="...würde das nach einem dynamischen Scope verlangen"/>
|
||||
<node CREATED="1712370682448" ID="ID_481728399" MODIFIED="1712370697486" TEXT="in dem auf allen Ebenen noch Methoden und Konstanten überlagert werden können"/>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1712370716979" ID="ID_923685396" MODIFIED="1712438645589" TEXT="dem stehen Limitierungen der Sprache im Wege">
|
||||
<node BACKGROUND_COLOR="#ecdf98" COLOR="#a50125" CREATED="1712370716979" ID="ID_923685396" MODIFIED="1712539643386" TEXT="dem stehen Limitierungen der Sprache im Wege">
|
||||
<arrowlink COLOR="#cf0467" DESTINATION="ID_1597269294" ENDARROW="Default" ENDINCLINATION="-91;9;" ID="Arrow_ID_156565320" STARTARROW="None" STARTINCLINATION="253;268;"/>
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1712438658067" ID="ID_108928226" MODIFIED="1712438666881" TEXT="keine Reflection"/>
|
||||
<node CREATED="1712438674412" ID="ID_833076441" MODIFIED="1712438688559" TEXT="keine Auswertungen auf Klassen-Scope"/>
|
||||
|
|
@ -114958,23 +114959,135 @@ std::cout << tmpl.render({"what", "World"}) << s
|
|||
<node CREATED="1712438854479" ID="ID_892223823" MODIFIED="1712438877962" TEXT="das ist potentiell gefährlich"/>
|
||||
<node CREATED="1712438878693" ID="ID_1350971341" MODIFIED="1712438912614" TEXT="und verhindert das Mischen von Konstanten und default-Methoden"/>
|
||||
</node>
|
||||
<node CREATED="1712438940621" ID="ID_567981926" MODIFIED="1712439567292" TEXT="Richtlinie ⟹ Konfiguration in testSetup()-Methode verlagern">
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1712443577073" ID="ID_392914682" MODIFIED="1712443583609" TEXT="brauche dafür eine klare Notation">
|
||||
<icon BUILTIN="flag-pink"/>
|
||||
<node COLOR="#435e98" CREATED="1712438940621" ID="ID_567981926" MODIFIED="1712539629436" TEXT="Richtlinie ⟹ Konfiguration in testSetup()-Methode verlagern">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node BACKGROUND_COLOR="#d9b073" COLOR="#900119" CREATED="1712443577073" ID="ID_392914682" MODIFIED="1712536000043" TEXT="brauche dafür eine klare Notation">
|
||||
<icon BUILTIN="closed"/>
|
||||
<node CREATED="1712443590806" ID="ID_1885394541" MODIFIED="1712443606819" TEXT="Idee: Setup-Datentyp">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1712443645159" ID="ID_222818686" MODIFIED="1712535946564" TEXT="Schwierigkeit: erst konkretes Tool legt den TestLoad-Typ fest">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...man würde also bereits ganz von Grund auf einen Hüllen-Container bzw. eine virtuelle Schnittstelle brauchen — und ich wollte hier exakt den entgegengesetzten Weg gehen, mit lauter konkreten, weitgehend lokal definierten Typen und daher auch Template-Parametern für die Breite des Graphen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#e302a0" CREATED="1712535412188" ID="ID_264329664" MODIFIED="1712539391510" TEXT="Quäle mich zwei Tage lang sinnlos mit dieser Idee herum">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="13"/>
|
||||
<icon BUILTIN="smily_bad"/>
|
||||
<node COLOR="#5b280f" CREATED="1712535472863" ID="ID_1597269294" MODIFIED="1712539439342" TEXT="das geht so nicht in C++">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<ul>
|
||||
<li>
|
||||
kann nicht einfach ausführbaren Code in einen Klassenrumpf schreiben (wie in Scala oder Python)
|
||||
</li>
|
||||
<li>
|
||||
kann keine Parameter eines Basis-Typs dynamisch / late-binding modifizieren
|
||||
</li>
|
||||
<li>
|
||||
kann keine virtuelle Funktion über generische Parameter arbeiten lassen
|
||||
</li>
|
||||
<li>
|
||||
Typen aus Template-Basisklassen werden erst durch explizite Typedefs sichtbar ⟹ schwer lesbar
|
||||
</li>
|
||||
<li>
|
||||
Template-Parameter einer Basis / Framework-Klasse müssen ganz zu Beginn schon feststehen, und können sich nicht aus konkreten Spezialisierungen ergeben
|
||||
</li>
|
||||
<li>
|
||||
es sei denn... man würde ein sehr komplexes Framework mit Wrapper-Typen bauen, und darüber einen »Deckel« setzen, der dann alles zusammenlinkt; ein solcher Ansatz wäre <i>vielleicht machbar (sicher Wochen an Arbeit) </i>— dann aber wohl so komplex, daß selbst C++ -  Experten nicht mehr auf Anhieb sehen, was gespielt wird.
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<linktarget COLOR="#cf0467" DESTINATION="ID_1597269294" ENDARROW="Default" ENDINCLINATION="-91;9;" ID="Arrow_ID_156565320" SOURCE="ID_923685396" STARTARROW="None" STARTINCLINATION="253;268;"/>
|
||||
<icon BUILTIN="stop-sign"/>
|
||||
</node>
|
||||
<node COLOR="#5e022b" CREATED="1712535478828" ID="ID_669931256" MODIFIED="1712535551431" TEXT="verdammt noch einmal ������☢��">
|
||||
<font NAME="SansSerif" SIZE="16"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1712536005711" ID="ID_88618902" MODIFIED="1712539848183" TEXT="Kompromiß-Lösung">
|
||||
<linktarget COLOR="#485b90" DESTINATION="ID_88618902" ENDARROW="Default" ENDINCLINATION="-10;50;" ID="Arrow_ID_693388546" SOURCE="ID_1123688435" STARTARROW="None" STARTINCLINATION="173;12;"/>
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1712536021629" ID="ID_927200163" MODIFIED="1712536051558" TEXT="Ansprüche zurückschrauben — Lesbarkeit ist wichtig">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node CREATED="1712536057096" ID="ID_70554973" MODIFIED="1712536083969" TEXT="Konstanten nur verwenden, insofern sie das eigentliche Tool-Verhalten steuern"/>
|
||||
<node CREATED="1712536084840" ID="ID_1196331192" MODIFIED="1712536102173" TEXT="alles Setup in eine einzige verkettete Methode testSetup() legen"/>
|
||||
<node CREATED="1712536102986" ID="ID_1903004341" MODIFIED="1712536116612" TEXT="in dieser Methode nur direkt die Test-Chain-Load-DSL verwenden"/>
|
||||
<node CREATED="1712536121655" ID="ID_433760929" MODIFIED="1712536131634" TEXT="als Binding...">
|
||||
<node CREATED="1712536132606" ID="ID_988672862" MODIFIED="1712536173898">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
direkt im Test: <font face="Monospaced" color="#202ab8">using StressRig = StressTestRig<16>;</font>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1712536178036" ID="ID_862077862" MODIFIED="1712536197371" TEXT="Hilfstypen + Tabelle in ein Mix-In auslagern">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1712539464952" ID="ID_234485789" MODIFIED="1712539487821">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
<b>Fazit</b>: knapp am Abgrund vorbei
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<node CREATED="1712539492581" ID="ID_1123688435" MODIFIED="1712539854967" TEXT="es bleibt eine fragile und komplexe Lösung">
|
||||
<arrowlink COLOR="#485b90" DESTINATION="ID_88618902" ENDARROW="Default" ENDINCLINATION="-10;50;" ID="Arrow_ID_693388546" STARTARROW="None" STARTINCLINATION="173;12;"/>
|
||||
</node>
|
||||
<node CREATED="1712539511301" ID="ID_948886158" MODIFIED="1712539529212" TEXT="aber ich konnte die Notation soweit „einfangen“"/>
|
||||
<node COLOR="#101055" CREATED="1712539530040" ID="ID_1981096404" MODIFIED="1712539822331">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Tests <i>sehen einfach aus... </i>
|
||||
</p>
|
||||
<p>
|
||||
und sind <i>leicht anpassbar</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<linktarget COLOR="#458191" DESTINATION="ID_1981096404" ENDARROW="Default" ENDINCLINATION="-160;25;" ID="Arrow_ID_784328672" SOURCE="ID_1714941979" STARTARROW="None" STARTINCLINATION="131;9;"/>
|
||||
<icon BUILTIN="forward"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1712539790060" ID="ID_1714941979" MODIFIED="1712539828859" TEXT="hab die Test-Definition jetzt soweit im Griff">
|
||||
<arrowlink COLOR="#458191" DESTINATION="ID_1981096404" ENDARROW="Default" ENDINCLINATION="-160;25;" ID="Arrow_ID_784328672" STARTARROW="None" STARTINCLINATION="131;9;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1712190783314" ID="ID_561451802" MODIFIED="1712238531623" TEXT="Gnuplot-Skript generieren">
|
||||
<linktarget COLOR="#4a8bb7" DESTINATION="ID_561451802" ENDARROW="Default" ENDINCLINATION="330;-389;" ID="Arrow_ID_787725069" SOURCE="ID_109820250" STARTARROW="None" STARTINCLINATION="191;23;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1712364733453" ID="ID_1252919239" MODIFIED="1712364934156" TEXT="setup in HIlfsfunktion im Stress-Test-Rig verlagen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1712364733453" ID="ID_1252919239" MODIFIED="1712539694378" TEXT="setup in HIlfsfunktion im Stress-Test-Rig verlagen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1712539700049" ID="ID_791898063" MODIFIED="1712539724079" TEXT="tatsächlich als Mix-in realisiert">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1712539707366" ID="ID_1463647276" MODIFIED="1712539724078" TEXT="steht im Code zusammen mit der Datenauswertung"/>
|
||||
</node>
|
||||
<node CREATED="1712364714975" ID="ID_1343230425" MODIFIED="1712364731729" TEXT="Anpassungen">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1712364780151" ID="ID_1769816620" MODIFIED="1712364932636" TEXT="Regressions-Parameter anzeigen">
|
||||
|
|
|
|||
Loading…
Reference in a new issue