From 26b2e6f1bd883457263ffd5045827657ca80dcfc Mon Sep 17 00:00:00 2001
From: Ichthyostega
Date: Fri, 20 Oct 2023 18:24:50 +0200
Subject: [PATCH] Scheduler: solve the initialisation of WorkForce
Notably I wanted an entirely static and direct binding
to the internals of the Scheduler, which can be completely inlined.
The chosen solution also has the benefit of making the back-reference
to the Scheduler explicitly visible to the reader. This is relevant,
since the Config-Subobject is *copied* into each Worker instance.
---
src/vault/gear/scheduler.hpp | 35 ++++++++++----
src/vault/gear/work-force.hpp | 5 +-
wiki/thinkPad.ichthyo.mm | 90 +++++++++++++++++++++++++++++++----
3 files changed, 108 insertions(+), 22 deletions(-)
diff --git a/src/vault/gear/scheduler.hpp b/src/vault/gear/scheduler.hpp
index 4d635d9f5..ebd80adf0 100644
--- a/src/vault/gear/scheduler.hpp
+++ b/src/vault/gear/scheduler.hpp
@@ -63,9 +63,17 @@ namespace gear {
// using util::isnil;
// using std::string;
+ namespace { // Scheduler default config
+
+ const auto IDLE_WAIT = 20ms;
+ const size_t DISMISS_CYCLES = 100;
+ }
- /**
- * Schedule and coordinate render activities.
+
+
+
+ /******************************************************//**
+ * »Scheduler-Service« : coordinate render activities.
* @todo WIP-WIP 6/2023
* @see BlockFlow
* @see SchedulerUsage_test
@@ -73,23 +81,30 @@ namespace gear {
class Scheduler
: util::NonCopyable
{
- using Setup = work::Config; ////////////////////////////////////////////////////OOO actually need subclass to attach the work-function
+ /** Binding of worker callbacks to the scheduler implementation */
+ struct Setup : work::Config
+ {
+ Scheduler& scheduler;
+ activity::Proc doWork() { return scheduler.getWork(); }
+ void finalHook (bool _) { scheduler.handleWorkerTermination(_);}
+ };
+
SchedulerInvocation layer1_;
SchedulerCommutator layer2_;
-// WorkForce workForce_;
+ WorkForce workForce_;
ActivityLang activityLang_;
LoadController loadControl_;
EngineObserver& engineObserver_;
+
public:
- explicit
Scheduler (BlockFlowAlloc& activityAllocator
,EngineObserver& engineObserver)
: layer1_{}
, layer2_{}
-// , workForce_{connectWorkers()}
+ , workForce_{Setup{IDLE_WAIT, DISMISS_CYCLES, *this}}
, activityLang_{activityAllocator}
, loadControl_{activityAllocator}
, engineObserver_{engineObserver}
@@ -139,17 +154,17 @@ namespace gear {
/**
*
*/
- void
+ activity::Proc
getWork()
{
UNIMPLEMENTED("the Worker-Funkction");
}
private:
- Setup
- connectWorkers()
+ void
+ handleWorkerTermination (bool isFailure)
{
- UNIMPLEMENTED("build Worker pool operational setup");
+ UNIMPLEMENTED("die harder");
}
};
diff --git a/src/vault/gear/work-force.hpp b/src/vault/gear/work-force.hpp
index a0246c362..4c9fc195c 100644
--- a/src/vault/gear/work-force.hpp
+++ b/src/vault/gear/work-force.hpp
@@ -72,12 +72,12 @@ namespace gear {
using std::move;
using std::atomic;
using util::unConst;
+ using std::chrono::milliseconds;
+ using std::chrono_literals::operator ""ms;
using std::this_thread::sleep_for;
namespace work { ///< Details of WorkForce (worker pool) implementation
- using std::chrono::milliseconds;
- using std::chrono_literals::operator ""ms;
using SIG_WorkFun = activity::Proc(void); ///< config should define a callable with this signature to perform work
using SIG_FinalHook = void(bool); ///< config should define callable invoked at exit (argument: isFailure)
@@ -94,7 +94,6 @@ namespace gear {
struct Config
{
static const size_t COMPUTATION_CAPACITY;
- const size_t EXPECTED_MAX_POOL = 1.5*COMPUTATION_CAPACITY;
const milliseconds IDLE_WAIT = 20ms;
const size_t DISMISS_CYCLES = 100;
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 258d26988..d85580a0b 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -81765,15 +81765,44 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
+
-
-
-
+
+
+
+
+
+
+ Schwere Geburt...
+
+
+ Irgendwie hatte sich bei mir die Idee mit den Lambdas so festgefressen — obwohl ich doch schon eingesehen hatte, daß C++ in der Hinsicht (aus gutem Grund) sehr konsequent ist, und keine Hintertür bietet, um Laufzeit-Bindigns in die statische Ebene „zu schmuggeln“. Was mich dann aber auch extrem gestört hat, waren die std::function-Felder, in die man die Lambdas speichern müßte. Es wäre nämlich eine andere Lösung denkbar, bei der diese Function-Objekte schon in der Basis-Config für die WorkForce enthalten sind; damit wäre das Design auch komplett festgelgt (und der Test würde sogar einfacher). Trotzdem habe ich eine Abneigung gegen diese Function-Objekte, weil sie eben komplett unnötig sind, da es sich effektiv um ein statisches Binding handeln sollte. Und das war dann das rettende Stichwort: dann definiert man eben diese Binding-Forwarder als statische Funktionen in einer nested Class, und macht die Rückreferenz auf den Scheduler explizit. Und mit Aggregat-Initialisierung kann man dann sogar noch die Definition des Konstruktors auslassen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -81799,6 +81828,19 @@ Date: Thu Apr 20 18:53:17 2023 +0200
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -84509,7 +84551,7 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
+
@@ -84520,10 +84562,21 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
-
+
+
+
+
+
+
+
+ Denn jeder Aufruf des Fork-Funktors wird unterschiedlich lang dauern. Und selbst wenn alle Worker idle sind: dann gibt es bei der ersten Runde die Mega-Contention, und danach liegen die Wartezyklen aller Worker leicht gestaffelt. Contention wäre nur dann ein Problem, wenn jemand, der arbeiten könnte, vom Arbeiten abgehalten wird.
+
+
+
+
+
@@ -84666,7 +84719,7 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
+
@@ -84675,6 +84728,23 @@ Date: Thu Apr 20 18:53:17 2023 +0200
+
+
+
+
+
+ ...wie so oft, vor allem getrieben durch die Tests: die Layer wurden zu einer Sammlung von Implementierungs-Bausteienen, welche auch aufeinander aufbauen. Aber die große Verdrahtung habe ich noch vor mir hergeschoben — sogar so weit, daß Layer-2 selbst keine Referenz auf Layer-1 besitzt (sondern diese für jede Funktion hereingereicht bekommt). Damit wird die Verdrahtung nun sternförmig, und der Binde-Code ist das, was den »Scheduler-Service« ausmacht
+
+
+
+
+
+
+
+
+
+
+
@@ -84741,6 +84811,7 @@ Date: Thu Apr 20 18:53:17 2023 +0200
+
@@ -84819,10 +84890,11 @@ Date: Thu Apr 20 18:53:17 2023 +0200
- C++ zwingt uns dazu, explizit das zu tun was ohnehin getan werden muß; da jedoch der Typ der Config per Template-Parameter gewählt wird, ist komplettes Inlining möglich; letztlich wird daher nur ein Pointer auf das Scheduler-Objekt in alle Threads kopiert — exakt das was wir brauchen
+ C++ zwingt uns dazu, explizit das zu tun was ohnehin getan werden muß; da jedoch der Typ der Config per Template-Parameter gewählt wird, ist komplettes Inlining möglich; letztlich wird daher nur ein Pointer auf das Scheduler-Objekt in alle Threads kopiert — exakt das was wir brauchen
+