Block-Flow: investigate, fix and fine-tune Epoch size control
- BUG: must prevent the Epoch size to become excessive low - Problem: feedback signal should not be overly aggressive Fine-Tuning: - Dose for Overflow-compensation is delicate - Moving average and Overflow should be balanced - ideally the compensatory actions should be one order of magnitude slower than the characteristic regulation time Improvement: perform Moving-Average calculations in doubles
This commit is contained in:
parent
c7d6f3e24c
commit
c008858d8f
5 changed files with 278 additions and 48 deletions
|
|
@ -277,6 +277,16 @@ namespace time {
|
|||
}
|
||||
|
||||
|
||||
Offset
|
||||
Offset::stretchedByFloatFactor (double factor) const
|
||||
{
|
||||
double distance(this->t_);
|
||||
distance *= factor;
|
||||
gavl_time_t microTicks = floor (distance);
|
||||
return Offset{buildRaw_(microTicks)};
|
||||
}
|
||||
|
||||
|
||||
/** offset by the given number of frames. */
|
||||
Offset::Offset (FrameCnt count, FrameRate const& fps)
|
||||
: TimeValue{buildRaw_(
|
||||
|
|
|
|||
|
|
@ -396,6 +396,7 @@ namespace time {
|
|||
/** @internal stretch offset by a possibly fractional factor,
|
||||
* and quantise into raw (micro tick) grid */
|
||||
Offset stretchedByRationalFactor (boost::rational<int64_t>) const;
|
||||
Offset stretchedByFloatFactor (double) const;
|
||||
|
||||
/** @internal diagnostics, indicating ∆ */
|
||||
operator std::string () const;
|
||||
|
|
@ -422,9 +423,9 @@ namespace time {
|
|||
return Offset(distance);
|
||||
}
|
||||
|
||||
template<typename INT>
|
||||
template<typename FAC>
|
||||
inline Offset
|
||||
operator* (Offset const& distance, INT factor)
|
||||
operator* (Offset const& distance, FAC factor)
|
||||
{
|
||||
return factor*distance;
|
||||
}
|
||||
|
|
@ -445,6 +446,12 @@ namespace time {
|
|||
return offset.stretchedByRationalFactor (boost::rational<int64_t>(factor.numerator(), factor.denominator()));
|
||||
}
|
||||
|
||||
inline Offset
|
||||
operator* (double factor, Offset const& offset)
|
||||
{
|
||||
return offset.stretchedByFloatFactor (factor);
|
||||
}
|
||||
|
||||
|
||||
/** flip offset direction */
|
||||
inline Offset
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@
|
|||
#include "lib/rational.hpp"
|
||||
#include "lib/nocopy.hpp"
|
||||
#include "lib/util.hpp"
|
||||
#include "lib/format-cout.hpp"///////////////////////TODO
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
|
@ -113,8 +114,10 @@ namespace gear {
|
|||
|
||||
const Duration INITIAL_EPOCH_STEP{FRAMES_PER_EPOCH * FrameRate{50}.duration()};
|
||||
|
||||
const Rat OVERFLOW_BOOST_FACTOR = 9_r/10; ///< increase capacity on each Epoch overflow event
|
||||
const Rat EMPTY_THRESHOLD = 1_r/20; ///< do not account for (almost) empty Epochs to avoid overshooting regulation
|
||||
const double BOOST_FACTOR = 0.85; ///< adjust capacity by this factor on Epoch overflow/underflow events
|
||||
const double BOOST_OVERFLOW = pow(BOOST_FACTOR, 1.0/EPOCH_SIZ);
|
||||
const double DAMP_THRESHOLD = 0.06; ///< do not account for (almost) empty Epochs to avoid overshooting regulation
|
||||
const TimeValue MIN_EPOCH_STEP{1000}; ///< minimal Epoch spacing in µs to prevent stalled Epoch progression
|
||||
const size_t AVERAGE_EPOCHS = 10; ///< moving average len for exponential convergence towards average Epoch fill
|
||||
|
||||
/** raw allocator to provide a sequence of Extents to place Activity records */
|
||||
|
|
@ -204,10 +207,10 @@ namespace gear {
|
|||
EpochGate& gate() { return static_cast<EpochGate&> ((*this)[0]); }
|
||||
Time deadline() { return Time{gate().deadline()}; }
|
||||
|
||||
Rat
|
||||
double
|
||||
getFillFactor()
|
||||
{
|
||||
return Rat{gate().filledSlots(), SIZ()-1};
|
||||
return double(gate().filledSlots()) / (SIZ()-1);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -275,9 +278,12 @@ namespace gear {
|
|||
}
|
||||
|
||||
void
|
||||
adjustEpochStep (Rat factor)
|
||||
adjustEpochStep (double factor)
|
||||
{
|
||||
epochStep_ = getEpochStep() * factor;
|
||||
double stretched = _raw(epochStep_) * factor;
|
||||
gavl_time_t microTicks(floor (stretched));
|
||||
epochStep_ = TimeValue{microTicks};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -338,6 +344,7 @@ namespace gear {
|
|||
{
|
||||
auto lastDeadline = flow_->lastEpoch().deadline();
|
||||
epoch_.expandAlloc(); // may throw out-of-memory..
|
||||
cout<<"||∧| +1 ⟶ "<<watch(flow_->alloc_).active()<<" of "<<watch(flow_->alloc_).size()<<endl;
|
||||
ENSURE (epoch_);
|
||||
Epoch::setup (epoch_, lastDeadline + flow_->getEpochStep());
|
||||
}
|
||||
|
|
@ -360,9 +367,11 @@ namespace gear {
|
|||
AllocatorHandle
|
||||
until (Time deadline)
|
||||
{
|
||||
cout<<"||>| "<<TimeValue(deadline);
|
||||
if (isnil (alloc_))
|
||||
{//just create new Epoch one epochStep ahead
|
||||
alloc_.openNew();
|
||||
cout<<"\n||∧| +1 ⟶ "<<watch(alloc_).active()<<" of "<<watch(alloc_).size()<<endl;
|
||||
Epoch::setup (alloc_.begin(), deadline + Time{epochStep_});
|
||||
return AllocatorHandle{alloc_.begin(), this};
|
||||
}
|
||||
|
|
@ -370,7 +379,10 @@ namespace gear {
|
|||
{//find out how the given time relates to existing Epochs
|
||||
if (firstEpoch().deadline() >= deadline)
|
||||
// way into the past ... put it in the first available Epoch
|
||||
{
|
||||
cout<<" ««······ ⟶ ⟶ "<<TimeValue{firstEpoch().deadline()}<<endl;
|
||||
return AllocatorHandle{alloc_.begin(), this};
|
||||
}
|
||||
else
|
||||
if (lastEpoch().deadline() < deadline)
|
||||
{ // a deadline beyond the established Epochs...
|
||||
|
|
@ -382,7 +394,9 @@ namespace gear {
|
|||
auto requiredNew = distance / _raw(epochStep_);
|
||||
if (distance % _raw(epochStep_) > 0)
|
||||
++requiredNew; // fractional: requested deadline lies within last epoch
|
||||
cout<<" »»······ "<<lastDeadline<<" ⟶ Δ"<<TimeValue(distance)<<endl;
|
||||
alloc_.openNew(requiredNew); // Note: epochHandle now points to the first new Epoch
|
||||
cout<<"||∧| +"<<requiredNew<<" ⟶ "<<watch(alloc_).active()<<" of "<<watch(alloc_).size()<<endl;
|
||||
for ( ; 0 < requiredNew; --requiredNew)
|
||||
{
|
||||
REQUIRE (nextEpoch);
|
||||
|
|
@ -400,7 +414,10 @@ namespace gear {
|
|||
else
|
||||
for (EpochIter epochIt{alloc_.begin()}; epochIt; ++epochIt)
|
||||
if (epochIt->deadline() >= deadline)
|
||||
{
|
||||
cout<<" ◆◆······ ⟶ "<<TimeValue{epochIt->deadline()}<<endl;
|
||||
return AllocatorHandle{epochIt, this};
|
||||
}
|
||||
|
||||
NOTREACHED ("Inconsistency in BlockFlow Epoch deadline organisation");
|
||||
}
|
||||
|
|
@ -416,6 +433,7 @@ namespace gear {
|
|||
void
|
||||
discardBefore (Time deadline)
|
||||
{
|
||||
cout<<"||■| CLUP <- "<<TimeValue(deadline)<<endl;
|
||||
if (isnil (alloc_)
|
||||
or firstEpoch().deadline() > deadline)
|
||||
return;
|
||||
|
|
@ -444,7 +462,9 @@ namespace gear {
|
|||
void
|
||||
markEpochOverflow()
|
||||
{
|
||||
adjustEpochStep (OVERFLOW_BOOST_FACTOR);
|
||||
if (epochStep_ > MIN_EPOCH_STEP)
|
||||
adjustEpochStep (BOOST_OVERFLOW);
|
||||
cout<<"||*| OVER -> "<<_raw(epochStep_)<<endl;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -462,15 +482,23 @@ namespace gear {
|
|||
* without much spurious range checks. /////////////////////////////////////////////////////////TICKET #1259 : reorganise raw time base datatypes : need conversion path into FSecs
|
||||
*/
|
||||
void
|
||||
markEpochUnderflow (TimeVar actualLen, Rat fillFactor)
|
||||
markEpochUnderflow (TimeVar actualLen, double fillFactor)
|
||||
{
|
||||
Rat contribution{_raw(actualLen), _raw(epochStep_)};
|
||||
if (fillFactor > EMPTY_THRESHOLD) // treat almost empty blocks as if their length was optimal
|
||||
contribution /= fillFactor;
|
||||
auto interpolate = [&](auto f, auto v1, auto v2) { return f*v2 + (1-f)*v1; };
|
||||
|
||||
// use actual fill as signal, but limit signal for empty Epochs
|
||||
double adjust =
|
||||
fillFactor > DAMP_THRESHOLD? fillFactor
|
||||
: interpolate (DAMP_THRESHOLD-fillFactor, fillFactor,BOOST_FACTOR);
|
||||
|
||||
// damped adjustment towards ideal size
|
||||
double contribution = double(_raw(actualLen)) / _raw(epochStep_) / adjust;
|
||||
|
||||
// Exponential MA: mean ≔ mean * (N-1)/N + newVal/N
|
||||
const Rat N = AVERAGE_EPOCHS;
|
||||
Rat avgFactor = (contribution + N-1) / N;
|
||||
auto N = AVERAGE_EPOCHS;
|
||||
double avgFactor = (contribution + N-1) / N;
|
||||
adjustEpochStep (avgFactor);
|
||||
cout<<"||∨| MAVG -> "<<_raw(epochStep_)<<" <= len="<<actualLen<<" fill="<<fillFactor<<" -> want "<<TimeValue{gavl_time_t(_raw(actualLen)/fillFactor)}<<" con:"<<contribution<< " * "<<avgFactor<<endl;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ namespace test {
|
|||
CHECK (1 == gate.filledSlots());
|
||||
CHECK (gate.hasFreeSlot());
|
||||
|
||||
CHECK (epoch.getFillFactor() == Rat(gate.filledSlots(), Epoch::SIZ()-1));
|
||||
CHECK (epoch.getFillFactor() == double(gate.filledSlots()) / (Epoch::SIZ()-1));
|
||||
|
||||
// so let's eat this space up...
|
||||
for (uint i=extent.size()-2; i>1; --i)
|
||||
|
|
@ -278,22 +278,23 @@ 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) == "11s131ms"_expect);
|
||||
CHECK (watch(bFlow).allEpochs() == "10s200ms|10s400ms|10s600ms|10s800ms|11s|11s131ms"_expect);
|
||||
CHECK (watch(bFlow).find(a6) == "11s198ms"_expect);
|
||||
CHECK (watch(bFlow).allEpochs() == "10s200ms|10s400ms|10s600ms|10s800ms|11s|11s198ms"_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|11s131ms|11s262ms|11s393ms|11s524ms"_expect);
|
||||
CHECK (watch(bFlow).find(a7) == "11s524ms"_expect);
|
||||
CHECK (watch(bFlow).allEpochs() == "10s200ms|10s400ms|10s600ms|10s800ms|11s|11s198ms|11s397ms|11s596ms"_expect);
|
||||
CHECK (watch(bFlow).find(a7) == "11s596ms"_expect);
|
||||
|
||||
CHECK (bFlow.getEpochStep() == "≺131ms≻"_expect);
|
||||
// on clean-up, actual fill ratio is used to adjust to optimise Epoch length for better space usage
|
||||
CHECK (bFlow.getEpochStep() == "≺198ms≻"_expect);
|
||||
bFlow.discardBefore (Time{999,10});
|
||||
CHECK (bFlow.getEpochStep() == "≺149ms≻"_expect);
|
||||
CHECK (watch(bFlow).allEpochs() == "11s|11s131ms|11s262ms|11s393ms|11s524ms"_expect);
|
||||
CHECK (bFlow.getEpochStep() == "≺802ms≻"_expect);
|
||||
CHECK (watch(bFlow).allEpochs() == "11s|11s198ms|11s397ms|11s596ms"_expect);
|
||||
|
||||
// placed into the oldest Epoch still alive
|
||||
auto& a8 = bFlow.until(Time{500,10}).create();
|
||||
CHECK (watch(bFlow).find(a8) == "11s131ms"_expect);
|
||||
CHECK (watch(bFlow).find(a8) == "11s198ms"_expect);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -311,31 +312,45 @@ 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();
|
||||
CHECK (bFlow.getEpochStep() == INITIAL_EPOCH_STEP * OVERFLOW_BOOST_FACTOR);
|
||||
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 * OVERFLOW_BOOST_FACTOR*OVERFLOW_BOOST_FACTOR);
|
||||
CHECK (bFlow.getEpochStep() == INITIAL_EPOCH_STEP * BOOST_OVERFLOW*BOOST_OVERFLOW);
|
||||
|
||||
// To counteract this increase, on clean-up the actual fill rate of the Extent
|
||||
// serves to guess an optimal Epoch duration, which is averaged exponentially
|
||||
|
||||
// Using just arbitrary demo values for some fictional Epochs
|
||||
TimeVar dur1 = INITIAL_EPOCH_STEP;
|
||||
Rat fill1 = 8_r/10;
|
||||
TimeVar dur2 = INITIAL_EPOCH_STEP * OVERFLOW_BOOST_FACTOR;
|
||||
Rat fill2 = 3_r/10;
|
||||
double fac1 = 0.8;
|
||||
TimeVar dur2 = INITIAL_EPOCH_STEP * BOOST_OVERFLOW;
|
||||
double fac2 = 0.4;
|
||||
|
||||
Rat N = AVERAGE_EPOCHS;
|
||||
TimeVar step = bFlow.getEpochStep();
|
||||
|
||||
auto movingAverage = [&](TimeValue old, double contribution)
|
||||
{
|
||||
auto N = AVERAGE_EPOCHS;
|
||||
auto averageTicks = double(_raw(old))*(N-1)/N + contribution/N;
|
||||
return TimeValue{gavl_time_t (floor (averageTicks))};
|
||||
};
|
||||
|
||||
bFlow.markEpochUnderflow (dur1, fill1);
|
||||
CHECK (bFlow.getEpochStep() == Duration{FSecs{step}*(N-1)/N + FSecs{dur1}/fill1/N});
|
||||
SHOW_EXPR(bFlow.getEpochStep())
|
||||
bFlow.markEpochUnderflow (dur1, fac1);
|
||||
SHOW_EXPR(bFlow.getEpochStep())
|
||||
SHOW_EXPR(movingAverage(step, double(_raw(dur1)) / fac1))
|
||||
CHECK (bFlow.getEpochStep() == movingAverage(step, double(_raw(dur1)) / fac1));
|
||||
|
||||
step = bFlow.getEpochStep();
|
||||
bFlow.markEpochUnderflow (dur2, fill2);
|
||||
CHECK (bFlow.getEpochStep() == Duration{FSecs{step}*(N-1)/N + FSecs{dur2}/fill2/N});
|
||||
} // Note: for verification the exponential average is computed via FSecs
|
||||
// which is a different calculation path but yields the same result
|
||||
bFlow.markEpochUnderflow (dur2, fac2);
|
||||
SHOW_EXPR(_raw(bFlow.getEpochStep()))
|
||||
SHOW_EXPR(_raw(movingAverage(step, double(_raw(dur2)) / fac2)))
|
||||
CHECK (bFlow.getEpochStep() == movingAverage(step, double(_raw(dur2)) / fac2));
|
||||
}
|
||||
|
||||
|
||||
/** @test investigate progression of epochs under realistic load
|
||||
|
|
@ -363,13 +378,14 @@ namespace test {
|
|||
|
||||
// pre-generate random test data
|
||||
TestData testData{INSTANCES};
|
||||
for (auto&[t,r] : testData)
|
||||
for (size_t i=0; i<INSTANCES; ++i)
|
||||
{
|
||||
const size_t SPREAD = 2*_raw(SPREAD_DEAD);
|
||||
const size_t MIN_DEAD = _raw(BASE_DEADLINE) - _raw(SPREAD_DEAD);
|
||||
|
||||
auto&[t,r] = testData[i];
|
||||
r = rand() % SPREAD;
|
||||
t = TimeValue(MIN_DEAD + r);
|
||||
t = TimeValue(i*STP + MIN_DEAD + r);
|
||||
}
|
||||
|
||||
Activity dummy; // reserve memory for test subject index
|
||||
|
|
@ -458,15 +474,16 @@ namespace test {
|
|||
size_t check = feedActivity.data_.feed.one;
|
||||
if (i % CLEAN_UP == 0)
|
||||
blockFlow.discardBefore (Time{TimeValue{i*STP}});
|
||||
++i;
|
||||
return check;
|
||||
};
|
||||
|
||||
sum3 = runTest (allocate, invoke);
|
||||
//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).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())
|
||||
};
|
||||
|
||||
|
|
@ -479,7 +496,8 @@ SHOW_EXPR(sum1);
|
|||
auto time_heapAlloc = benchmark(heapAlloc);
|
||||
SHOW_EXPR(time_heapAlloc)
|
||||
SHOW_EXPR(sum2);
|
||||
|
||||
|
||||
cout<<"\n\n■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□"<<endl;
|
||||
// INVOKE Setup-3
|
||||
auto time_blockFlow = benchmark(blockFlow);
|
||||
SHOW_EXPR(time_blockFlow)
|
||||
|
|
|
|||
|
|
@ -80396,7 +80396,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1689640146728" ID="ID_1549819920" MODIFIED="1689640170406" TEXT="Hinweise auf Blocksteuerung">
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1689640146728" ID="ID_1549819920" MODIFIED="1689684857285" TEXT="Probleme in der Blocksteuerung">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689640172272" ID="ID_581706192" MODIFIED="1689640208346" TEXT="Epoch-Step ist zuletzt 0">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
|
|
@ -80422,11 +80422,14 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689642371947" ID="ID_1406026816" MODIFIED="1689642405098" TEXT="insgesamt: möglicherweise ist das Konzept so nicht tragfähig">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1689642408734" ID="ID_1850569145" MODIFIED="1689642449156" TEXT="schon die Parametrisierung für den Test zeit einen viel zu kleinen Hebel"/>
|
||||
<node CREATED="1689642450264" ID="ID_1125214093" MODIFIED="1689642537977" TEXT="es ist klar: die beiden anderen Varianten sind nicht skalierbar">
|
||||
<node CREATED="1689642408734" ID="ID_1850569145" MODIFIED="1689642449156" TEXT="schon die Parametrisierung für den Test zeigt einen viel zu kleinen Hebel"/>
|
||||
<node CREATED="1689642450264" ID="ID_1125214093" MODIFIED="1689684699740" TEXT="allerdings ist klar: die beiden anderen Varianten sind nicht skalierbar">
|
||||
<node CREATED="1689642540378" ID="ID_1216826442" MODIFIED="1689642547999" TEXT="wir brauchen Dauerbetrieb"/>
|
||||
<node CREATED="1689642549891" ID="ID_960993571" MODIFIED="1689642558846" TEXT="Heap fragmentiert im Lauf der Zeit"/>
|
||||
<node CREATED="1689642582295" ID="ID_1154028289" MODIFIED="1689642651289" TEXT="wir brauchen sichere Erkennung freiggebarer Records"/>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1689642582295" ID="ID_1154028289" MODIFIED="1689684715594" TEXT="wir brauchen sichere Erkennung freiggebarer Records">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1689642751072" ID="ID_1608372510" MODIFIED="1689642786257">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
|
|
@ -80449,6 +80452,170 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1689684827456" ID="ID_1251456862" MODIFIED="1689684834449" TEXT="Untersuchung">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1689688605214" ID="ID_1479889724" MODIFIED="1689688613864" TEXT="Instrumentierung per Dump-Message">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node CREATED="1689688665057" ID="ID_191179239" MODIFIED="1689689020435">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
die erste belegte Epoche ist <i>exterm viel zu lang</i> ⟹ sehr <b>viele Overflows</b> zu Beginn
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1689688809029" ID="ID_197704228" MODIFIED="1689689024928" TEXT="die Overflow-Skalierung ist zu aggresiv">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1689688867029" ID="ID_370596400" MODIFIED="1689688892793">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
sie wird <i>für jedes Element </i>aktiviert!
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1689688913178" ID="ID_750544240" MODIFIED="1689688932088" TEXT="...ist aber konzeptionell auf Block-Ebene gedacht"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689688962913" ID="ID_1246079128" MODIFIED="1689688986512" TEXT="abschwächen auf Wurzel-Blockgröße">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689688991172" ID="ID_1205551912" MODIFIED="1689689193276" TEXT="es fehlt eine Mindestgrenze">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1689689101381" ID="ID_1069284022" MODIFIED="1689689142544" TEXT="damit läuft der Wert irgendwann in die Auflösungsgrenze">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
</node>
|
||||
<node CREATED="1689689121643" ID="ID_1139921351" MODIFIED="1689689145605" TEXT="zumal sehr viel häufiger / aggressiver skaliert wird (als intendiert)">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689689147911" ID="ID_325871925" MODIFIED="1689689193276" TEXT="die generierten Deadlines vom Test sind falsch">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1689689201144" ID="ID_1519775847" MODIFIED="1689689215381" TEXT="damit kommt das Epochen-System nicht vom Fleck"/>
|
||||
<node CREATED="1689689279445" ID="ID_1830236844" MODIFIED="1689689306124">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
vermutlich findet deshalb auch <b>überhaupt kein clean-up</b> statt
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1689689307341" ID="ID_1812665874" MODIFIED="1689689327476" TEXT="weshalb dann auch die division-by-zero gar nicht getriggert wird"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1689692582553" ID="ID_291005420" MODIFIED="1689692625099" TEXT="die Bremse im MovingAverage ist kontraproduktiv">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1689692626589" ID="ID_629425172" MODIFIED="1689692652763">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
bisher werden stark unterfüllte Epochen als <i>neutral </i>eingebucht
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1689692673756" ID="ID_397401907" MODIFIED="1689692700628" TEXT="das führt dazu, daß sich eine sehr kleine Epochen-Länge „festsetzt“"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689692715478" ID="ID_1884642604" MODIFIED="1689692741660" TEXT="stattdessen genau mit dem Gegenstück zur Overflow-Skalierung hochfahren">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689695509771" ID="ID_1680463612" MODIFIED="1689695577443" TEXT="besser noch: linear interpolieren zwischen diesem und dem tatsächlichen Signal">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Grundsätzlich ist der Ansatz schon richtig: wenn wir uns weit vom Regelfokus entfernen, dann die Rückstellkraft stärker dämpfen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689706630682" ID="ID_1207312075" MODIFIED="1689706639238" TEXT="Beobachtungen-2">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node COLOR="#338800" CREATED="1689706647127" ID="ID_122402325" MODIFIED="1689706656742" TEXT="nach Beheben der Fehler greift die Regelung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node CREATED="1689706729972" ID="ID_109351292" MODIFIED="1689707548071" TEXT="der Moving-Average muß vor allem die Verzögerung zum Meßpunkt abfangen">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1689706842221" ID="ID_46527499" MODIFIED="1689706924295">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
muß die Dämpfung für extreme Zustände so einstellen,
|
||||
</p>
|
||||
<p>
|
||||
daß sie etwa eine Größenordnung langsamer greift,
|
||||
</p>
|
||||
<p>
|
||||
als die charakteristische Regelzeit (≙ Verzögerung)
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1689707069750" ID="ID_1676110559" MODIFIED="1689707543214" TEXT="die Overflow-Korrektur sollte im Schnitt etwas stärker wirken">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1689707102105" ID="ID_1477862319" MODIFIED="1689707113227" TEXT="gilt nur im stabilen Zustand"/>
|
||||
<node CREATED="1689707125990" ID="ID_86627735" MODIFIED="1689707145143" TEXT="weil dort Overflows nur punktweise auftreten"/>
|
||||
<node CREATED="1689707145850" ID="ID_218220838" MODIFIED="1689707160501" TEXT="und Overflows generell die Performance beeinträchtigen"/>
|
||||
<node CREATED="1689707223025" ID="ID_18144633" MODIFIED="1689707248873" TEXT="die zusätziche Dämpfung durch den MovingAverage hat aber bereits genau diesen Effekt"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1689707264498" ID="ID_36545794" MODIFIED="1689707536374">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
<b>Feinabstimmung</b>: den Testfall rund laufen lasssen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1689707302230" ID="ID_1843953493" MODIFIED="1689707397166" TEXT="Overflow-Kompensation vs. Vorlaufzeit für MA">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Die Korrektur bei Overflows darf nur so stark sein, daß die Blöcke während der Vorlaufzeit etwa halbiert werden, aber nicht so stark, daß wir gegen das Limit laufen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1689707398181" ID="ID_536362200" MODIFIED="1689707492490" TEXT="bei Einsetzen der Regelung sind halb-volle Blöcke optimal">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<ul>
|
||||
<li>
|
||||
wenn die Blöcke noch leer sind, kommt es zu Regelschwingungen und es dauert doppelt so lange bis zum stationären Zustand
|
||||
</li>
|
||||
<li>
|
||||
weitgehend volle Blöcke dagegen verlängern die Überlastungsphase unnötig
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1689707495357" ID="ID_1663505203" MODIFIED="1689707522915" TEXT="⟹ Default-Werte sollten initial ehr auf Unterfüllung zielen"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1688559356693" HGAP="9" ID="ID_1823374976" MODIFIED="1688559375797" TEXT="Grenzfälle" VSHIFT="7">
|
||||
|
|
|
|||
Loading…
Reference in a new issue