Block-Flow: final adjustments from performance test (closes: #1311)

Further extensive testing with parameter variations,
using the test setup in `BlockFlow_test::storageFlow()`

- Tweaks to improve convergence under extreme overload;
  sudden load peaks are now accomodated typically < 5 sec

- Make the test definition parametric, to simplify variations

- Extract the generic microbenchmark helper function

- Documentation
This commit is contained in:
Fischlurch 2023-07-22 01:54:25 +02:00
parent 049ca833a0
commit 28b3900284
5 changed files with 469 additions and 162 deletions

View file

@ -22,18 +22,19 @@
/** @file microbenchmark.hpp
** A function to perform multithreaded timing measurement on a given functor.
** Functions to perform (multithreaded) timing measurement on a given functor.
** This helper simplifies micro benchmarks of isolated implementation details.
** The test subject, given as function object or lambda, is copied into N threads
** and invoked numerous times within a tight loop. After waiting on termination of
** the test threads, results are summed up and then averaged into milliseconds
** per single invocation. The actual timing measurement relies on `chrono::duration`,
** which means to count micro ticks of the OS.
** The test subject, given as function object or lambda, is invoked numerous times
** within a tight loop. In the [multithreaded variant](\ref threadBenchmark()),
** the lambda is copied into N threads and performed in each thread in parallel;
** after waiting on termination of the test threads, results are summed up and then
** averaged into milliseconds per single invocation. The actual timing measurement
** relies on `chrono::duration`, which means to count micro ticks of the OS.
** @warning care has to bee taken when optimisation is involved!
** Optimisation usually has quite some impact on the results, but since
** this function is inline, the lambda can typically be inlined and the
** loop possibly be optimised away entirely. A simple workaround is to
** define a _volatile_ variable in the call context, close the lambda
** loop possibly be optimised away altogether. A simple workaround is
** to define a _volatile_ variable in the call context, close the lambda
** by reference, and perform a comparison with that volatile variable
** in each invocation. The compiler is required actually to access the
** value of the volatile each time.
@ -45,7 +46,7 @@
** - multithreaded (unlocked) incrementing of the _global_ volatile
** creates massive overhead and increases the running time by factor 100.
** This nicely confirms that the x86_64 platform has strong cache coherence.
**
**
*/
@ -53,6 +54,7 @@
#define LIB_TEST_MICROBENCHMARK_H
#include "lib/meta/function.hpp"
#include "vault/thread-wrapper.hpp"
#include <chrono>
@ -64,11 +66,73 @@ namespace lib {
namespace test{
namespace {
constexpr size_t DEFAULT_RUNS = 10000000;
constexpr size_t DEFAULT_RUNS = 10'000'000;
constexpr double SCALE = 1e6; // Results are in µ sec
}
/**
* Helper to invoke a functor or λ to observe its running time.
* @param invokeTestLoop the test (complete including loop) invoked once
* @param repeatCnt number of repetitions to divide the timing measurement
* @return averaged time for one repetition, in nanoseconds
*/
template<class FUN>
inline double
benchmarkTime (FUN const& invokeTestLoop, const size_t repeatCnt = DEFAULT_RUNS)
{
using std::chrono::system_clock;
using Dur = std::chrono::duration<double>;
const double SCALE = 1e9; // Results are in ns
auto start = system_clock::now();
invokeTestLoop();
Dur duration = system_clock::now () - start;
return duration.count()/(repeatCnt) * SCALE;
};
/**
* Benchmark building block to invoke a functor or λ in a tight loop,
* passing the current loop index and capturing a result checksum value.
* @return sum of all individual invocation results as checksum
*/
template<class FUN>
inline size_t
benchmarkLoop (FUN const& testSubject, const size_t repeatCnt = DEFAULT_RUNS)
{
// the test subject gets the current loop-index and returns a checksum value
ASSERT_VALID_SIGNATURE (decltype(testSubject), size_t&(size_t));
size_t checksum{0};
for (size_t i=0; i<repeatCnt; ++i)
checksum += testSubject(i);
return checksum;
}
/** perform a simple looped microbenchmark.
* @param testSubject the operation to test as functor or λ
* @return a pair `(nanoseconds, checksum)`
* @warning this setup is only usable under strong optimisation;
* moreover, the scaffolding without actual operation should also
* be tested for comparison, to get a feeling for the setup overhead.
* For very small test subjects (single operations) it is recommended
* to use a direct loop without any lambdas and building blocks.
*/
template<class FUN>
inline auto
microBenchmark (FUN const& testSubject, const size_t repeatCnt = DEFAULT_RUNS)
{
size_t checksum{0};
auto invokeTestLoop = [&]{ checksum = benchmarkLoop (testSubject, repeatCnt); };
double nanos = benchmarkTime (invokeTestLoop, repeatCnt);
return std::make_tuple (nanos, checksum);
}
/** perform a multithreaded microbenchmark.
* This function fires up a number of threads
* and invokes the given test subject repeatedly.
@ -85,7 +149,7 @@ namespace test{
*/
template<size_t nThreads, class FUN>
inline double
microbenchmark(FUN const& subject, const size_t nRepeat = DEFAULT_RUNS)
threadBenchmark(FUN const& subject, const size_t nRepeat = DEFAULT_RUNS)
{
using vault::ThreadJoinable;
using std::chrono::system_clock;

View file

@ -76,9 +76,7 @@
** @see BlockFlow_test
** @see SchedulerUsage_test
** @see extent-family.hpp underlying allocation scheme
**
** @todo WIP-WIP-WIP 6/2023 »Playback Vertical Slice«
**
**
*/
@ -124,12 +122,12 @@ namespace gear {
/* === algorithm tuning settings === */
const double TARGET_FILL = 0.90; ///< aim at using this fraction of Epoch space on average (slightly below 100%)
const double BOOST_FACTOR = 0.85; ///< adjust capacity by this factor on Epoch overflow/underflow events
const double DAMP_THRESHOLD = 0.06; ///< do not account for (almost) empty Epochs to avoid overshooting regulation
const double DAMP_THRESHOLD = 0.08; ///< do not account for (almost) empty Epochs to avoid overshooting regulation
/* === contextual assumptions === */
const size_t ACTIVITIES_PER_FRAME = 10; ///< how many Activity records are typically used to implement a single frame
const size_t REFERENCE_FPS = 25; ///< frame rate to use as reference point to relate DUTY_CYCLE and default counts
const size_t OVERLOAD_LIMIT = 200; ///< load factor over normal use where to assume saturation and limit throughput
const size_t OVERLOAD_LIMIT = 60; ///< load factor over normal use where to assume saturation and limit throughput
};
/**
@ -371,8 +369,6 @@ namespace gear {
public:
BlockFlow()
// : alloc_{INITIAL_ALLOC}//Strategy::initialEpochCnt()}
// , epochStep_{INITIAL_EPOCH_STEP}//Strategy::initialEpochStep()}
: alloc_{Strategy::initialEpochCnt()}
, epochStep_{Strategy::initialEpochStep()}
{ }
@ -435,17 +431,10 @@ namespace gear {
void*
claimSlot() ///< EX_SANE
{
bool first{true};
while (not (epoch_ and
epoch_->gate().hasFreeSlot()))
// Epoch overflow
// use following Epoch; possibly allocate
{
if (first)
{// each shifted allocation accounted once as overflow
flow_->markEpochOverflow();
first = false;
}
// Epoch overflow...
{// shift to following Epoch; possibly allocate
if (not epoch_)
{
auto lastDeadline = flow_->lastEpoch().deadline();
@ -455,6 +444,7 @@ namespace gear {
}
else
{
flow_->markEpochOverflow();
++epoch_;
}
}
@ -565,7 +555,7 @@ namespace gear {
/**
* On clean-up of past Epochs, the actual fill factor is checked to guess an
* Epoch duration for optimal usage of epoch storage. Assuming that requested
* Epoch duration to make optimal use of epoch storage. Assuming that requested
* Activity deadlines are evenly spaced, for a simple heuristic we can just divide
* actual Epoch duration by the fill factor (longer Epoch => less capacity).
* To avoid control oscillations however, it seems prudent to use damping by

View file

@ -28,10 +28,10 @@
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "vault/gear/block-flow.hpp"
#include "lib/test/microbenchmark.hpp"
#include "lib/time/timevalue.hpp"
//#include "lib/format-cout.hpp"
#include "lib/test/diagnostic-output.hpp" ////////////////////////////////TODO
#include "lib/meta/function.hpp"
#include "lib/format-cout.hpp"
#include "lib/util.hpp"
#include <chrono>
@ -66,6 +66,7 @@ namespace test {
const size_t AVERAGE_EPOCHS = Strategy{}.averageEpochs();
const double BOOST_OVERFLOW = Strategy{}.boostFactorOverflow();
const double TARGET_FILL = Strategy{}.config().TARGET_FILL;
const double ACTIVITIES_P_FR = Strategy{}.config().ACTIVITIES_PER_FRAME;
}
@ -221,7 +222,6 @@ namespace test {
* - exhaust last Epoch, causing setup of new Epoch, with reduced spacing
* - use this reduced spacing also for subsequently created Epochs
* - clean up obsoleted Epochs, based on given deadline
* @todo WIP 7/23 define implement
*/
void
placeActivity()
@ -288,32 +288,31 @@ namespace test {
CHECK (not allocHandle.hasFreeSlot());
auto& a6 = bFlow.until(Time{850,10}).create();
// Note: encountered four overflow-Events, leading to decreased Epoch spacing for new Epochs
CHECK (watch(bFlow).find(a6) == "11s193ms"_expect);
CHECK (watch(bFlow).allEpochs() == "10s200ms|10s400ms|10s600ms|10s800ms|11s|11s193ms"_expect);
CHECK (watch(bFlow).find(a6) == "11s192ms"_expect);
CHECK (watch(bFlow).allEpochs() == "10s200ms|10s400ms|10s600ms|10s800ms|11s|11s192ms"_expect);
auto& a7 = bFlow.until(Time{500,11}).create();
// this allocation does not count as overflow, but has to expand the Epoch grid, now using the reduced Epoch spacing
CHECK (watch(bFlow).allEpochs() == "10s200ms|10s400ms|10s600ms|10s800ms|11s|11s193ms|11s387ms|11s580ms"_expect);
CHECK (watch(bFlow).find(a7) == "11s580ms"_expect);
CHECK (watch(bFlow).allEpochs() == "10s200ms|10s400ms|10s600ms|10s800ms|11s|11s192ms|11s384ms|11s576ms"_expect);
CHECK (watch(bFlow).find(a7) == "11s576ms"_expect);
// on clean-up, actual fill ratio is used to adjust to optimise Epoch length for better space usage
CHECK (bFlow.getEpochStep() == "≺193ms≻"_expect);
CHECK (bFlow.getEpochStep() == "≺192ms≻"_expect);
bFlow.discardBefore (Time{999,10});
CHECK (bFlow.getEpochStep() == "≺234ms≻"_expect);
CHECK (watch(bFlow).allEpochs() == "11s|11s193ms|11s387ms|11s580ms"_expect);
CHECK (bFlow.getEpochStep() == "≺218ms≻"_expect);
CHECK (watch(bFlow).allEpochs() == "11s|11s192ms|11s384ms|11s576ms"_expect);
// placed into the oldest Epoch still alive
auto& a8 = bFlow.until(Time{500,10}).create();
CHECK (watch(bFlow).find(a8) == "11s193ms"_expect);
CHECK (watch(bFlow).find(a8) == "11s192ms"_expect);
}
/** @test load based regulation of Epoch spacing
* - on overflow, capacity is boosted by a fixed factor
* - on clean-up, a moving average of (in hindsight) optimal length is
* computed and used as the new Epoch spacing
* @todo WIP 7/23 define 🔁implement
* - on clean-up, a moving average of (in hindsight) optimal length
* is computed and used as the new Epoch spacing
*/
void
adjustEpochs()
@ -322,11 +321,7 @@ namespace test {
CHECK (bFlow.getEpochStep() == INITIAL_EPOCH_STEP);
// whenever an Epoch overflow happens, capacity is boosted by reducing the Epoch duration
SHOW_EXPR(bFlow.getEpochStep())
bFlow.markEpochOverflow();
SHOW_EXPR(bFlow.getEpochStep())
SHOW_EXPR(INITIAL_EPOCH_STEP)
SHOW_EXPR(INITIAL_EPOCH_STEP*BOOST_OVERFLOW)
CHECK (bFlow.getEpochStep() == INITIAL_EPOCH_STEP * BOOST_OVERFLOW);
bFlow.markEpochOverflow();
CHECK (bFlow.getEpochStep() == INITIAL_EPOCH_STEP * BOOST_OVERFLOW*BOOST_OVERFLOW);
@ -351,41 +346,48 @@ SHOW_EXPR(INITIAL_EPOCH_STEP*BOOST_OVERFLOW)
};
TimeVar step = bFlow.getEpochStep();
SHOW_EXPR(bFlow.getEpochStep())
bFlow.markEpochUnderflow (dur1, fac1);
SHOW_EXPR(bFlow.getEpochStep())
SHOW_EXPR(fac1/TARGET_FILL)
SHOW_EXPR(goal1)
SHOW_EXPR(movingAverage(step, goal1))
CHECK (bFlow.getEpochStep() == movingAverage(step, goal1));
step = bFlow.getEpochStep();
bFlow.markEpochUnderflow (dur2, fac2);
SHOW_EXPR(_raw(bFlow.getEpochStep()))
SHOW_EXPR(_raw(movingAverage(step, goal2)))
CHECK (bFlow.getEpochStep() == movingAverage(step, goal2));
}
/** @test investigate progression of epochs under realistic load
* - expose the allocator to a load of 200fps for simulated 60sec
* - assuming 10 Activities per frame, this means a throughput of 120000 Activities
* - expose the allocator to a load of 200fps for simulated 3 Minutes
* - assuming 10 Activities per frame, this means a throughput of 360000 Activities
* - run this load exposure under saturation for performance measurement
* - use a planning to deadline delay of 500ms, but with ±200ms random spread
* - after 250ms (500 steps), »invoke« by accessing and adding the random checksum
* - run a comparison of all-pre-allocated heap allocated Refcount BlockFlow
* @todo WIP 7/23 🔁define 🔁implement
* @remarks
* This test setup can be used to investigate different load scenarios.
* In the standard as defined, the BlockFlow allocator is overloaded initially;
* within 5 seconds, the algorithm should have regulated the Epoch stepping down
* to accommodate the load peak. As immediate response, excess allocation requests
* are shifted into later Epochs. To cope with a persisting higher load, the spacing
* is reduced swiftly, by growing the internal pool with additional heap allocated Extents.
* In the following balancing phase, the mechanism aims at bringing back the Epoch duration
* into a narrow corridor, to keep the usage quotient as close as possible to 90%
*/
void
storageFlow()
{
const uint INSTANCES = 120000; // Activities to send through the test subject
const uint MAX_TIME = 121000; // Test steps to perform
const gavl_time_t STP = 500; // with 2 steps per ms
Offset BASE_DEADLINE{FSecs{1,2}}; // base pre-roll before deadline
Offset SPREAD_DEAD{FSecs{2,100}}; // random spread of deadline around base
const uint INVOKE_LAG = 500; // „invoke“ the Activity after 500 steps (≙ simulated 250ms)
const uint CLEAN_UP = 200; // perform clean-up every 200 steps
const size_t FPS = 200;
const size_t TICK_P_S = FPS * ACTIVITIES_P_FR; // Simulated throughput 200 frames per second
const gavl_time_t STP = Time::SCALE / TICK_P_S; // Simulation stepping (here 2 steps per ms)
const gavl_time_t RUN = _raw(Time{0,0,3}); // nominal length of the simulation time axis
Offset BASE_DEADLINE{FSecs{1,2}}; // base pre-roll before deadline
Offset SPREAD_DEAD{FSecs{2,100}}; // random spread of deadline around base
const uint INVOKE_LAG = _raw(Time{250,0}) /STP; // „invoke“ the Activity after simulated 250ms (≙ 500 steps)
const uint CLEAN_UP = _raw(Time{100,0}) /STP; // perform clean-up every 200 steps
const uint INSTANCES = RUN /STP; // 120000 Activity records to send through the test subject
const uint MAX_TIME = INSTANCES
+INVOKE_LAG+2*CLEAN_UP; // overall count of Test steps to perform
using TestData = vector<pair<TimeVar, size_t>>;
using Subjects = vector<reference_wrapper<Activity>>;
@ -428,18 +430,12 @@ SHOW_EXPR(_raw(movingAverage(step, goal2)))
};
auto benchmark = [INSTANCES](auto invokeTest)
{
using std::chrono::system_clock;
using Dur = std::chrono::duration<double>;
const double SCALE = 1e9; // Results are in ns
auto start = system_clock::now();
invokeTest();
Dur duration = system_clock::now () - start;
return duration.count()/(INSTANCES) * SCALE;
{ // does the timing measurement with result in nanoseconds
return lib::test::benchmarkTime(invokeTest, INSTANCES);
};
/* =========== Test-Setup-1: no individual allocations/deallocations ========== */
size_t sum1{0};
vector<Activity> storage{INSTANCES};
@ -466,7 +462,7 @@ SHOW_EXPR(_raw(movingAverage(step, goal2)))
};
auto invoke = [](Activity& feedActivity)
{
size_t check = feedActivity.data_.feed.one;
size_t check = feedActivity.data_.feed.one;
delete &feedActivity;
return check;
};
@ -488,7 +484,7 @@ SHOW_EXPR(_raw(movingAverage(step, goal2)))
};
auto invoke = [&, i=0](Activity& feedActivity) mutable
{
size_t check = feedActivity.data_.feed.one;
size_t check = feedActivity.data_.feed.one;
manager[i].reset();
return check;
};
@ -527,39 +523,51 @@ SHOW_EXPR(_raw(movingAverage(step, goal2)))
// INVOKE Setup-1
auto time_noAlloc = benchmark(noAlloc);
SHOW_EXPR(time_noAlloc)
SHOW_EXPR(sum1);
// INVOKE Setup-2
auto time_heapAlloc = benchmark(heapAlloc);
SHOW_EXPR(time_heapAlloc)
SHOW_EXPR(sum2);
// INVOKE Setup-3
auto time_sharedAlloc = benchmark(sharedAlloc);
SHOW_EXPR(time_sharedAlloc)
SHOW_EXPR(sum3);
cout<<"\n\n■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□"<<endl;
cout<<"\n\n■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■"<<endl;
// INVOKE Setup-4
auto time_blockFlow = benchmark(blockFlowAlloc);
cout<<"\n\n■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□"<<endl;
SHOW_EXPR(time_blockFlow)
SHOW_EXPR(sum4);
cout<<"\n"<<endl;
SHOW_EXPR(watch(blockFlow).cntEpochs())
SHOW_EXPR(watch(blockFlow).poolSize())
SHOW_EXPR(watch(blockFlow).first())
SHOW_EXPR(watch(blockFlow).last())
SHOW_EXPR(_raw(blockFlow.getEpochStep()))
//SHOW_EXPR(watch(blockFlow).allEpochs())
SHOW_EXPR(blockFlow.framesPerEpoch())
SHOW_EXPR(blockFlow.initialEpochCnt())
//SHOW_EXPR(INITIAL_ALLOC)
SHOW_EXPR(blockFlow.initialEpochStep())
//SHOW_EXPR(INITIAL_EPOCH_STEP)
SHOW_EXPR(_raw(blockFlow.timeStep_cutOff()))
SHOW_EXPR(blockFlow.averageEpochs())
Duration expectStep{FSecs{blockFlow.framesPerEpoch(), FPS} * 9/10};
cout<<"\n___Microbenchmark____"
<<"\nnoAlloc : "<<time_noAlloc
<<"\nheapAlloc : "<<time_heapAlloc
<<"\nsharedAlloc : "<<time_sharedAlloc
<<"\nblockFlow : "<<time_blockFlow
<<"\n_____________________\n"
<<"\ninstances.... "<<INSTANCES
<<"\nfps.......... "<<FPS
<<"\nActivities/s. "<<TICK_P_S
<<"\nEpoch(expect) "<<expectStep
<<"\nEpoch (real) "<<blockFlow.getEpochStep()
<<"\ncnt Epochs... "<<watch(blockFlow).cntEpochs()
<<"\nalloc pool... "<<watch(blockFlow).poolSize()
<<endl;
// all Activities have been read in all test cases,
// yielding identical checksum
CHECK (sum1 == sum2);
CHECK (sum1 == sum3);
CHECK (sum1 == sum4);
// Epoch spacing regulation must be converge up to ±10ms
CHECK (expectStep - blockFlow.getEpochStep() < Time(10,0));
// after the initial overload is levelled,
// only a small number of Epochs should be active
CHECK (watch(blockFlow).cntEpochs() < 8);
// Due to Debug / Release builds, we can not check the runtime only a very rough margin.
// With -O3, this amortised allocation time should be way below time_sharedAlloc
CHECK (time_blockFlow < 800);
}
};

View file

@ -6183,7 +6183,7 @@ This is the core service provided by the player subsystem. The purpose is to cre
:any details of this processing remain opaque for the clients; even the player subsystem just accesses the EngineFaçade
</pre>
</div>
<div title="PlaybackVerticalSlice" creator="Ichthyostega" modifier="Ichthyostega" created="202303272236" modified="202307161834" tags="overview impl discuss draft" changecount="33">
<div title="PlaybackVerticalSlice" creator="Ichthyostega" modifier="Ichthyostega" created="202303272236" modified="202307220249" tags="overview impl discuss draft" changecount="34">
<pre>//Integration effort to promote the development of rendering, playback and video display in the GUI//
This IntegrationSlice was started in {{red{2023}}} as [[Ticket #1221|https://issues.lumiera.org/ticket/1221]] to coordinate the completion and integration of various implementation facilities, planned, drafted and built during the last years; this effort marks the return of development focus to the lower layers (after years of focussed UI development) and will implement the asynchronous and time-bound rendering coordinated by the [[Scheduler]] in the [[Vault|Vault-Layer]]
@ -6210,8 +6210,8 @@ __June23__: building upon this prototyping approach, the dispatcher pipeline cou
__July23__: this leads to a shift of work focus towards implementing the [[Scheduler]] itself.
The Scheduler will be structured into two Layers, where the lower layer is implemented as //priority queue// (using the STL). So the most tricky part to solve is the representation of //dependencies// between jobs, with the possible extension to handling IO operations asynchronously. Analysis and planning of the implementation indicate that the [[scheduler memory managment|SchedulerMemory]] can be based on //Extents//, which are interpreted as »Epochs« with a deadline. These considerations imply what steps to take next for building up Scheduler functionality and memory management required for processing a simple job
* 🗘 build a first working draft for the {{{BlockFlow}}} allocation scheme [[#1311|https://issues.lumiera.org/ticket/1311]]
* define and cover the basic [[Activities|RenderActivity]] necessary to implement a plain-simple-Job (without dependencies)
* build a first working draft for the {{{BlockFlow}}} allocation scheme [[#1311|https://issues.lumiera.org/ticket/1311]]
* 🗘 define and cover the basic [[Activities|RenderActivity]] necessary to implement a plain-simple-Job (without dependencies)
* ⌛ pass such an Activity through the two layers of the Scheduler
* ⌛ adapt the [[job planning pipeline|JobPlanningPipeline]] implemented thus far to produce the appropriate {{{Activity}}} records for the scheduler
@ -7100,7 +7100,7 @@ The Scheduler is now considered an implementation-level facility with an interfa
&amp;rarr; [[Workers|SchedulerWorker]]
</pre>
</div>
<div title="SchedulerMemory" creator="Ichthyostega" modifier="Ichthyostega" created="202307031622" modified="202307161840" tags="Rendering operational draft" changecount="21">
<div title="SchedulerMemory" creator="Ichthyostega" modifier="Ichthyostega" created="202307031622" modified="202307220323" tags="Rendering operational draft" changecount="29">
<pre>//The Scheduler uses an »Extent« based memory management scheme known as {{{BlockFlow}}}.//
The organisation of rendering happens in terms of [[Activities|RenderActivity]], which may bound by //dependencies// and limited by //deadlines.// For the operational point of view this implies that a sequence of allocations must be able to „flow through the Scheduler“ -- in fact, only references to these {{{Activity}}}-records are passed, while the actual descriptors reside at fixed memory locations. This is essential to model the dependencies and conditional execution structures efficiently. At some point however, any {{{Activity}}}-record will either be //performed// or //obsoleted// -- and this leads to the idea of managing the allocations in //extents// of memory here termed as »Epochs«
* a new Activity is planted into a suitable //Epoch,// based on its deadline
@ -7122,7 +7122,14 @@ The memory management for the scheduler is arranged into three layers...
* raw memory is allocated in large blocks of {{{Extent}}} size -- {{red{currently as of 7/23}}} claimed from regular heap storage
* a low-level allocation scheme, the {{{ExtentFamily}}} uses a //pool of extents cyclically,// with the ability to claim more extents on-demand
* the high-level {{{BlockFlow}}} allocation manager is aware of scheduler semantics and dresses up those extents as {{{Epoch}}}
For each new RenderActivity, the API usage with the help of the {{{ActivityLang}}} is required to designate a ''deadline'' -- which can be used to associate the corresponding {{{Activity}}}-records with a suitable {{{Epoch}}}. The //temporal spacing// of epochs, as well as the number of active epochs (=extents) must be managed dynamically. {{red{As of 7/23, a scheme to avoid control oscillations}}} need to be devised, see [[#1316|https://issues.lumiera.org/ticket/1316]]. When the reserved allocation for an epoch turns out as insufficient (i.e. the underlying extent has been filled up prior to maturity), further {{{Activity}}} records will be //„borrowed“// from the next epoch, while reducing the epoch spacing for compensation. Each {{{Epoch}}} automatically maintains a specifically rigged »''~EpochGuard''«-{{{Activity}}}, always located in the first »slot« of the epoch storage. This guard models the deadline and additionally allows to block deallocation with a count-down latch, which can be tied to pending IO operations.
For each new RenderActivity, the API usage with the help of the {{{ActivityLang}}} is required to designate a ''deadline'' -- which can be used to associate the corresponding {{{Activity}}}-records with a suitable {{{Epoch}}}. The //temporal spacing// of epochs, as well as the number of active epochs (=extents) must be managed dynamically, to accommodate varying levels of load. This bears the danger of control oscillations, and more fine tuning and observations under real-world conditions are indicated {{red{as of 7/23}}}, see [[#1316|https://issues.lumiera.org/ticket/1316]]. When the reserved allocation for an epoch turns out as insufficient (i.e. the underlying extent has been filled up prior to maturity), further {{{Activity}}} records will be //„borrowed“// from the next epoch, while reducing the epoch spacing for compensation. Each {{{Epoch}}} automatically maintains a specifically rigged »''~EpochGuard''«-{{{Activity}}}, always located in the first »slot« of the epoch storage. This guard models the deadline and additionally allows to block deallocation with a count-down latch, which can be tied to pending IO operations.
The auto-regulation of this allocation scheme is based on //controlling the Epoch duration// dynamically. As immediate response to sudden load peaks, the Epoch stepping is reduced eagerly while excess allocations are shifted into Epochs with later deadline; the underlying {{{Extent}}} allocation pool is increased to satisfy additional demand. Overshooting regulation need to be limited however, which is achieved by watching the fill level of each Epoch at the later time point when is //is discarded.// This generates a signal to counteract the eager increase of capacity, and can be used to regulate the load factor to be close to 90%. Yet this quite precise accounting is only possibly with some delay (the limited life time of the Epochs is fundamental trait of this allocation scheme); this second steering signal is thus passed through an exponential moving average and applied with considerable damping, albeit with higher binding force than the eager capacity increase.
!!!performance considerations
It should be noted that {{{BlockFlow}}} provides very specific services, which are more elaborate than just a custom memory allocator. By leveraging possible scale factors, it is possible however to bring the amortised effort for a single {{{Activity}}} allocation down into the same order of magnitude as a standard heap allocation, which equates to roughly 30ns on contemporary machines. For context, an individually managed allocation-deallocation pair with a ref-counting {{{std::shared_ptr}}} has a typical performance cost of ~100ns.
The primary scaling effects exploited to achieve this level of performance are the combined de-allocation of a complete Epoch, and the combination of several allocations tied to a common deadline. However -- since the Epoch duration is chosen dynamically, performance can potentially be //degraded drastically// once the scheme is put under pressure -- since each new allocation has to search through the list of active Epochs. Parameters are tuned such as to ensure this list remains very short (about 5 Epochs) under typical operational conditions.
</pre>
</div>
<div title="SchedulerRequirements" modifier="Ichthyostega" created="201107080145" modified="201112171835" tags="Rendering spec draft discuss">

View file

@ -78824,9 +78824,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1688336218233" HGAP="-55" ID="ID_323523273" MODIFIED="1688337255857" TEXT="testgetriebener Aufbau" VSHIFT="34">
<linktarget COLOR="#fe3a58" DESTINATION="ID_323523273" ENDARROW="Default" ENDINCLINATION="-167;17;" ID="Arrow_ID_589297136" SOURCE="ID_1968961000" STARTARROW="None" STARTINCLINATION="-139;-149;"/>
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1688336601091" ID="ID_1454374119" MODIFIED="1688514802412" TEXT="BlockFlow_test">
<linktarget COLOR="#eb4070" DESTINATION="ID_1454374119" ENDARROW="Default" ENDINCLINATION="-596;80;" ID="Arrow_ID_208594716" SOURCE="ID_836380061" STARTARROW="None" STARTINCLINATION="-331;-16;"/>
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1688336601091" ID="ID_1454374119" MODIFIED="1689993700816" TEXT="BlockFlow_test">
<linktarget COLOR="#50c146" DESTINATION="ID_1454374119" ENDARROW="Default" ENDINCLINATION="-596;80;" ID="Arrow_ID_208594716" SOURCE="ID_836380061" STARTARROW="None" STARTINCLINATION="-331;-16;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1688336974018" ID="ID_1806920884" MODIFIED="1688337018608" TEXT="&#xbb;Epoch&#xab; based memory layout">
<icon BUILTIN="info"/>
</node>
@ -78917,19 +78917,24 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689199850230" ID="ID_500959752" MODIFIED="1689199853830" TEXT="storageFlow">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1689202692911" ID="ID_906364025" MODIFIED="1689639989685" TEXT="Massentest zur Performance-Messung">
<linktarget COLOR="#a03b66" DESTINATION="ID_906364025" ENDARROW="Default" ENDINCLINATION="-1525;104;" ID="Arrow_ID_849510703" SOURCE="ID_1170043916" STARTARROW="None" STARTINCLINATION="455;-1256;"/>
<node COLOR="#338800" CREATED="1689199850230" ID="ID_500959752" MODIFIED="1689993386504" TEXT="storageFlow">
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1689202692911" FOLDED="true" ID="ID_906364025" MODIFIED="1689996471260" TEXT="Massentest zur Performance-Messung">
<linktarget COLOR="#3ba098" DESTINATION="ID_906364025" ENDARROW="Default" ENDINCLINATION="-1525;104;" ID="Arrow_ID_849510703" SOURCE="ID_1170043916" STARTARROW="None" STARTINCLINATION="455;-1256;"/>
<icon BUILTIN="info"/>
<node CREATED="1689607803699" ID="ID_620009729" MODIFIED="1689609183664" TEXT="Default-Init-Parameter">
<node COLOR="#435e98" CREATED="1689607803699" ID="ID_620009729" MODIFIED="1689993509825" TEXT="Default-Init-Parameter">
<icon BUILTIN="info"/>
<node CREATED="1689608995574" ID="ID_1382602336" MODIFIED="1689608995574" TEXT="EPOCH_SIZ = 100"/>
<node CREATED="1689609002434" ID="ID_216937805" MODIFIED="1689609002434" TEXT="ACTIVITIES_PER_FRAME = 10"/>
<node CREATED="1689609017551" ID="ID_272032946" MODIFIED="1689609040604" TEXT="&#x27f9; FRAMES_PER_EPOCH = 10"/>
<node CREATED="1689609051050" ID="ID_1257102210" MODIFIED="1689609058851" TEXT="initial assumed Framerate: 50 fps"/>
<node CREATED="1689609051050" ID="ID_1257102210" MODIFIED="1689993486041" TEXT="initial assumed Framerate: 2 *25 fps"/>
<node CREATED="1689609075143" ID="ID_344074739" MODIFIED="1689609133361" TEXT="&#x27f9; INITIAL_EPOCH_STEP = 200ms"/>
</node>
<node COLOR="#435e98" CREATED="1689993440459" ID="ID_1517441371" MODIFIED="1689993508074" TEXT="Parameter f&#xfc;r Real-Betrieb">
<icon BUILTIN="info"/>
<node CREATED="1689608995574" ID="ID_710035024" MODIFIED="1689993463534" TEXT="EPOCH_SIZ = 500"/>
<node CREATED="1689993496963" ID="ID_967241641" MODIFIED="1689993502910" TEXT="initial assumed Framerate: 5 * 25 fps "/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1689609141854" ID="ID_82493559" MODIFIED="1689610221195">
<richcontent TYPE="NODE"><html>
<head/>
@ -78948,13 +78953,12 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1689610228610" ID="ID_1383838489" MODIFIED="1689610246476" TEXT="aber auch hinreichend viel Durchsatz f&#xfc;r Laufzeitmessung"/>
</node>
<node CREATED="1689609334347" ID="ID_1456811556" MODIFIED="1689610460870" TEXT="Zielwert: 200 fps f&#xfc;r simulierte 60 Sekunden mit 500ms Planungsvorlauf"/>
<node CREATED="1689609334347" ID="ID_1456811556" MODIFIED="1689993432552" TEXT="Zielwert: 200 fps f&#xfc;r simulierte 3 Minuten mit 500ms Planungsvorlauf"/>
<node CREATED="1689609354638" ID="ID_13693062" MODIFIED="1689609360660" TEXT="erwartete Lastdaten">
<node CREATED="1689609372927" ID="ID_1978827728" MODIFIED="1689609380722" TEXT="12000 Frames"/>
<node CREATED="1689609382411" ID="ID_155883232" MODIFIED="1689609389365" TEXT="120000 Activities"/>
<node CREATED="1689609467874" ID="ID_1876259312" MODIFIED="1689609473232" TEXT="1200 Epochen"/>
<node CREATED="1689610411828" ID="ID_386161916" MODIFIED="1689610424739" TEXT="2000 Activities/sec"/>
<node CREATED="1689611568517" ID="ID_1701491686" MODIFIED="1689611600839" TEXT="20 Epochen / sec"/>
<node CREATED="1689609372927" ID="ID_1978827728" MODIFIED="1689993423049" TEXT="36000 Frames"/>
<node CREATED="1689609382411" ID="ID_155883232" MODIFIED="1689993411675" TEXT="360000 Activities"/>
<node CREATED="1689610411828" ID="ID_386161916" MODIFIED="1689993570348" TEXT="2000 Activities/sec"/>
<node CREATED="1689609467874" ID="ID_1876259312" MODIFIED="1689993562902" TEXT="720 Epochen"/>
<node CREATED="1689610474674" ID="ID_1543562596" MODIFIED="1689610513127" TEXT="&#x2205; 1000 Activities im Vorlauf">
<node CREATED="1689610536148" ID="ID_1153226592" MODIFIED="1689610541467" TEXT="das sind &#x2205; 10 Epochen"/>
<node CREATED="1689610676253" ID="ID_910559745" MODIFIED="1689610685976" TEXT="verwende &#xb1;200ms Streuung im Vorlauf"/>
@ -78962,7 +78966,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1689611710754" ID="ID_488317579" MODIFIED="1689611720732" TEXT="alle 100ms ein clean-up"/>
</node>
</node>
<node COLOR="#338800" CREATED="1689560632798" ID="ID_1959869883" MODIFIED="1689639978410" TEXT="probabilistische F&#xfc;llung verwenden">
<node COLOR="#338800" CREATED="1689560632798" FOLDED="true" ID="ID_1959869883" MODIFIED="1689639978410" TEXT="probabilistische F&#xfc;llung verwenden">
<icon BUILTIN="button_ok"/>
<node CREATED="1689610738613" ID="ID_981353581" MODIFIED="1689610750951" TEXT="System wird synchron Ende-zu-Ende unter Druck gesetzt"/>
<node CREATED="1689610757842" ID="ID_1665227842" MODIFIED="1689610778211" TEXT="erzeuge im Vorlauf die Zufallsdaten">
@ -78970,15 +78974,21 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1689610928747" ID="ID_796987353" MODIFIED="1689610975585" TEXT="Deadline-Vorlauf zuf&#xe4;llig 500ms &#xb1; 200ms"/>
</node>
<node CREATED="1689610781367" ID="ID_777278499" MODIFIED="1689610796142" TEXT="erzeuge die Activities direkt hintereinander">
<node CREATED="1689611029321" ID="ID_262626991" MODIFIED="1689611091545" TEXT="k&#xfc;nstliche Zeitachse">
<node CREATED="1689611092623" ID="ID_1167959769" MODIFIED="1689611179221" TEXT="120000/60000ms &#x2259; 2 / ms"/>
<node CREATED="1689611188368" ID="ID_1473863990" MODIFIED="1689611233453" TEXT="Messdauer 60.5 sec"/>
<node CREATED="1689611093797" ID="ID_852184671" MODIFIED="1689611304636" TEXT="t = i/121000"/>
<node CREATED="1689611317734" ID="ID_1020302542" MODIFIED="1689611352430" TEXT="i &#x2259; step mit 2step / ms"/>
<node COLOR="#338800" CREATED="1689611029321" ID="ID_262626991" MODIFIED="1689993653798" TEXT="k&#xfc;nstliche Zeitachse systematisch aus den Basisdaten aufbauen">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1689993660956" ID="ID_1439463033" MODIFIED="1689993680618" TEXT="alle Zufallszahlen vor dem eigentlichen Test vorberechnen und in Vector speichern">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1689610978989" ID="ID_986448579" MODIFIED="1689993690794" TEXT="stelle die Pointer auf die erzeugten Activiteis in vorbereiteten Vector">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1689611424768" ID="ID_770500915" MODIFIED="1689993693177" TEXT="mit 1000 Steps Verz&#xf6;gerung (500ms) : Pr&#xfc;fsumme zugreifen und lesen">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1689611688365" ID="ID_693753703" MODIFIED="1689993694159" TEXT="alle 200 Steps ein clean-up">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1689610978989" ID="ID_986448579" MODIFIED="1689610993746" TEXT="stelle die Pointer in vorbereiteten Vector"/>
<node CREATED="1689611424768" ID="ID_770500915" MODIFIED="1689611453648" TEXT="mit 1000 Steps Verz&#xf6;gerung (500ms) : Pr&#xfc;fsumme zugreifen und lesen"/>
<node CREATED="1689611688365" ID="ID_693753703" MODIFIED="1689611706798" TEXT="alle 200 Steps ein clean-up"/>
</node>
<node CREATED="1689611733375" ID="ID_1765690809" MODIFIED="1689611754896" TEXT="brauche Abstraktion der Messung durch zwei &#x3bb;">
<node CREATED="1689611756428" ID="ID_121020011" MODIFIED="1689611763612" TEXT="&#x3bb;1 : alloc"/>
@ -79186,7 +79196,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1688051068000" ID="ID_555375367" MODIFIED="1688336007132" TEXT="Thema: Arbeitsspeicher">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1688051068000" ID="ID_555375367" MODIFIED="1689994063022" TEXT="Thema: Arbeitsspeicher">
<icon BUILTIN="bell"/>
<node CREATED="1688051147135" ID="ID_1865550842" MODIFIED="1688051346737" TEXT="aktive Steuerung zwingend erforderlich">
<icon BUILTIN="yes"/>
@ -79196,7 +79206,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1688051303633" ID="ID_837527400" MODIFIED="1688051334263" TEXT="Verweise ohne Pr&#xfc;fung erm&#xf6;glichen"/>
<node CREATED="1688051266167" ID="ID_237996247" MODIFIED="1688051279937" TEXT="Keine Einzelfall-Suche und -Verwaltung"/>
</node>
<node CREATED="1688051375174" ID="ID_1732350232" MODIFIED="1688051379092" TEXT="m&#xf6;gliche Modelle">
<node CREATED="1688051375174" ID="ID_1732350232" MODIFIED="1689993770143" TEXT="m&#xf6;gliche Modelle">
<icon BUILTIN="idea"/>
<node COLOR="#5b280f" CREATED="1688051443983" ID="ID_1229960682" MODIFIED="1688051687690" TEXT="einfacher Kachel-Pool">
<icon BUILTIN="button_cancel"/>
<node CREATED="1688051454370" ID="ID_227724531" MODIFIED="1688051487509" TEXT="leistet schnelle Allokation"/>
@ -79230,7 +79241,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1688053388889" ID="ID_1778479709" MODIFIED="1688053515642" TEXT="Vorteil: gute Speicherauslastung und wenig contention-Probleme"/>
</node>
<node CREATED="1688053526333" ID="ID_617675303" MODIFIED="1688053637212" TEXT="Epochen-Pools">
<node COLOR="#435e98" CREATED="1688053526333" ID="ID_617675303" MODIFIED="1689993854261" TEXT="Epochen-Pools">
<linktarget COLOR="#929ace" DESTINATION="ID_617675303" ENDARROW="Default" ENDINCLINATION="-97;16;" ID="Arrow_ID_359478919" SOURCE="ID_1880692941" STARTARROW="None" STARTINCLINATION="-8;-22;"/>
<node CREATED="1688053638890" ID="ID_276255064" MODIFIED="1688053999948" TEXT="alle Activities bis zu einer Deadline sch&#xf6;pfen aus einem Pool"/>
<node CREATED="1688054012571" ID="ID_1965757784" MODIFIED="1688054041039" TEXT="Vorteil: keinerlei Einzelfallpr&#xfc;fung notwendig"/>
<node CREATED="1688054042658" ID="ID_593771141" MODIFIED="1688054900987" TEXT="Nachteil: Speicher bleibt bis zur Deadline nutzlos geblockt">
@ -79271,7 +79283,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node COLOR="#435e98" CREATED="1688055236771" ID="ID_1880692941" MODIFIED="1689560781065" TEXT="Entscheidung f&#xfc;r ein Schema">
<node COLOR="#435e98" CREATED="1688055236771" FOLDED="true" ID="ID_1880692941" MODIFIED="1689560781065" TEXT="Entscheidung f&#xfc;r ein Schema">
<arrowlink COLOR="#929ace" DESTINATION="ID_617675303" ENDARROW="Default" ENDINCLINATION="-97;16;" ID="Arrow_ID_359478919" STARTARROW="None" STARTINCLINATION="-8;-22;"/>
<icon BUILTIN="yes"/>
<node CREATED="1688055361612" ID="ID_1809618499" MODIFIED="1688057881911" TEXT="Cluster/count-down ist &#x201e;sch&#xf6;n&#x201c; &#x2014; aber leider nur auf den ersten Blick"/>
<node CREATED="1688055245099" ID="ID_1913128751" MODIFIED="1688057920440" TEXT="das Epochen-Schema...">
@ -79401,8 +79414,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1688337270626" ID="ID_1810148055" MODIFIED="1688337284937" TEXT="&#xbb;BlockFlow&#xab; : Implementation">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1688337270626" ID="ID_1810148055" MODIFIED="1689994032309" TEXT="&#xbb;BlockFlow&#xab; : Implementation">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1688398675985" ID="ID_291772625" MODIFIED="1689188506325" TEXT="Basis: ExtentFamily">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1688398685028" ID="ID_1348599303" MODIFIED="1689188393371" TEXT="Anforderungen">
@ -79775,8 +79788,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1688509829145" HGAP="36" ID="ID_836380061" MODIFIED="1689560578397" TEXT="ben&#xf6;tigte high-Level-Operationen identifizieren">
<arrowlink COLOR="#eb4070" DESTINATION="ID_1454374119" ENDARROW="Default" ENDINCLINATION="-596;80;" ID="Arrow_ID_208594716" STARTARROW="None" STARTINCLINATION="-331;-16;"/>
<node COLOR="#338800" CREATED="1688509829145" FOLDED="true" HGAP="36" ID="ID_836380061" MODIFIED="1689993872497" TEXT="ben&#xf6;tigte high-Level-Operationen identifizieren">
<arrowlink COLOR="#50c146" DESTINATION="ID_1454374119" ENDARROW="Default" ENDINCLINATION="-596;80;" ID="Arrow_ID_208594716" STARTARROW="None" STARTINCLINATION="-331;-16;"/>
<linktarget COLOR="#473acf" DESTINATION="ID_836380061" ENDARROW="Default" ENDINCLINATION="47;-174;" ID="Arrow_ID_166794449" SOURCE="ID_361634809" STARTARROW="None" STARTINCLINATION="-289;16;"/>
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1688510160724" ID="ID_915708936" MODIFIED="1689528992185" TEXT="Activity allozieren">
@ -79878,12 +79891,12 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1688515962746" HGAP="25" ID="ID_468510160" MODIFIED="1689560775845" TEXT="Strukturen" VSHIFT="4">
<node COLOR="#338800" CREATED="1688515962746" HGAP="38" ID="ID_468510160" MODIFIED="1689560775845" TEXT="Strukturen" VSHIFT="4">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1688515974697" ID="ID_1054833524" MODIFIED="1689296818673" TEXT="h&#xe4;lt eine ExtentFamily&lt;Activity,siz&gt;">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1688555107931" ID="ID_285024973" MODIFIED="1689528942853" TEXT="Datentyp: Epoch">
<node COLOR="#338800" CREATED="1688555107931" FOLDED="true" ID="ID_285024973" MODIFIED="1689528942853" TEXT="Datentyp: Epoch">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1688555141913" ID="ID_406773800" MODIFIED="1689296815496" TEXT="als Subtyp der Extent-Storage">
<icon BUILTIN="button_ok"/>
@ -80106,7 +80119,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node COLOR="#338800" CREATED="1688516187452" ID="ID_843039397" MODIFIED="1689528833423" TEXT="Zusatz-Infos zu verwalten">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1688516199288" ID="ID_1824919687" MODIFIED="1689528828766" TEXT="Epochen-Deadline">
<node COLOR="#338800" CREATED="1688516199288" FOLDED="true" ID="ID_1824919687" MODIFIED="1689528828766" TEXT="Epochen-Deadline">
<icon BUILTIN="button_ok"/>
<node CREATED="1688516220648" ID="ID_1169377280" MODIFIED="1688516237353" TEXT="steht in einem Gate im 1.Slot"/>
<node COLOR="#435e98" CREATED="1688553471328" HGAP="24" ID="ID_262514506" MODIFIED="1689296881046" TEXT="daf&#xfc;r eigenen Sub-Typ anliegen: EpochGate" VSHIFT="7">
@ -80204,8 +80217,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1689204220486" ID="ID_277319829" MODIFIED="1689560519834" TEXT="Flow-Zyklus">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1689204220486" FOLDED="true" HGAP="37" ID="ID_277319829" MODIFIED="1689994046938" TEXT="Flow-Zyklus" VSHIFT="1">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1689204233030" ID="ID_649398296" MODIFIED="1689905259947" TEXT="Frage: Parametrisierung?">
<icon BUILTIN="help"/>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1689357111293" ID="ID_1755712040" MODIFIED="1689357127978" TEXT="Alle Werte erst mal fest verdrahtet">
@ -80390,7 +80403,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1689204430524" ID="ID_1525654861" MODIFIED="1689560447571" TEXT="Signale">
<node COLOR="#338800" CREATED="1689204430524" FOLDED="true" ID="ID_1525654861" MODIFIED="1689560447571" TEXT="Signale">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1689204438866" ID="ID_586190414" MODIFIED="1689528725978" TEXT="Epochen-Overflow">
<linktarget COLOR="#34819d" DESTINATION="ID_586190414" ENDARROW="Default" ENDINCLINATION="-456;-39;" ID="Arrow_ID_1282441869" SOURCE="ID_855611178" STARTARROW="None" STARTINCLINATION="-78;65;"/>
@ -80471,10 +80484,12 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689560454292" ID="ID_1170043916" MODIFIED="1689560767049" TEXT="Laufzeitverhalten beobachten">
<arrowlink COLOR="#a03b66" DESTINATION="ID_906364025" ENDARROW="Default" ENDINCLINATION="-1525;104;" ID="Arrow_ID_849510703" STARTARROW="None" STARTINCLINATION="455;-1256;"/>
<icon BUILTIN="flag-yellow"/>
<node CREATED="1689607767280" ID="ID_1402491463" MODIFIED="1689607773610" TEXT="Analyse-Setup">
<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;"/>
<arrowlink COLOR="#636cb5" DESTINATION="ID_256501398" ENDARROW="Default" ENDINCLINATION="-369;-101;" ID="Arrow_ID_1474600084" STARTARROW="None" STARTINCLINATION="439;37;"/>
<linktarget COLOR="#5366b8" DESTINATION="ID_1170043916" ENDARROW="Default" ENDINCLINATION="-302;546;" ID="Arrow_ID_718336697" SOURCE="ID_558083096" STARTARROW="None" STARTINCLINATION="-1231;101;"/>
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1689607767280" ID="ID_1402491463" MODIFIED="1689993920706" TEXT="Analyse-Setup">
<icon BUILTIN="info"/>
<node COLOR="#338800" CREATED="1689560462402" ID="ID_572069226" MODIFIED="1689640015674" TEXT="verwende probabilisitsche F&#xfc;llung">
<icon BUILTIN="button_ok"/>
@ -80963,7 +80978,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1689905291335" ID="ID_819874692" MODIFIED="1689905297638" TEXT="Me&#xdf;werte">
<icon BUILTIN="messagebox_warning"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1689905301815" ID="ID_405640996" MODIFIED="1689905322286" TEXT="die Optimierung ist instabil">
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1689905301815" ID="ID_405640996" MODIFIED="1689950763361" TEXT="die Code-Optimierung ist instabil">
<icon BUILTIN="broken-line"/>
<node CREATED="1689905324122" ID="ID_792821621" MODIFIED="1689905374660" TEXT="st&#xe4;rkere Verwendung der Diagnostik-Funktionen kann ebenfalls +10ns bewirken"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689905375355" ID="ID_1645056082" MODIFIED="1689905463104" TEXT="die beobachteten besseren Werte (45ns -&gt; 35ns) beruhten auf auskommentierten Testf&#xe4;llen">
@ -81015,11 +81030,143 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1689817546283" ID="ID_165095840" MODIFIED="1689817582250" TEXT="das System l&#xe4;uft nach Last&#xe4;nderungen zu lange mit unpassender Parametrisierung"/>
<node CREATED="1689817583069" ID="ID_1436375130" MODIFIED="1689817598879" TEXT="und hat zu lange Zeit, w&#xe4;hrenddessen komplett aus dem Ruder zu laufen"/>
</node>
<node COLOR="#338800" CREATED="1689957719174" ID="ID_803343004" MODIFIED="1689982764638" TEXT="Einstellungen unter h&#xf6;herer Last pr&#xfc;fen">
<icon BUILTIN="button_ok"/>
<node CREATED="1689957738867" ID="ID_382228850" MODIFIED="1689957747374" TEXT="verwende mal die 5-fache Last">
<icon BUILTIN="yes"/>
</node>
<node CREATED="1689957748553" ID="ID_1266344997" MODIFIED="1689957765233" TEXT="die Reaktionszeiten bleiben stabil"/>
<node CREATED="1689957844712" ID="ID_624897576" MODIFIED="1689957881817" TEXT="das Regelverhalten sieht gesund aus">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
vor allem die 2-Schichtige Regelung, die &#220;bersteuerungen wieder einf&#228;ngt...
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1689957766031" ID="ID_604445268" MODIFIED="1689970468326" TEXT="allerdings geht das System in extreme &#xdc;berlast (&gt;40 Bl&#xf6;cke Backlog)">
<icon BUILTIN="messagebox_warning"/>
</node>
<node COLOR="#338800" CREATED="1689957816332" ID="ID_790127688" MODIFIED="1689970390032" TEXT="&#x27f9; Mehrfach-Overflows besser doch einzeln einbuchen">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1689970392316" ID="ID_616252096" MODIFIED="1689970458561" TEXT="daraufhin Overload nach 2.5sec behoben (nur max +25 Bl&#xf6;cke Backlog)"/>
<node CREATED="1689970471668" ID="ID_1896898039" MODIFIED="1689970487731" TEXT="danach nochmal leichtes Overload (+2 Block)"/>
<node CREATED="1689970491847" ID="ID_583645348" MODIFIED="1689970503145">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
bereits nach 5 sec im <i>lock-step</i>
</p>
</body>
</html></richcontent>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1689982374730" ID="ID_1285035201" MODIFIED="1689982410622">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
unter extremer &#220;berlast gibt es einen ung&#252;nstigen <b>Mitkopplungs-Effekt</b>
</p>
</body>
</html></richcontent>
<icon BUILTIN="broken-line"/>
<node CREATED="1689982419508" ID="ID_349137595" MODIFIED="1689982435779" TEXT="wenn der Epoch-Step bereits bis auf das Minimum heruntergefahren wurde">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1689982436801" ID="ID_1534182741" MODIFIED="1689982672346">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
... dann werden <b>extrem viele neue Bl&#246;cke</b>&#160;hinzugef&#252;gt
</p>
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
In diesem extremen Overload gilt: <i>jeder neue Block wandert die Kette entlang</i>&#160;und wird &#8222;hinten abgeworfen&#8220;. Dort hinten ist dann zwar das Spacing bereits klein genug, um die Last aufzufangen &#8212; aber <i>vorne besteht noch ein viel gr&#246;&#223;eres Spacing.<b>&#160;</b></i>Konsequenz: w&#228;hrend die Einf&#252;geposition vorne immer noch die gleichen alten zu langen Epochen &#252;berf&#252;llt, werden hinten permanent neue Mini-Epochen angeh&#228;ngt. Erst wenn auch die Einf&#252;ge-Position im Bereich der kleinen Bl&#246;cke angekommen ist, baut sich der R&#252;ckstau (ziemlich schnell) ab.
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1689982460830" ID="ID_984735290" MODIFIED="1689982488254" TEXT="&#x27f9; das Backlog w&#xe4;chst an, bis auch die aktuelle Position nachgekommen ist"/>
</node>
<node COLOR="#338800" CREATED="1689982675969" ID="ID_1366866694" MODIFIED="1689982708144" TEXT="&#x27f9; sollte die Bl&#xf6;cke nicht zu klein werden lassen">
<icon BUILTIN="button_ok"/>
<node CREATED="1689982710492" ID="ID_1913227483" MODIFIED="1689982721832" TEXT="die &#xdc;berlast schon bei 1/4 des bisherigen Wertes kappen"/>
<node CREATED="1689982723163" ID="ID_1597778968" MODIFIED="1689982736837" TEXT="auch das ist mehr als genug">
<icon BUILTIN="yes"/>
</node>
<node CREATED="1689982739334" ID="ID_1325440779" MODIFIED="1689982754154" TEXT="dadurch w&#xe4;chst aber das Backlog (und damit die Allokation) weniger an"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1688559356693" HGAP="9" ID="ID_1823374976" MODIFIED="1688559375797" TEXT="Grenzf&#xe4;lle" VSHIFT="7">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#435e98" CREATED="1689950328624" FOLDED="true" HGAP="-13" ID="ID_256501398" MODIFIED="1689993985081" TEXT="Fazit" VSHIFT="4">
<linktarget COLOR="#636cb5" DESTINATION="ID_256501398" ENDARROW="Default" ENDINCLINATION="-369;-101;" ID="Arrow_ID_1474600084" SOURCE="ID_1170043916" STARTARROW="None" STARTINCLINATION="439;37;"/>
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="forward"/>
<node CREATED="1689950345232" ID="ID_360564477" MODIFIED="1689950453654" TEXT="Betriebs-Parametrisierung">
<node CREATED="1689950455235" ID="ID_1151158118" MODIFIED="1689950460693" TEXT="500 Slots/Epoche"/>
<node CREATED="1689950475992" ID="ID_1049792646" MODIFIED="1689950487415" TEXT="50 Frames per Epoch"/>
<node CREATED="1689950461585" ID="ID_1621205435" MODIFIED="1689950534818" TEXT="initial 5 streams (125 fps)"/>
<node CREATED="1689950464713" ID="ID_1661388363" MODIFIED="1689950472807" TEXT="Epoch-Step 400ms"/>
</node>
<node CREATED="1689950543944" ID="ID_608988368" MODIFIED="1689950584911" TEXT="typischerweise leicht &#xfc;bertrieben und regelt sich dann langsam auf das Optimum herunter">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1689950587187" ID="ID_556296327" MODIFIED="1689950601684" TEXT="Testfall mit 200 fps">
<node CREATED="1689950603056" ID="ID_1886508729" MODIFIED="1689975501688" TEXT="geht f&#xfc;r 4 Sekunden in &#xdc;berlast"/>
<node CREATED="1689950623124" ID="ID_93627662" MODIFIED="1689954091686" TEXT="schiebt im Schnitt +1 Epoche vor sich her (max +3)"/>
<node CREATED="1689950660388" ID="ID_152417641" MODIFIED="1689975522833">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
nach weiteren 6 Sekunden ist die Regelung<i>&#160;locked&#160;to target</i>
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1689950684224" ID="ID_1736716979" MODIFIED="1689950696097" TEXT="hat im Schnitt 6 offene Epochen"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1689989914104" ID="ID_1875944853" MODIFIED="1689989984058" TEXT="Laufzeiten -O3">
<icon BUILTIN="forward"/>
<node CREATED="1689989933355" ID="ID_845757793" MODIFIED="1689989977713" TEXT="noAlloc: 9ns"/>
<node CREATED="1689989936387" ID="ID_848944790" MODIFIED="1689989964587" TEXT="heapAlloc: 23ns"/>
<node CREATED="1689989939363" ID="ID_1418270280" MODIFIED="1689989958732" TEXT="refcntAlloc: 97ns"/>
<node CREATED="1689989943802" ID="ID_347157521" MODIFIED="1689989992692">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
blockFlow: <b>32</b>ns
</p>
</body>
</html></richcontent>
</node>
</node>
</node>
<node CREATED="1689950700829" ID="ID_838109116" MODIFIED="1689950717404" TEXT="durchschnittliche Allokations-Zeit l&#xe4;&#xdf;t sich kaum unter 30ns dr&#xfc;cken"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1688559356693" HGAP="19" ID="ID_1823374976" MODIFIED="1689994043643" TEXT="Grenzf&#xe4;lle" VSHIFT="8">
<icon BUILTIN="list"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1688559379394" ID="ID_1315709817" MODIFIED="1688560429832" TEXT="zu weit in der Zukunft">
<linktarget COLOR="#fd1a6e" DESTINATION="ID_1315709817" ENDARROW="Default" ENDINCLINATION="21;-31;" ID="Arrow_ID_1483237280" SOURCE="ID_27532065" STARTARROW="None" STARTINCLINATION="-248;12;"/>
<icon BUILTIN="messagebox_warning"/>
@ -81043,7 +81190,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</html></richcontent>
<icon BUILTIN="clanbomber"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1688774377755" HGAP="25" ID="ID_459856850" MODIFIED="1688774405179" TEXT="Einsch&#xe4;tzung" VSHIFT="4">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1688774377755" HGAP="25" ID="ID_459856850" MODIFIED="1689950794771" TEXT="Einsch&#xe4;tzung" VSHIFT="4">
<edge COLOR="#7b323c"/>
<icon BUILTIN="yes"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1688773732470" ID="ID_1175257683" MODIFIED="1688773790095" TEXT="dieser Fall pa&#xdf;t mir nicht so recht ins Konzept">
@ -81073,19 +81220,20 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</body>
</html></richcontent>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1688775205671" ID="ID_263429425" MODIFIED="1688775230379" TEXT="daher per Exception abbrechen">
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1688775205671" ID="ID_263429425" MODIFIED="1689950800005" TEXT="daher per Exception abbrechen">
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1688776216348" ID="ID_1377510140" MODIFIED="1688776233672" TEXT="&#xdc;berlauf einer Epoche">
<node COLOR="#435e98" CREATED="1688776216348" ID="ID_1377510140" MODIFIED="1689951307913" TEXT="&#xdc;berlauf einer Epoche">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1688776236442" ID="ID_1772819578" MODIFIED="1688776249385" TEXT="die Epoche ist mit einer festen Gr&#xf6;&#xdf;e vor-alloziert"/>
<node CREATED="1688776251767" ID="ID_1569050620" MODIFIED="1688776277483" TEXT="demnach kann sie zu klein sein und damit bereits vorzeitig voll"/>
<node CREATED="1688778417547" ID="ID_1014314478" MODIFIED="1688778430437" TEXT="in diesem Fall wechseln wir (vorzeitig) auf die n&#xe4;chste Epoche"/>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1688778436978" ID="ID_1329649699" MODIFIED="1688847252879" TEXT="...und justieren die Epochen-Dauer nach">
<icon BUILTIN="hourglass"/>
<node CREATED="1688846534217" ID="ID_1103016582" MODIFIED="1688846978585" TEXT="nicht ganz einfach: Zeitpunkt und Grad">
<node COLOR="#338800" CREATED="1688778436978" ID="ID_1329649699" MODIFIED="1689950910885" TEXT="...und justieren die Epochen-Dauer nach">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1688846534217" ID="ID_1103016582" MODIFIED="1689950908528" TEXT="nicht ganz einfach: Zeitpunkt und Grad">
<richcontent TYPE="NOTE"><html>
<head>
@ -81097,13 +81245,57 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</body>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1688847294057" ID="ID_1401641986" MODIFIED="1688847402052" TEXT="kurzfristig: bei &#xdc;berlauf einen Zuschlag geben">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1688847294057" ID="ID_1401641986" MODIFIED="1689950836532" TEXT="kurzfristig: bei &#xdc;berlauf einen Zuschlag geben">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1688847321781" ID="ID_1927207477" MODIFIED="1688847391104" TEXT="gemittelt: optimalen F&#xfc;llgrad steuern"/>
<node COLOR="#338800" CREATED="1688847321781" ID="ID_1927207477" MODIFIED="1689950837811" TEXT="gemittelt: optimalen F&#xfc;llgrad steuern">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1688846986442" ID="ID_514303739" MODIFIED="1688847240923" TEXT="&#x27f9; besser als ein TimingObservable mit Mittelwertbildung handhaben">
<arrowlink COLOR="#a11225" DESTINATION="ID_1197144274" ENDARROW="Default" ENDINCLINATION="206;-20;" ID="Arrow_ID_945653766" STARTARROW="None" STARTINCLINATION="-233;10;"/>
<node COLOR="#338800" CREATED="1689950854496" ID="ID_175704045" MODIFIED="1689950905793" TEXT="ziele auf eine F&#xfc;llgrad von 90%">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
damit kann die Mittelung in beide Richtungen um den Optimalwert arbeiten
</p>
</body>
</html></richcontent>
<icon BUILTIN="idea"/>
</node>
</node>
<node COLOR="#435e98" CREATED="1689951124796" ID="ID_1136496493" MODIFIED="1689951305811" TEXT="verwende eine zeitlich mehrstufige Balancierung">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<ul>
<li>
die &#220;berl&#228;ufe erzeugen einen sofort wirksamen Druck Richtung mehr Kapazit&#228;t
</li>
<li>
aber eine exponentielle Mittelung wirkt verz&#246;gert, jedoch mit gr&#246;&#223;erer Kraft
</li>
<li>
die Mittelung zielt auf 90% F&#252;llung, hat also eine kleine Regelzone, in der sie beidseitig wirkt
</li>
<li>
im Extremfall jedoch wirken Overflow und Mittelwert gegensinning, wobei der Overflow direkter und schneller wirksam wird, um dem System Luft zu verschaffen
</li>
<li>
die l&#228;ngerfristige Regelung jedoch bremst den Overflow mit einiger Verz&#246;gerung auch wieder aus; zwar f&#252;hrt das dazu, da&#223; die &#220;berlastung l&#228;nger besteht, daf&#252;r aber auch weicher ausgeregelt wird, wodurch das System anschlie&#223;end ohne weitere Schwingungen direkt in den lock-step &#252;bergeht
</li>
</ul>
</body>
</html></richcontent>
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1688846986442" ID="ID_514303739" MODIFIED="1689951110512" TEXT="k&#xf6;nnte sp&#xe4;ter als ein TimingObservable dargestellt werden">
<arrowlink COLOR="#85314b" DESTINATION="ID_1197144274" ENDARROW="Default" ENDINCLINATION="206;-20;" ID="Arrow_ID_945653766" STARTARROW="None" STARTINCLINATION="-249;11;"/>
<icon BUILTIN="idea"/>
<icon BUILTIN="hourglass"/>
</node>
</node>
</node>
@ -81121,8 +81313,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node COLOR="#435e98" CREATED="1689204675211" ID="ID_428260433" MODIFIED="1689204694353" STYLE="fork" TEXT="Kapazit&#xe4;t"/>
<node COLOR="#435e98" CREATED="1689204681138" ID="ID_719751542" MODIFIED="1689204694353" STYLE="fork" TEXT="Index-Positionen"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689204604589" ID="ID_1478405779" MODIFIED="1689204610300" TEXT="Deadlines">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1689204604589" ID="ID_1478405779" MODIFIED="1689994014285" TEXT="Deadlines">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1689204644343" ID="ID_1848987574" MODIFIED="1689449409248" TEXT="oldest"/>
<node COLOR="#435e98" CREATED="1689204650526" ID="ID_624484958" MODIFIED="1689449409248" TEXT="newest"/>
<node COLOR="#435e98" CREATED="1689204731722" ID="ID_1494295782" MODIFIED="1689439593921" TEXT="Allokations-Zuordnung"/>
@ -81252,8 +81444,24 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1688847208788" ID="ID_1229178383" MODIFIED="1688847225405" TEXT="Zweck">
<icon BUILTIN="info"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1688847011314" ID="ID_1197144274" MODIFIED="1688847240923" TEXT="steuern der Epochen-L&#xe4;nge">
<linktarget COLOR="#a11225" DESTINATION="ID_1197144274" ENDARROW="Default" ENDINCLINATION="206;-20;" ID="Arrow_ID_945653766" SOURCE="ID_514303739" STARTARROW="None" STARTINCLINATION="-233;10;"/>
<linktarget COLOR="#85314b" DESTINATION="ID_1197144274" ENDARROW="Default" ENDINCLINATION="206;-20;" ID="Arrow_ID_945653766" SOURCE="ID_514303739" STARTARROW="None" STARTINCLINATION="-249;11;"/>
<icon BUILTIN="flag-yellow"/>
<node COLOR="#435e98" CREATED="1689950955808" ID="ID_539654006" MODIFIED="1689951087443" TEXT="Stand 7/23 : vollst&#xe4;ndig im BlockFlow selber implementiert">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Zun&#228;chst dachte ich, das ist <i>nur ein Provisorium...</i>
</p>
<p>
Aber derzeit ist eine vollt&#228;ndige und elaborierte Regelung im BlockFlow selber implementiert, die bereits robust aussieht und auch kurzzeitige Lastspitzen gut abfedert; es erscheint zweifelhaft, ob hier noch eine externe Regelung ben&#246;tigt wird. M&#246;glicherweise k&#246;nnte das TimingObservable einen <b>2. Layer</b>&#160;bilden, der die Grundparameter des Algorithmus l&#228;ngerfristig optimiert
</p>
</body>
</html></richcontent>
<icon BUILTIN="info"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1688851183024" ID="ID_371629266" MODIFIED="1688851189173" TEXT="#1317 capture Scheduler allocator behaviour">
<icon BUILTIN="hourglass"/>
</node>
@ -88851,6 +89059,36 @@ class Something
</node>
</node>
</node>
<node CREATED="1689951616772" FOLDED="true" ID="ID_1731970825" MODIFIED="1689951678536" TEXT="Diagnose-Patches">
<icon BUILTIN="list"/>
<node CREATED="1689951371503" ID="ID_558083096" MODIFIED="1689951667311" TEXT="Diagnose BlockFlow-Verhalten">
<arrowlink COLOR="#5366b8" DESTINATION="ID_1170043916" ENDARROW="Default" ENDINCLINATION="-302;546;" ID="Arrow_ID_718336697" STARTARROW="None" STARTINCLINATION="-1231;101;"/>
<icon BUILTIN="info"/>
<node CREATED="1689951419600" ID="ID_738226800" MODIFIED="1689951473750">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
<u>Bezug</u>: Changeset <font face="Monospaced" color="#704ea7">bf35ae0</font>
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1689951480271" ID="ID_718912155" MODIFIED="1689951540442">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
als Patch <font size="1">(Tag)</font>&#160;<b>dump.blockFlow</b>
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1689951551670" ID="ID_1562067193" MODIFIED="1689951565361" TEXT="BlockFlow_test damit ausf&#xfc;hren">
<icon BUILTIN="idea"/>
</node>
</node>
</node>
</node>
</node>
<node CREATED="1439176875682" HGAP="47" ID="ID_1487331591" MODIFIED="1582315396874" TEXT="Referenzplattform" VSHIFT="60">