From 38ab5a6aa94af41ba3008d566df3d9b8cc2beda8 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 4 Sep 2023 23:48:12 +0200 Subject: [PATCH] Workforce: draft simple usage ...start with an oversimplified implementation... --- src/vault/gear/work-force.cpp | 4 ++ src/vault/gear/work-force.hpp | 66 ++++++++++++++++++++++++---- tests/vault/gear/work-force-test.cpp | 6 +-- wiki/renderengine.html | 4 +- wiki/thinkPad.ichthyo.mm | 9 ++++ 5 files changed, 76 insertions(+), 13 deletions(-) diff --git a/src/vault/gear/work-force.cpp b/src/vault/gear/work-force.cpp index 5f3005b93..31423df24 100644 --- a/src/vault/gear/work-force.cpp +++ b/src/vault/gear/work-force.cpp @@ -37,6 +37,7 @@ #include "vault/gear/work-force.hpp" //#include "lib/symbol.hpp" //#include "include/logging.h" +#include "lib/util.hpp" //#include @@ -49,12 +50,15 @@ namespace gear { namespace { // internal details + size_t MINIMAL_CONCURRENCY = 2; + } // internal details // NA::~NA() { } + const size_t WorkForce::FULL_SIZE = util::max (std::thread::hardware_concurrency(), MINIMAL_CONCURRENCY); diff --git a/src/vault/gear/work-force.hpp b/src/vault/gear/work-force.hpp index 523c759cc..a594e559a 100644 --- a/src/vault/gear/work-force.hpp +++ b/src/vault/gear/work-force.hpp @@ -37,11 +37,17 @@ #include "vault/common.hpp" +#include "vault/gear/activity.hpp" #include "lib/nocopy.hpp" //#include "lib/symbol.hpp" -//#include "lib/util.hpp" +#include "lib/util.hpp" //#include +#include +#include +#include +#include +#include namespace vault{ @@ -49,6 +55,8 @@ namespace gear { // using util::isnil; // using std::string; + using std::move; + using std::atomic; /** @@ -60,27 +68,69 @@ namespace gear { class WorkForce : util::NonCopyable { - short nothing_; + using WorkFun = std::function; + using Pool = std::vector; + + WorkFun workFun_; + Pool workers_; + + atomic halt_{false}; public: - template + static const size_t FULL_SIZE; + explicit - WorkForce (FUN&& fun) - : nothing_{42} - { } + WorkForce (WorkFun&& fun) + : workFun_{move (fun)} + , workers_{} + { + workers_.reserve (1.5*FULL_SIZE); + } + + ~WorkForce() + { + try { + deactivate(); + } + ERROR_LOG_AND_IGNORE (threadpool, "defunct worker thread") + } void activate (double degree =1.0) { - UNIMPLEMENTED ("scale up"); + halt_ = false; + size_t scale = util::max (size_t(degree*FULL_SIZE), 1u); + for (uint i = workers_.size(); i < scale; ++i) + workers_.emplace_back ([this]{ pullWork(); }); } void deactivate() { - UNIMPLEMENTED ("scale down to halt"); + halt_ = true; + for (auto& w : workers_) + if (w.joinable()) + w.join(); + workers_.clear(); } + + private: + void + pullWork() + { + try { + while (true) + { + activity::Proc res = workFun_(); + if (halt_ or res != activity::PASS) + break; + } + } + ERROR_LOG_AND_IGNORE (threadpool, "defunct worker thread") + } + + }; diff --git a/tests/vault/gear/work-force-test.cpp b/tests/vault/gear/work-force-test.cpp index eb14df02a..78178b57f 100644 --- a/tests/vault/gear/work-force-test.cpp +++ b/tests/vault/gear/work-force-test.cpp @@ -28,7 +28,7 @@ #include "lib/test/run.hpp" #include "vault/gear/work-force.hpp" //#include "lib/time/timevalue.hpp" -//#include "lib/format-cout.hpp" +#include "lib/format-cout.hpp" ///////////////////////////////WIP //#include "lib/util.hpp" //#include @@ -75,9 +75,9 @@ namespace test { void simpleUsage() { - uint check{0}; + atomic check{0}; - WorkForce wof{[&]{ ++check; return true; }}; + WorkForce wof{[&]{ ++check; return activity::PASS; }}; CHECK (0 == check); diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 9ddc34d8b..738a6a7ef 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -7167,14 +7167,14 @@ Later on we expect a distinct __query subsystem__ to emerge, presumably embeddin &rarr; QuantiserImpl -
+
//Invoke and control the dependency and time based execution of  [[render jobs|RenderJob]]//
 The Scheduler acts as the central hub in the implementation of the RenderEngine and coordinates the //processing resources// of the application. Regarding architecture, the Scheduler is located in the Vault-Layer and //running// the Scheduler is equivalent to activating the »Vault Subsystem«. An EngineFaçade acts as entrance point, providing high-level render services to other parts of the application: [[render jobs|RenderJob]] can be activated under various timing and dependency constraints. Internally, the implementation is segregated into two layers
 ;Layer-2: Coordination
 :maintains a network of interconnected [[activities|RenderActivity]], tracks dependencies and observes timing constraints
+:coordinates a [[pool of active Workers|SchedulerWorker]] to dispatch the next activities
 ;Layer-1: Invocation
 :operates a low-level priority scheduling mechanism for time-bound execution of [[activities|RenderActivity]]
-:coordinates a ThreadPool and dispatches the execution of individual jobs into appropriate worker threads.
 
 !Event based vs. time based operational control
 Time bound delivery of media data is an important aspect of editing and playback -- yet other concerns are of similar importance: the ability to make optimum use of scarce resources and to complete extended processing in reasonable time, while retaining some overall responsiveness of the system. And, especially for the //final render,// it is tantamount to produce 100% correct results without any glitches -- a goal that can not be reconciled with the demand for perfect timing. These considerations alone are sufficient to indicate, that strict adherence to a pre-established calculation plan is not enough to build a viable render engine. As far as media processing is concerned, the limited I/O bandwidth is the most precious resource -- reading and writing data from persistent storage requires a lot of time, with generally unpredictable timings, necessitating asynchronous processing.
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 9fcc8b18a..dee2fea23 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -79627,6 +79627,15 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + +