Scheduler: look for ways to propagate a capacity-hint
...whenever a new CalcStream is seeded, it would be prudent not only to step up the WorkForce (which is already implemented), but also to provide a hint to the BlockFlow allocator regarding the expected calculation density. Such a hint would allow to set a more ample »epoch« spacing, thereby avoiding to drive the allocator into overload first. The allocator will cope anyway and re-balance in a matter of about 2 seconds, but avoiding this kind of control oscillations altogether will lead to better performance at calculation start.
This commit is contained in:
parent
ecf1a5a301
commit
a2a960f544
5 changed files with 149 additions and 56 deletions
|
|
@ -49,6 +49,7 @@
|
|||
#include "lib/rational.hpp"
|
||||
#include "lib/util-quant.hpp"
|
||||
#include "lib/format-string.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "lib/tmpbuf.h"
|
||||
|
|
@ -62,12 +63,15 @@ extern "C" {
|
|||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
using std::string;
|
||||
using util::limited;
|
||||
using util::floordiv;
|
||||
using lib::time::FSecs;
|
||||
using lib::time::FrameRate;
|
||||
using boost::rational_cast;
|
||||
using boost::lexical_cast;
|
||||
|
||||
#undef MAX
|
||||
#undef MIN
|
||||
|
||||
|
||||
namespace error = lumiera::error;
|
||||
|
|
@ -263,6 +267,47 @@ namespace time {
|
|||
|
||||
return Duration (1, *this);
|
||||
}
|
||||
|
||||
|
||||
/** a rather arbitrary safety limit imposed on internal numbers used to represent a frame rate.
|
||||
* @remark rational numbers bear the danger to overflow for quite ordinary computations;
|
||||
* we stay away from the absolute maximum by an additional safety margin of 1/1000.
|
||||
*/
|
||||
const uint RATE_LIMIT{std::numeric_limits<uint>::max() / 1000};
|
||||
|
||||
/**
|
||||
* @internal helper to work around the limitations of `uint`.
|
||||
* @return a fractional number approximating the floating-point spec.
|
||||
* @todo imposing a quite coarse limitation. If this turns out
|
||||
* to be a problem: we can do better, use lib::reQuant (rational.hpp)
|
||||
*/
|
||||
boost::rational<uint>
|
||||
__framerate_approximation (double fps)
|
||||
{
|
||||
double quantised{fabs(fps) * RATE_LIMIT};
|
||||
|
||||
uint num = uint(limited (1u, quantised + 0.5, 1000u*RATE_LIMIT));
|
||||
uint den = RATE_LIMIT;
|
||||
return {num, den};
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal helper calculate the _count per time span_ approximately,
|
||||
* to the precision possible to represent as fractional `uint`.
|
||||
*/
|
||||
boost::rational<uint>
|
||||
__framerate_approximation (size_t cnt, Duration timeReference)
|
||||
{
|
||||
boost::rational<uint64_t> quot{cnt, _raw(timeReference)};
|
||||
if (quot.denominator() < RATE_LIMIT
|
||||
and quot.numerator() < RATE_LIMIT/1000)
|
||||
return {uint(quot.numerator()) * uint(Time::SCALE)
|
||||
,uint(quot.denominator())
|
||||
};
|
||||
// precise computation can not be handled numerically...
|
||||
return __framerate_approximation (rational_cast<double>(quot) * Time::SCALE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -667,7 +667,11 @@ namespace time {
|
|||
public:
|
||||
FrameRate (uint fps) ;
|
||||
FrameRate (uint num, uint denom);
|
||||
FrameRate (boost::rational<uint> const& fractionalRate);
|
||||
FrameRate (size_t count, Duration timeReference);
|
||||
explicit
|
||||
FrameRate (boost::rational<uint> fractionalRate);
|
||||
|
||||
static FrameRate approx(double fps);
|
||||
|
||||
// standard copy acceptable;
|
||||
|
||||
|
|
@ -806,10 +810,25 @@ namespace time {
|
|||
{ }
|
||||
|
||||
inline
|
||||
FrameRate::FrameRate (boost::rational<uint> const& fractionalRate)
|
||||
FrameRate::FrameRate (boost::rational<uint> fractionalRate)
|
||||
: boost::rational<uint> (__ensure_nonzero(fractionalRate))
|
||||
{ }
|
||||
|
||||
boost::rational<uint> __framerate_approximation (size_t, Duration);
|
||||
boost::rational<uint> __framerate_approximation (double);
|
||||
|
||||
inline
|
||||
FrameRate::FrameRate (size_t count, Duration timeReference)
|
||||
: FrameRate{__framerate_approximation (count, timeReference)}
|
||||
{ }
|
||||
|
||||
inline FrameRate
|
||||
FrameRate::approx (double fps)
|
||||
{
|
||||
return FrameRate{__framerate_approximation (fps)};
|
||||
}
|
||||
|
||||
|
||||
inline double
|
||||
FrameRate::asDouble() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ namespace gear {
|
|||
using lib::time::FSecs;
|
||||
using lib::time::TimeVar;
|
||||
using lib::time::Duration;
|
||||
using lib::time::FrameRate;
|
||||
|
||||
|
||||
namespace blockFlow {///< Parametrisation of Scheduler memory management scheme
|
||||
|
|
@ -327,6 +328,7 @@ namespace gear {
|
|||
* Scheduling entails to provide a chain of Activity definitions,
|
||||
* which will then »flow« through the priority queue until invocation.
|
||||
*
|
||||
* @see ActivityLang
|
||||
* @see SchedulerCommutator
|
||||
* @see BlockFlow_test
|
||||
*/
|
||||
|
|
@ -385,7 +387,16 @@ namespace gear {
|
|||
double stretched = _raw(epochStep_) * factor;
|
||||
gavl_time_t microTicks(floor (stretched));
|
||||
epochStep_ = TimeValue{microTicks};
|
||||
|
||||
}
|
||||
|
||||
/** provide a hint to the self-regulating allocation scheme */
|
||||
void
|
||||
announceAdditionalFlow (FrameRate additionalFps)
|
||||
{
|
||||
FrameRate currFps{config().framesPerEpoch(), epochStep_};
|
||||
/////////////////////////////////////////////////////////////////////TODO need arithmetics on FrameRate
|
||||
/////////////////////////////////////////////////////////////////////TODO -> then just add the new and calculate new stepping
|
||||
/////////////////////////////////////////////////////////////////////TODO !! watch out for the minimum limit !!
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -229,6 +229,20 @@ namespace test{
|
|||
|
||||
CHECK (isnil (Duration (0, FrameRate::PAL)));
|
||||
CHECK (isnil (Duration (0, FrameRate(123))));
|
||||
|
||||
CHECK (FrameRate::approx(2000) == "1000FPS"_expect); // limited
|
||||
CHECK (FrameRate::approx(1e-5) == "43/4294967FPS"_expect);
|
||||
CHECK (FrameRate::approx(1e-6) == "4/4294967FPS"_expect);
|
||||
CHECK (FrameRate::approx(1e-7) == "1/4294967FPS"_expect); // limited
|
||||
CHECK (FrameRate::approx(1e-8) == "1/4294967FPS"_expect); // limited
|
||||
|
||||
CHECK (FrameRate( 20'000, Duration{Time{0,10}}) == "2000FPS"_expect);
|
||||
CHECK (FrameRate( 20'000, Duration{Time::MAX }) == "1/4294967FPS"_expect);// limited
|
||||
|
||||
CHECK (FrameRate(size_t(2e10), Duration{Time::MAX }) == "279397/4294967FPS"_expect);
|
||||
CHECK (FrameRate(size_t(2e14), Duration{Time::MAX }) == "2793967531/4294967FPS"_expect);
|
||||
CHECK (FrameRate(size_t(2e15), Duration{Time::MAX }) == "1000FPS"_expect); // limited
|
||||
CHECK (FrameRate(size_t(2e16), Duration{Time::MAX }) == "1000FPS"_expect); // limited
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -78951,9 +78951,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1699563656019" ID="ID_1361396246" MODIFIED="1699566672294" TEXT="Job-Planung muß aus Konsistenzgründen in einem Job laufen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...damit sie das Grooming-Token hat und damit Zugriff auf die Scheduler-Ressourcen. Außerdem ist damit ein konsitenter Rahmen sichergestellt: geplante Startzeiten sollten frühestend 20ms danach beginnen
|
||||
|
|
@ -80253,9 +80251,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
<node CREATED="1699563384878" ID="ID_28734392" LINK="#ID_394986223" MODIFIED="1699563462111" VSHIFT="6">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p style="text-align: center">
|
||||
beide Probleme lassen sich nicht lösen —
|
||||
|
|
@ -80441,9 +80437,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</body>
|
||||
</html></richcontent>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...da nun wirklich jeder Dispatch am Grooming-Token <i>„vorbei muß“  — </i>theoretisch wäre es sogar darstellbar, die eigentliche Job-Planung außerhalb und ohne Grooming-Token zu machen; die neuen Jobs gehen dann eben in die Instruction-Queue. Auch eine Notification (welche das Gate dekrementieren könnte) geht durch das λ-post, welches direkt durch Layer2.postDispatch geht, und damit entweder versucht, das Grooming-Token zu erlangen, oder eben in die Instruct-Queue einstellt
|
||||
|
|
@ -80483,9 +80477,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
<node CREATED="1699563536669" ID="ID_1878072938" MODIFIED="1699563756594" TEXT="dieser ist selbst ein (Meta)Job">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
und hat damit garantiert das Grooming-Token
|
||||
|
|
@ -82110,9 +82102,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1698937110289" ID="ID_1837336933" MODIFIED="1698937115982" TEXT="reduziert Header-Includes"/>
|
||||
<node CREATED="1698937116771" ID="ID_231850405" MODIFIED="1699573981078" TEXT="verbessert Verständlichkeit">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
<i>das</i> ist das ausschlaggebende Argument: Jemand, der erst mal nur den Scheduler-Header liest, wäre sonst sofort erschlagen von technischen Details, und würde den Wald vor lauter Bäumen nicht mehr sehen. Zumal Scheduler selber nochmal zerlegt wird in einen Header-Anteil und eine eigene translation-unit (scheduler.cpp)
|
||||
|
|
@ -82151,29 +82141,23 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1699573633992" ID="ID_1916986829" MODIFIED="1699573853826" TEXT="das läßt sich in der Strenge nicht ohne Weiteres realisieren">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...und zwar wegen der Builder-Notation; wegen der Möglichkeit, später noch Dependencies aufzuschalten, muß der activity::Term im Builder eingebettet sein, also bei der Definition der Builder-Klasse bekannt. Einziger Ausweg wäre, in die äußere Builder-Klasse einen opaque buffer zu legen, und die Implementierung in scheduler.cpp nachzutragen. Diese Lösung halte ich für unnötig komplex (wiewohl sie keinen relevanten Performance-overhead erzeugt)
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1699573648854" ID="ID_716393193" MODIFIED="1699573724694" TEXT="ist aber auch nicht wirklich notwendig">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...denn die betreffenden Header sind nicht wirklich <i>schwergewichtig</i>  —<b> </b>im Besonderen da die typischen Clients des SchedulerService selber Implementierungs-Code sind
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1698936663551" ID="ID_1985217972" MODIFIED="1698937090405" TEXT="normalen Job über abstrahiertes Builder-API einstellen">
|
||||
|
|
@ -82191,29 +82175,23 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1699574037212" ID="ID_621021823" MODIFIED="1699574131476" TEXT="postChain wäre ein Kandidat, ist aber zweifelhaft">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
denn dabei handelt es sich nun wirklich um eine zentrale Implementierungs-Funktion, die auch aus der Implementierung heraus aufgerufen wird. Selbst wenn der Optimizer wahrscheinlich die <i>monomorphic optimization </i>beherrscht, macht man sowas einfach nicht.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1699574329467" ID="ID_1038685203" MODIFIED="1699574971826" TEXT="zumal die anderen high-level-Funktionen auch virtual sein müssen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...so ziemlich jede von denen greift in der Implementierung auf die Komponenten im Scheduler zu.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -82429,37 +82407,35 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1699568058043" ID="ID_1348913314" MODIFIED="1699568067002" TEXT="daher ist hier kein expliziter Builder notwendig"/>
|
||||
<node CREATED="1699568068327" ID="ID_1707263469" MODIFIED="1699568075312" TEXT="kann direkt auf die unterliegenden APIs durchgehen"/>
|
||||
<node CREATED="1699568097669" ID="ID_669864822" MODIFIED="1699568115788" TEXT="einige Parameter werden fest vorgegeben">
|
||||
<node COLOR="#338800" CREATED="1699568068327" ID="ID_1707263469" MODIFIED="1699588825322" TEXT="kann direkt auf die unterliegenden APIs durchgehen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1699568097669" ID="ID_669864822" MODIFIED="1699588821465" TEXT="einige Parameter werden fest vorgegeben">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1699568121776" ID="ID_33668425" MODIFIED="1699568155219" TEXT="die Deadline: analog zum »Tick«">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
also sehr großzügig
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1699568156544" ID="ID_635029922" MODIFIED="1699568164782" TEXT="es ist immer ein Meta-Job"/>
|
||||
<node CREATED="1699568165537" ID="ID_788135445" MODIFIED="1699568185049">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
er ist stets <i>compulsory</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1699568192950" ID="ID_46078853" MODIFIED="1699568201950" TEXT="weitere Parameter sind nur optional">
|
||||
<node COLOR="#338800" CREATED="1699568192950" ID="ID_46078853" MODIFIED="1699588823469" TEXT="weitere Parameter sind nur optional">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1699568225289" ID="ID_1953407534" MODIFIED="1699568238756" TEXT="brauche daher zwei Varianten"/>
|
||||
<node CREATED="1699568239935" ID="ID_1918919265" MODIFIED="1699568264056" TEXT="Start-Offset ist per default »now«"/>
|
||||
<node CREATED="1699568273591" ID="ID_138761713" MODIFIED="1699568281494" TEXT="aber die ManifestationID wird man meist angeben">
|
||||
|
|
@ -82467,6 +82443,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1699568305542" ID="ID_145276801" MODIFIED="1699568314497" TEXT="sie wird ja um eine erhebliche Zeit in die Zukunft geschoben"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1699588828420" ID="ID_291850353" MODIFIED="1699588844769" TEXT="zusätzlich die ManifestationID freischalten">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1699588845747" ID="ID_75294881" MODIFIED="1699589219892" TEXT="scheduler CalcStream: Kapazitäts-hint an den BlockFlow-Allocator weitergeben">
|
||||
<arrowlink COLOR="#df1a3b" DESTINATION="ID_737137964" ENDARROW="Default" ENDINCLINATION="-1137;63;" ID="Arrow_ID_1003728898" STARTARROW="None" STARTINCLINATION="-998;36;"/>
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1697757058002" ID="ID_603254465" MODIFIED="1698867045291" TEXT="terminateProcessing()">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
|
|
@ -94226,6 +94209,30 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1699588894575" ID="ID_737137964" MODIFIED="1699589215022" TEXT="BlockFlow: Hint zur Platz-Regulierung unterstützen">
|
||||
<linktarget COLOR="#df1a3b" DESTINATION="ID_737137964" ENDARROW="Default" ENDINCLINATION="-1137;63;" ID="Arrow_ID_1003728898" SOURCE="ID_75294881" STARTARROW="None" STARTINCLINATION="-998;36;"/>
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1699588945917" ID="ID_83511183" MODIFIED="1699588974776">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Idee: Angabe in <i>»zusätzlichen Frames-per-second«</i>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1699588976977" ID="ID_290474610" MODIFIED="1699588993439" TEXT="dazu den FrameRate-Typ ausbauen">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1699588995897" ID="ID_14216185" MODIFIED="1699589010757" TEXT="Errechnen aus count + Referenz-Zeit">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1699589011492" ID="ID_1793529885" MODIFIED="1699589032034" TEXT="Problem: Überlauf-Gefahr der fractional-Arrithmetik">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1689560454292" FOLDED="true" ID="ID_1170043916" MODIFIED="1689993985097" TEXT="Laufzeitverhalten beobachten">
|
||||
<arrowlink COLOR="#3ba098" DESTINATION="ID_906364025" ENDARROW="Default" ENDINCLINATION="-1525;104;" ID="Arrow_ID_849510703" STARTARROW="None" STARTINCLINATION="455;-1256;"/>
|
||||
|
|
@ -95627,16 +95634,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1699571882718" ID="ID_306783739" MODIFIED="1699571918305" TEXT="außerdem führt die Aktivierung via λ-post wieder in den Dispatch"/>
|
||||
<node CREATED="1699571920304" ID="ID_645005092" MODIFIED="1699571938972">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
allerdings haben wir jetzt praktisch immer einen<i> direkten Eingang</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1699571939723" ID="ID_308661587" MODIFIED="1699571957595" TEXT="und dabei werden (start, deadline) jeweils nochmal explizit gegeben"/>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue