Scheduler-test: define storage for instrumentation helper

...using a simplistic allocation of next-slot based on initialisation
of a thread_local storage. This implies that this helper can not be
reset or reused, and that there can not be multiple or long-lived instances.

Keep-it-simple for now...
This commit is contained in:
Fischlurch 2024-02-12 20:26:38 +01:00
parent a68adb0364
commit 754b3a2ea6
3 changed files with 165 additions and 14 deletions

View file

@ -30,6 +30,14 @@
** a thread local ID is constructed, thereby incrementing an global atomic counter.
** Statistics evaluation is comprised of integrating and sorting the captured
** event log, followed by a summation pass.
**
** # Usage and limitations
** This helper is intended for tests and one-time usage. Create an instance,
** launch a test, retrieve the observed statistics, destroy the object. Each
** separate Threads encountered gets the next consecutive ID. Thus it is *not possible*
** to have long-living instances or even multiple instances of IncidenceCount; doing so
** would require a much more elaborate ID management, which is beyond requirement's scope.
**
** @see IncidenceCount_test
** @see vault::gear::TestChainLoad::ScheduleCtx
** @see SchedulerStress_test
@ -41,17 +49,128 @@
//#include "lib/meta/function.hpp"
#include "lib/nocopy.hpp"
//#include <utility>
#include <cstdint>
#include <atomic>
#include <vector>
#include <chrono>
#include <limits>
namespace lib {
// using std::forward;
/**
* A recorder for concurrent incidences.
* Start and end of individual activations are recorded by direct calls,
* automatically detecting the thread identity; for further differentiation,
* an additional `caseID` can be given. Accumulated observations can be
* integrated into a statistics evaluation.
* @warning never operate multiple instances of this helper at the same time
*/
class IncidenceCount
: util::NonCopyable
{
using TIMING_SCALE = std::micro; // Results are in µ-sec
using Clock = std::chrono::steady_clock;
using Instance = decltype(Clock::now());
using Dur = std::chrono::duration<double, TIMING_SCALE>;
struct Inc
{
Instance when{};
uint8_t thread :8;
uint8_t caseID :8;
bool isLeave :1;
};
using Sequence = std::vector<Inc>;
using Recording = std::vector<Sequence>;
Recording rec_;
std::atomic_uint8_t slotID_{0};
/** threadsafe allocation of thread/slotID */
uint8_t
allocateNextSlot()
{ // Note : returning previous value before increment
return slotID_.fetch_add(+1, std::memory_order_relaxed);
}
uint8_t
getMySlot()
{
thread_local uint8_t threadID{allocateNextSlot()};
ASSERT (threadID < std::numeric_limits<uint8_t>::max(), "WOW -- so many threads?");
return threadID;
}
Sequence
getMySequence()
{
uint8_t id{getMySlot()};
if (id >= rec_.size())
{
rec_.reserve (id);
for (size_t i = rec_.size(); i < id; ++i)
rec_.emplace_back();
}
return rec_[id];
}
public:
IncidenceCount() = default;
IncidenceCount&
expectThreads(uint8_t cnt)
{
REQUIRE (cnt);
rec_.reserve (cnt);
for ( ; cnt; --cnt)
rec_.emplace_back();
return *this;
}
IncidenceCount&
expectIncidents(size_t cnt)
{
REQUIRE (cnt);
for (Sequence& s : rec_)
s.reserve (cnt);
return *this;
}
/* ===== Measurement API ===== */
void
markEnter(uint8_t caseID =0)
{
UNIMPLEMENTED ("Incidence measurement");
}
void
markLeave(uint8_t caseID =0)
{
UNIMPLEMENTED ("Incidence measurement");
}
/* ===== Evaluations ===== */
double
calcCumulatedTime()
{
UNIMPLEMENTED ("Evaluation");
}
};

View file

@ -26,7 +26,7 @@
#include "lib/test/run.hpp"
#include "lib/format-cout.hpp"//////////////TODO RLY?
#include "lib/test/diagnostic-output.hpp"//////////////TODO RLY?
#include "lib/incidence-count.hpp"
//#include <string>
@ -35,6 +35,7 @@
//using std::string;
using std::this_thread::sleep_for;
using std::chrono_literals::operator ""ms;
namespace lib {
@ -66,6 +67,15 @@ namespace test{
void
demonstrate_usage()
{
IncidenceCount watch;
watch.markEnter();
sleep_for (1ms);
watch.markLeave();
double time = watch.calcCumulatedTime();
SHOW_EXPR(time)
CHECK (time > 900);
CHECK (time < 1100);
}

View file

@ -111003,7 +111003,29 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</html>
</richcontent>
</node>
<node CREATED="1707754287446" ID="ID_1946786749" MODIFIED="1707754298871" TEXT="erlaubt einen Daten-Reset"/>
<node CREATED="1707754287446" ID="ID_1946786749" MODIFIED="1707764788791" TEXT="Einmal / Wegwerf-Objekt &#x2014; kein Reset m&#xf6;glich">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1707764803549" ID="ID_512591097" MODIFIED="1707764837542" TEXT="eigentlich wollte ich das genaue Gegenteil">
<icon BUILTIN="smily_bad"/>
</node>
<node CREATED="1707764811980" ID="ID_237325015" MODIFIED="1707765252943" TEXT="aber das geht nicht &#x2014; thread_local ist implizit statisch (oder global)">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Aus Performance-Gr&#252;nden m&#246;chte ich f&#252;r jeden separaten Thread eine initial belegte slotID haben, so da&#223; der Thread direkt ohne weiteres Locking mit seinen separaten Daten arbeiten kann. Daf&#252;r mu&#223; ich f&#252;r neu auftauchende Threads immer die n&#228;chste ID vergeben, brauche also einen atomaren counter. Da aber jeder Thread dann seine ID kennen mu&#223;, brauche ich zudem eine thread_local-Variable, in der er sich seinen Slot merken kann. Und damit tut sich ein Dilemma auf: ein &#252;bergreifendes Management von Instanzen wird richtig komplex, besonders dann, wenn es auch noch performant sein soll. Daher der KISS-Beschlu&#223; &#10233; das gesamte Thema wird auf den User abgew&#228;ltzt
</p>
</body>
</html>
</richcontent>
</node>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1707764840510" ID="ID_302736823" MODIFIED="1707764853515" TEXT="also dann ... KISS">
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
</node>
</node>
<node CREATED="1707754306402" ID="ID_1000855981" MODIFIED="1707754339123" TEXT="Datenspeicher wachstumsf&#xe4;hig aber vor-dimensionierbar"/>
<node CREATED="1707754346219" ID="ID_70463862" MODIFIED="1707754354568" TEXT="nachtr&#xe4;gliche Statistik-Berechnung">
<node CREATED="1707754377665" ID="ID_1715084685" MODIFIED="1707754382860" TEXT="kumulierte Aktiv-Zeit"/>
@ -111013,23 +111035,23 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1707754450711" ID="ID_910369325" MODIFIED="1707754945117" TEXT="Implementierung">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1707754455351" ID="ID_1263178646" MODIFIED="1707754598476" TEXT="Rahmen">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1707754460590" ID="ID_1078644826" MODIFIED="1707754601796" TEXT="Lib-Implementierung">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1707754455351" ID="ID_1263178646" MODIFIED="1707765868713" TEXT="Rahmen">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1707754460590" ID="ID_1078644826" MODIFIED="1707765871131" TEXT="Lib-Implementierung">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1707754467269" ID="ID_124517380" MODIFIED="1707754601796" TEXT="Unit-Test">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1707754467269" ID="ID_124517380" MODIFIED="1707757261847" TEXT="Unit-Test">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1707754482411" ID="ID_1352527465" MODIFIED="1707754601796" TEXT="Heap-allozierte Datenstruktur">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1707754482411" ID="ID_1352527465" MODIFIED="1707765872398" TEXT="Heap-allozierte Datenstruktur">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1707754582085" ID="ID_1743945344" MODIFIED="1707754597885" TEXT="belegen einer l&#xfc;ckenlosen eindeutigen Thread-ID">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1707754582085" ID="ID_1743945344" MODIFIED="1707765867440" TEXT="belegen einer l&#xfc;ckenlosen eindeutigen Thread-ID">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1707754857153" ID="ID_259283020" MODIFIED="1707754870587" TEXT="Reset und Dimensionierung">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1707754857153" ID="ID_259283020" MODIFIED="1707765866391" TEXT="Dimensionierung und automatische Allokation">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1707754606698" ID="ID_1650260006" MODIFIED="1707754614458" TEXT="Me&#xdf;-Eing&#xe4;nge">
<icon BUILTIN="flag-yellow"/>