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:
parent
a68adb0364
commit
754b3a2ea6
3 changed files with 165 additions and 14 deletions
|
|
@ -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");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -111003,7 +111003,29 @@ Date:   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 — kein Reset mö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 — thread_local ist implizit statisch (oder global)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Aus Performance-Gründen möchte ich für jeden separaten Thread eine initial belegte slotID haben, so daß der Thread direkt ohne weiteres Locking mit seinen separaten Daten arbeiten kann. Dafür muß ich für neu auftauchende Threads immer die nächste ID vergeben, brauche also einen atomaren counter. Da aber jeder Thread dann seine ID kennen muß, brauche ich zudem eine thread_local-Variable, in der er sich seinen Slot merken kann. Und damit tut sich ein Dilemma auf: ein übergreifendes Management von Instanzen wird richtig komplex, besonders dann, wenn es auch noch performant sein soll. Daher der KISS-Beschluß ⟹ das gesamte Thema wird auf den User abgewä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ähig aber vor-dimensionierbar"/>
|
||||
<node CREATED="1707754346219" ID="ID_70463862" MODIFIED="1707754354568" TEXT="nachträgliche Statistik-Berechnung">
|
||||
<node CREATED="1707754377665" ID="ID_1715084685" MODIFIED="1707754382860" TEXT="kumulierte Aktiv-Zeit"/>
|
||||
|
|
@ -111013,23 +111035,23 @@ Date:   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ückenlosen eindeutigen Thread-ID">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1707754582085" ID="ID_1743945344" MODIFIED="1707765867440" TEXT="belegen einer lü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ß-Eingänge">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue