BufferProvider: look through further aspects of the API
* write down some first considerations regarding requirements of the actual production-strength implementation of buffer management * consider relevance of the part of the API that was retained * write a new series of test cases to cover handling of embedded objects, using the test support for tracking object creation
This commit is contained in:
parent
8a8f98ceb0
commit
6c880c5d10
3 changed files with 628 additions and 92 deletions
|
|
@ -161,7 +161,7 @@ namespace test{
|
|||
}
|
||||
|
||||
Tracker()
|
||||
: val{rani (1000)}
|
||||
: val{1 + rani (999)}
|
||||
{
|
||||
log.call (this,"ctor");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,15 +20,14 @@
|
|||
#include "lib/test/run.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
#include "lib/test/tracking-dummy.hpp"
|
||||
#include "lib/util-foreach.hpp"
|
||||
#include "lib/iter-zip.hpp"
|
||||
#include "steam/engine/testframe.hpp"
|
||||
#include "steam/engine/test-rand-ontology.hpp"
|
||||
#include "steam/engine/diagnostic-buffer-provider.hpp"
|
||||
#include "lib/test/diagnostic-output.hpp"////////////////////TODO
|
||||
#include "steam/engine/test-rand-ontology.hpp"
|
||||
#include "steam/engine/testframe.hpp"
|
||||
#include "lib/iter-zip.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
using util::isSameObject;
|
||||
using util::for_each;
|
||||
using lib::HashVal;
|
||||
using lib::zip;
|
||||
|
||||
|
|
@ -37,16 +36,12 @@ namespace steam {
|
|||
namespace engine{
|
||||
namespace test {
|
||||
|
||||
using lib::test::Dummy;
|
||||
|
||||
using steam::engine::BuffHandle;
|
||||
using LERR_(LIFECYCLE);
|
||||
using LERR_(LOGIC);
|
||||
|
||||
|
||||
namespace { // Test fixture
|
||||
|
||||
const uint TEST_ELMS = 20;
|
||||
const uint TEST_ELMS = 50;
|
||||
|
||||
|
||||
HashVal
|
||||
|
|
@ -80,10 +75,11 @@ namespace test {
|
|||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
seedRand();
|
||||
|
||||
verifySimpleUsage();
|
||||
verifyRenderingUse();
|
||||
// verifyObjectAttachment();
|
||||
// verifyObjectAttachmentFailure(); //////////////////////////OOO need a completely new test case to cover behaviour of failed ctor calls
|
||||
verifyObjectEmbedding();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -116,7 +112,39 @@ namespace test {
|
|||
}
|
||||
|
||||
|
||||
/** @test demonstrate the full sequence of invocations during rendering
|
||||
/** @test demonstrate the full sequence of invocations encountered during rendering:
|
||||
* - as a first step, _buffer types_ are declared (usually by the Builder)
|
||||
* - before start of computations, required amount of buffers is _announced_
|
||||
* - actual buffers are then claimed from within the ongoing computation
|
||||
* - buffer handles can be passed on and re-assigned
|
||||
* - buffers with computed results are _marked emitted_
|
||||
* - each step not only creates new buffers, but also _releases_ old ones.
|
||||
* @remark while the control structure in this test is represented by a simple `for`-loop,
|
||||
* instead of the complicated recursive call-down found in the actual Render Engine,
|
||||
* the actual computations use a test-scheme with chained hash values, which allows
|
||||
* to prove that all computations happened exactly in the planned order. This
|
||||
* technique was developed for [verifying render nodes](\ref node-devel-test.cpp)
|
||||
* and relies on TestFrame objects representing a buffer filled with random yet
|
||||
* deterministic data. Each step in this [dummy computation](\ref do-some_computation)
|
||||
* - uses a source data buffer
|
||||
* - reads the _checksum_ of this source buffer
|
||||
* - uses this checksum as a _parameter_ for a »filtering operation«
|
||||
* - this filter or manipulation operation chains each source value with the parameter
|
||||
* - the resulting result values are then extracted from TestFrame and copied into
|
||||
* another data buffer (thereby widening from 8bit data to 64bit data)
|
||||
* - furthermore, each step computes the checksum of the result buffer
|
||||
* - and stores this checksum into a mark buffer
|
||||
* - note that the result buffer is passed on as source buffer to the next step.
|
||||
* Once this computation scheme is carried out, the checksum from the last result buffer
|
||||
* is retrieved. All buffers are already marked as discarded at that point, yet due to
|
||||
* the DiagnosticBufferProvider used for the test, the actual memory blocks were not
|
||||
* really deleted yet, and their contents can be inspected and verified after the fact.
|
||||
* This verification reinvokes the computation steps to validate the captured checksums,
|
||||
* which ensures that, overall
|
||||
* - buffers are not mixed up
|
||||
* - the buffer identities are maintained in the correct way
|
||||
* - data in buffers is not corrupted or re-used in uncontrolled ways
|
||||
* - all protocol steps (locking, emitting, releasing) happen in the expected order
|
||||
*/
|
||||
void
|
||||
verifyRenderingUse()
|
||||
|
|
@ -177,6 +205,7 @@ namespace test {
|
|||
workBuff.release(); // note: not every buffer need be emitted.
|
||||
CHECK (!workBuff);
|
||||
|
||||
// Computation complete now — verify buffer management....
|
||||
auto inspect = watch(provider);
|
||||
CHECK (inspect.created.cnt() == 3*TEST_ELMS + 1);
|
||||
CHECK (inspect.was_used (workBuff));
|
||||
|
|
@ -184,9 +213,9 @@ namespace test {
|
|||
CHECK (not inspect.was_emitted (workBuff));
|
||||
CHECK (inspect.all_buffers_released());
|
||||
|
||||
// now peek into buffer memory
|
||||
// to prove that that the complete computation chain
|
||||
// was in fact performed, and was using the memory as intended
|
||||
// peek into buffer memory...
|
||||
// to prove that that the complete computation chain was
|
||||
// in fact performed, and was using the memory as intended
|
||||
uint last = inspect.released.cnt() - 1;
|
||||
diagn::Block lastWork = inspect.released[last];
|
||||
diagn::Block lastMark = inspect.released[last-1];
|
||||
|
|
@ -223,83 +252,202 @@ namespace test {
|
|||
}
|
||||
|
||||
|
||||
#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
|
||||
|
||||
/** @test automatic embedding of structures into a buffer
|
||||
* - contents of a raw buffer are never touched by the BufferProvider
|
||||
* - yet it is possible to define a _buffer type_ to _emplace_
|
||||
* some arbitrary type into the buffer; such an embedded instance
|
||||
* is then managed alongside with the buffer state transitions
|
||||
* - we can even define custom handler functions to prepare
|
||||
* arbitrary structures within the buffer — or engage into
|
||||
* whatever kind of havoc we like (you have been warned)
|
||||
* - when invoking an _emergency clean-up_, destructor functors
|
||||
* can optionally invoked, or skipped (the latter is the default)
|
||||
* @remark this test uses the [tracking test-dummy](\ref lib::test::Tracker),
|
||||
* which records each ctor and dtor call into an lib::test::EventLog.
|
||||
* This allows us to play through several scenarios and verify
|
||||
* that objects are created and (not) destroyed, all as expected.
|
||||
* @see test-tracking-test.cpp
|
||||
* @see event-log-test.cpp
|
||||
*/
|
||||
void
|
||||
verifyObjectAttachment()
|
||||
verifyObjectEmbedding()
|
||||
{
|
||||
DiagnosticBufferProvider provider;
|
||||
BuffDescr type_A = provider.getDescriptorFor(sizeof(TestFrame));
|
||||
BuffDescr type_B = provider.getDescriptorFor(sizeof(int));
|
||||
BuffDescr type_C = provider.getDescriptor<int>();
|
||||
|
||||
BuffHandle handle_A = provider.lockBuffer(type_A);
|
||||
BuffHandle handle_B = provider.lockBuffer(type_B);
|
||||
BuffHandle handle_C = provider.lockBuffer(type_C);
|
||||
using lib::test::Tracker;
|
||||
auto& log = Tracker::log;
|
||||
log.clear();
|
||||
|
||||
CHECK (handle_A);
|
||||
CHECK (handle_B);
|
||||
CHECK (handle_C);
|
||||
BuffDescr rawBuff = provider.getDescriptorFor(sizeof(Tracker));
|
||||
BuffDescr objBuff = provider.getDescriptor<Tracker>();
|
||||
CHECK (rawBuff.buffSize() == objBuff.buffSize());
|
||||
|
||||
CHECK (sizeof(TestFrame) == handle_A.size());
|
||||
CHECK (sizeof( int ) == handle_B.size());
|
||||
CHECK (sizeof( int ) == handle_C.size());
|
||||
|
||||
TestFrame& embeddedFrame = handle_A.create<TestFrame>();
|
||||
CHECK (isSameObject (*handle_A, embeddedFrame));
|
||||
CHECK (embeddedFrame.isAlive());
|
||||
CHECK (embeddedFrame.isSane());
|
||||
{ // Case-1 : Raw buffer does not create any embedded instance
|
||||
log.event("Case-1");
|
||||
BuffHandle handle = provider.lockBuffer(rawBuff);
|
||||
CHECK (handle.size() >= sizeof(Tracker));
|
||||
CHECK (handle.isAllotted());
|
||||
// But no object has been created yet....
|
||||
CHECK (log.ensureNot("ctor")
|
||||
.afterEvent("Case-1"));
|
||||
|
||||
VERIFY_ERROR (LOGIC, handle_B.create<TestFrame>()); // too small to hold a TestFrame
|
||||
VERIFY_ERROR (LIFECYCLE, handle_C.create<int>()); // has already an attached TypeHandler (creating an int)
|
||||
// explicitly placement-construct object into the buffer
|
||||
new(handle.rawStorage()) Tracker{55};
|
||||
Tracker& emplaced = handle.accessAs<Tracker>();
|
||||
CHECK (emplaced.val == 55);
|
||||
CHECK (log.verify("Case-1")
|
||||
.beforeCall("ctor").on(&emplaced).arg(55));
|
||||
|
||||
handle_A.release();
|
||||
handle_B.release();
|
||||
handle_C.release();
|
||||
handle.release();
|
||||
CHECK (not handle.isAllotted());
|
||||
|
||||
CHECK (embeddedFrame.isDead());
|
||||
CHECK (embeddedFrame.isSane());
|
||||
// Buffer is disposed now,
|
||||
// but emplaced object was not destroyed automatically
|
||||
CHECK (log.ensureNot("dtor")
|
||||
.afterCall("ctor").arg(55));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
verifyObjectAttachmentFailure()
|
||||
{
|
||||
DiagnosticBufferProvider provider;
|
||||
BuffDescr type_D = provider.getDescriptorFor(sizeof(Dummy));
|
||||
{ // Case-2 : Buffer with object instance automatically emplaced
|
||||
log.event("Case-2");
|
||||
CHECK (log.ensureNot("ctor").after("Case-2"));
|
||||
|
||||
Dummy::checksum() = 0;
|
||||
BuffHandle handle_D = provider.lockBuffer(type_D);
|
||||
CHECK (0 == Dummy::checksum()); // nothing created thus far
|
||||
// allot buffer and emplace Tracker instance automatically
|
||||
BuffHandle handle = provider.lockBuffer(objBuff);
|
||||
Tracker& emplaced = handle.accessAs<Tracker>();
|
||||
CHECK (log.verify("Case-2")
|
||||
.beforeCall("ctor").on(&emplaced).arg());
|
||||
|
||||
handle_D.create<Dummy>();
|
||||
CHECK (0 < Dummy::checksum());
|
||||
int randomVal{emplaced.val};
|
||||
CHECK (0 < randomVal and randomVal < 1000);
|
||||
// NOTE: buffer access is actually an unchecked force-cast!
|
||||
int something = handle.accessAs<int>();
|
||||
CHECK (something == randomVal);
|
||||
CHECK (std::is_standard_layout_v<Tracker>);
|
||||
|
||||
handle_D.release();
|
||||
CHECK (0 == Dummy::checksum());
|
||||
CHECK (log.ensureNot("dtor").afterEvent("Case-2"));
|
||||
handle.emit();
|
||||
CHECK (not handle); // no longer accessible
|
||||
CHECK (handle.isAllotted()); // while buffer contents are still alive
|
||||
CHECK (log.ensureNot("dtor").afterEvent("Case-2"));
|
||||
|
||||
BuffHandle handle_DD = provider.lockBuffer(type_D);
|
||||
|
||||
CHECK (0 == Dummy::checksum());
|
||||
Dummy::activateCtorFailure();
|
||||
|
||||
CHECK (handle_DD.isValid());
|
||||
try
|
||||
{
|
||||
handle_DD.create<Dummy>();
|
||||
NOTREACHED ("Dummy ctor should fail");
|
||||
}
|
||||
catch (int val)
|
||||
{
|
||||
CHECK (!handle_DD.isValid());
|
||||
|
||||
CHECK (0 < Dummy::checksum());
|
||||
CHECK (val == Dummy::checksum());
|
||||
// Emplaced object is destroyed when releasing buffer
|
||||
handle.release();
|
||||
CHECK (not handle.isAllotted());
|
||||
CHECK (log.verify("Case-2")
|
||||
.beforeCall("ctor").arg()
|
||||
.beforeCall("dtor").arg(randomVal));
|
||||
}
|
||||
|
||||
VERIFY_ERROR (LIFECYCLE, handle_DD.accessAs<Dummy>() );
|
||||
VERIFY_ERROR (LIFECYCLE, handle_DD.create<Dummy>() );
|
||||
|
||||
{ // Case-3 : Emergency clean-up
|
||||
log.event("Case-3");
|
||||
|
||||
BuffHandle buf1 = provider.lockBuffer(objBuff);
|
||||
BuffHandle buf2 = provider.lockBuffer(objBuff);
|
||||
|
||||
auto& o1 = buf1.accessAs<Tracker>();
|
||||
auto& o2 = buf2.accessAs<Tracker>();
|
||||
CHECK (log.verify("Case-3")
|
||||
.beforeCall("ctor").on(&o1).arg()
|
||||
.beforeCall("ctor").on(&o2).arg());
|
||||
|
||||
int i1 = o1.val;
|
||||
CHECK (i1 > 0);
|
||||
o2.val = -1; // so we can tell them apart
|
||||
|
||||
// Emergency clean-up can optionally invoke the dtor
|
||||
CHECK (buf1.isAllotted());
|
||||
CHECK (buf2.isAllotted());
|
||||
provider.emergencyCleanup(buf1, true); // invoke dtor
|
||||
buf2.emergencyCleanup(); // don't invoke dtor
|
||||
CHECK (not buf1.isAllotted());
|
||||
CHECK (not buf2.isAllotted());
|
||||
|
||||
// only dtor for o1 was invoked
|
||||
CHECK (log.verify("Case-3")
|
||||
.beforeCall("ctor")
|
||||
.beforeCall("dtor").arg(i1));
|
||||
// while buf2 was discarded without invoking dtor of o2
|
||||
CHECK (log.ensureNot("Case-3")
|
||||
.beforeCall("ctor")
|
||||
.beforeCall("dtor").arg(-1));
|
||||
}
|
||||
|
||||
|
||||
{ // Case-4 : explicitly given ctor/dtor-λ
|
||||
log.event("Case-4");
|
||||
using Arr = std::array<Tracker,2>;
|
||||
TypeHandler treat{[](void* buff){ // invoked on each buffer created from that type
|
||||
Tracker::log.event("create two...");
|
||||
new(buff) Arr{};
|
||||
}
|
||||
,[](void* buff){ // invoked whenever releasing a buffer of that type
|
||||
static_cast<Arr*>(buff)->~Arr();
|
||||
Tracker::log.event("both destroyed");
|
||||
}
|
||||
};
|
||||
|
||||
BuffDescr special = provider.getDescriptorFor(sizeof(Arr), treat);
|
||||
CHECK (special.isValid());
|
||||
CHECK (special.buffSize() == sizeof(Arr));
|
||||
CHECK (HashVal(special) != HashVal(rawBuff));
|
||||
CHECK (HashVal(special) != HashVal(objBuff));
|
||||
|
||||
// nothing happened yet...
|
||||
CHECK (log.ensureNot("create two..."));
|
||||
|
||||
// allocate a buffer as »instance« of this buffer type...
|
||||
BuffHandle buff = special.lockBuffer();
|
||||
CHECK (buff.isValid());
|
||||
CHECK (log.verify("Case-4")
|
||||
.beforeEvent("create two...")
|
||||
.beforeCall("ctor").arg()
|
||||
.beforeCall("ctor").arg());
|
||||
// so buffer was called and two objects created, but not destroyed yet
|
||||
CHECK (log.ensureNot("Case-4").before("ctor").before("dtor"));
|
||||
|
||||
// can use buffer with embedded structure now...
|
||||
Arr& inlay = buff.accessAs<Arr>();
|
||||
CHECK (0 < inlay[0].val);
|
||||
CHECK (0 < inlay[1].val);
|
||||
int i1 = inlay[0].val;
|
||||
inlay[1].val = -55; // so we can identify the dtor call in the log
|
||||
|
||||
// complete buffer usage cycle...
|
||||
buff.emit();
|
||||
CHECK (not buff);
|
||||
CHECK (buff.isAllotted());
|
||||
// objects are still alive....
|
||||
CHECK (log.ensureNot("Case-4").before("both destroyed"));
|
||||
//
|
||||
buff.release();
|
||||
CHECK (not buff.isAllotted());
|
||||
CHECK (log.verify("Case-4")
|
||||
.beforeEvent("create two...")
|
||||
.before("ctor")
|
||||
.before("ctor")
|
||||
.before("dtor")
|
||||
.before("dtor")
|
||||
.beforeEvent("both destroyed"));
|
||||
// Order of individual ctor/dtor calls is implementation defined,
|
||||
// yet the overall sequence is guaranteed...
|
||||
CHECK (log.verify("Case-4")
|
||||
.before("ctor")
|
||||
.before("dtor").arg(i1)
|
||||
.beforeEvent("both destroyed"));
|
||||
CHECK (log.verify("Case-4")
|
||||
.before("ctor")
|
||||
.before("dtor").arg(-55)
|
||||
.beforeEvent("both destroyed"));
|
||||
}
|
||||
|
||||
cout << "____Tracker-Log_______________\n"
|
||||
<< util::join(Tracker::log, "\n")
|
||||
<< "\n───╼━━━━━━━━━━━╾──────────────"<<endl;
|
||||
}
|
||||
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -112294,6 +112294,100 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<edge COLOR="#61fe5b" STYLE="bezier" WIDTH="thin"/>
|
||||
<font NAME="SansSerif" SIZE="15"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1771436783713" ID="ID_193788147" MODIFIED="1771458129212" TEXT="Object-Attachment: Test neu schreiben">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1771436808099" ID="ID_1875105522" MODIFIED="1771436817968" TEXT="die bestehende Logik wurde aufgegeben"/>
|
||||
<node CREATED="1771436819011" ID="ID_1216779511" MODIFIED="1771436846683" TEXT="jedoch weiterhin zu belegen...">
|
||||
<node CREATED="1771436848184" ID="ID_71721349" MODIFIED="1771436869562" TEXT="daß Konstruktoren / Destruktoren aufgerufen werden (wenn erwartet)"/>
|
||||
<node CREATED="1771436873021" ID="ID_282076766" MODIFIED="1771436880834" TEXT="wie Fehler behandelt werden">
|
||||
<node COLOR="#5b280f" CREATED="1771436928263" ID="ID_446121201" MODIFIED="1771441543550" TEXT="Exception aus der Allokation">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1771441546352" ID="ID_571861145" MODIFIED="1771441567658" TEXT="das diskutiere ich weg">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="11"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node CREATED="1771441578989" ID="ID_1186695503" MODIFIED="1771441590495" TEXT="ein solcher Test ist...">
|
||||
<node CREATED="1771441592519" ID="ID_206617730" MODIFIED="1771441611094" TEXT="schwer zu realisieren ohne Mock-Instrumentierung"/>
|
||||
<node CREATED="1771441613485" ID="ID_972749888" MODIFIED="1771441636565" TEXT="läuft darauf hinaus, die Implementierung im Test aufzudoppeln"/>
|
||||
<node CREATED="1771441653055" ID="ID_333922655" MODIFIED="1771441760759" TEXT="testet nicht aktiv implementiertes Verhalten, sondern dokumentiert nur die Struktur">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Das entscheidende Kriterium nämlich, EX_STRONG, wird in der Regel nicht aktiv hergestellt, sondern dadurch, daß die Schritte der Implementierung logisch präzise angeordnet werden. Überdies ist so etwas schwer empirisch zu belegen, dann man müßte den Beweis führen, daß etwas Mögliches <i>nicht passiert</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1771436936743" ID="ID_1363737657" MODIFIED="1771436946781" TEXT="Emergency-Abort">
|
||||
<node CREATED="1771436948096" ID="ID_449913080" MODIFIED="1771436951446" TEXT="ohne Dtor"/>
|
||||
<node CREATED="1771436952498" ID="ID_131359835" MODIFIED="1771436955830" TEXT="mit Dtor"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1771442679582" ID="ID_1646361815" MODIFIED="1771442683402" TEXT="Test-Framework">
|
||||
<node CREATED="1771442684317" ID="ID_1793773266" MODIFIED="1771442728428" TEXT="verwende den Tracker (Dummy-Objekt mit eingebautem EventLog)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
siehe test-tracking-test.cpp
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1771445216811" ID="ID_1830844578" MODIFIED="1771445232082" TEXT="führe mehrere abgeschlossene sub-Tests aus"/>
|
||||
<node CREATED="1771445233144" ID="ID_1380577086" MODIFIED="1771445240705" TEXT="prüfe jeweils unmittelbar das Log"/>
|
||||
</node>
|
||||
<node CREATED="1771445249561" ID="ID_770084282" MODIFIED="1771445253530" TEXT="Test-Inhalte">
|
||||
<node CREATED="1771445255165" ID="ID_1398246748" MODIFIED="1771447709003" TEXT="Typen / Descriptoren einrichten">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node COLOR="#435e98" CREATED="1771445266196" ID="ID_44204253" MODIFIED="1771447715307" TEXT="für einen roh-Buffer (nur Größe festgelegt)"/>
|
||||
<node COLOR="#435e98" CREATED="1771445279571" ID="ID_560437674" MODIFIED="1771447715307" TEXT="für einen Buffer mit automatisch erzeugtem Objekt"/>
|
||||
<node CREATED="1771445303551" ID="ID_143464891" MODIFIED="1771445326791" TEXT="für einen Buffer mit explizit angegebener Konstruktor / Destruktor-Funktion"/>
|
||||
<node CREATED="1771445331287" ID="ID_467418427" MODIFIED="1771445341928" TEXT="Type-Refinement">
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1771445344331" HGAP="30" ID="ID_1813249595" MODIFIED="1771445458623" TEXT="hoppla — dieses Feature wurde nicht auf das BufferProvider-Interface herausgeführt" VSHIFT="3">
|
||||
<arrowlink COLOR="#b43f57" DESTINATION="ID_1703778866" ENDARROW="Default" ENDINCLINATION="-1037;-26;" ID="Arrow_ID_1563102453" STARTARROW="None" STARTINCLINATION="-107;797;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1771445469499" ID="ID_1217260767" MODIFIED="1771447698493" TEXT="Case-1">
|
||||
<node CREATED="1771445475727" ID="ID_1387681407" MODIFIED="1771445492202" TEXT="roh-Buffer belegen ⟹ kein ctor aufgerufen"/>
|
||||
<node CREATED="1771445494472" ID="ID_1296494011" MODIFIED="1771445506683" TEXT="Objekt erzeugen ⟹ ctor"/>
|
||||
<node CREATED="1771445515166" ID="ID_447921413" MODIFIED="1771445531675" TEXT="roh-Buffer schließen ⟹ kein dtor"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1771445534280" ID="ID_858270212" MODIFIED="1771449157190" TEXT="Case-2">
|
||||
<node CREATED="1771445538631" ID="ID_1776783699" MODIFIED="1771445547081" TEXT="Buffer mit Objekt"/>
|
||||
<node CREATED="1771445548213" ID="ID_1664695576" MODIFIED="1771445555881" TEXT="ctor und dtor automatisch aufgerufen"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1771445561658" ID="ID_722870223" MODIFIED="1771454491546" TEXT="Case-3">
|
||||
<node CREATED="1771445568235" ID="ID_527191809" MODIFIED="1771445576172" TEXT="Emergency Clean-up"/>
|
||||
<node CREATED="1771445577130" ID="ID_428883319" MODIFIED="1771445584948" TEXT="Buffer mit Objekt ⟹ ctor aufgerufen"/>
|
||||
<node CREATED="1771445586568" ID="ID_241080784" MODIFIED="1771445596299" TEXT="clean-up ohne dtor ⟹ kein dtor"/>
|
||||
<node CREATED="1771445603598" ID="ID_965160552" MODIFIED="1771445612252" TEXT="weiterer Buffer + clean-up mit dtor"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1771445614229" ID="ID_33658292" MODIFIED="1771456881976" TEXT="Case-4">
|
||||
<node CREATED="1771445620940" ID="ID_1189233412" MODIFIED="1771445648006" TEXT="ctor/dtor-λ"/>
|
||||
<node CREATED="1771445682427" ID="ID_1710187908" MODIFIED="1771445718602" TEXT="pflanze mehrere Objekte + Logging"/>
|
||||
</node>
|
||||
<node CREATED="1771445726309" ID="ID_1153792783" MODIFIED="1771446278063" TEXT="Case-5">
|
||||
<node CREATED="1771445734608" ID="ID_1237619577" MODIFIED="1771445895319" TEXT="Refinement mit TypeHandler"/>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1771445942584" ID="ID_1549365674" MODIFIED="1771445985771" TEXT="zeigt daß »Basis« hier nur eine Buffer-Größe ist">
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -113164,8 +113258,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<b>Solange ich mich also nicht aus dem zugrundeliegenden gedanklichen Schema löse</b><i>, werde ich hier nichts Relevantes in Bewegung bringen können</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<arrowlink COLOR="#65343f" DESTINATION="ID_560454050" ENDARROW="Default" ENDINCLINATION="428;-25;" ID="Arrow_ID_267752890" STARTARROW="Default" STARTINCLINATION="-454;26;"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1771335394173" ID="ID_1566341422" MODIFIED="1771335450534" TEXT="offene Probleme:">
|
||||
|
|
@ -113231,6 +113324,10 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1771445380969" ID="ID_1703778866" MODIFIED="1771445458623" TEXT="Type-Refinement fehlt">
|
||||
<linktarget COLOR="#b43f57" DESTINATION="ID_1703778866" ENDARROW="Default" ENDINCLINATION="-1037;-26;" ID="Arrow_ID_1563102453" SOURCE="ID_1813249595" STARTARROW="None" STARTINCLINATION="-107;797;"/>
|
||||
<icon BUILTIN="broken-line"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1771195835031" ID="ID_465237496" MODIFIED="1771195857844" TEXT="BufferProvider ⟶ in Vault umziehen">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1771196048101" ID="ID_1022260808" MODIFIED="1771196056256" TEXT="TypeHandler kann auch dorting"/>
|
||||
|
|
@ -113359,8 +113456,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
Inhaltlich ist sie redundant, denn Zustandsübergänge werden auch in den Metadaten geprüft. Jedoch ist die ganze Struktur relativ offen, und es gibt sogar die »Unschärfe«, daß u.U der Pointer im Handle nicht auf NULL gesetzt wird (hab das gestern durchdacht und bin zu dem Schluß gekommen, daß sich das nur um den Preis eines kompletten Umbaues beheben ließe, wozu ich keinen Anlaß sehe)
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1771349832972" ID="ID_1073377063" MODIFIED="1771350841958" TEXT="also: auch dafür einen API-call-Pfad schaffen: isAllotted">
|
||||
|
|
@ -113775,8 +113871,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1771180748333" ID="ID_738177995" MODIFIED="1771180765150" TEXT="Fazit">
|
||||
<icon BUILTIN="flag-pink"/>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1771180751573" ID="ID_577853070" MODIFIED="1771180760077" TEXT="jetzt sieht die Sache schon klarer aus?">
|
||||
<icon BUILTIN="help"/>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1771180751573" ID="ID_577853070" MODIFIED="1771436757915" TEXT="insgesamt sieht die Sache schon klarer aus">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node CREATED="1771347540167" ID="ID_140501031" MODIFIED="1771348112880" TEXT="Habe BufferMetadata im Kern bestätigt — und (voererst) so belassen">
|
||||
<arrowlink COLOR="#634f7d" DESTINATION="ID_1922405500" ENDARROW="Default" ENDINCLINATION="259;1028;" ID="Arrow_ID_1669195374" STARTARROW="None" STARTINCLINATION="550;23;"/>
|
||||
|
|
@ -113902,8 +113999,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
derzeit <b><font size="4" color="#4a0cce">kann</font></b> ich gar nix mehr ändern
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="full-1"/>
|
||||
<node COLOR="#734398" CREATED="1771348310745" HGAP="24" ID="ID_842039957" MODIFIED="1771348334164" TEXT="(aus Mangel an Ideen)" VSHIFT="3">
|
||||
<font NAME="SansSerif" SIZE="9"/>
|
||||
|
|
@ -113940,10 +114036,99 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1771430377359" ID="ID_1030710505" MODIFIED="1771430406015" TEXT="Vorüberlegung: der Metadaten-Record wird auch vom Speichermanagement mitverwendet">
|
||||
<node CREATED="1771430412735" ID="ID_776105206" MODIFIED="1771431080667" TEXT="das beruht auf den Allokator-Grundmustern">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Das sind letztlich immer wieder Variationen von Kachel-Bitmap und Freelist; die Entscheidung ist geprägt vom Problem der Fragmentierung und dem Verschwenden von Speicher. Kacheln sind nur sinnvoll, wenn man sie nicht zusammenlegen muß; Pools brauchen ein gewisses Maß an »Statistik«, um zu funktionieren.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771431082049" ID="ID_619351703" MODIFIED="1771431230064" TEXT="der lokale Allokator sollte keine Speicher-Reorganisation machen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Erfahrungsgemäß braucht jede Art von Speicher-Reorganisation einen gewissen Hebel (und ist trotzdem stets sehr aufwendig). Daher sollte der lokale Allokator selber keinen roh-Speicher zuteilen, sondern nur ganze Blöcke herumschieben
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771431231469" ID="ID_136832370" MODIFIED="1771431303641" TEXT="Konsequenz: es braucht einen Deskriptor für den Speicherblock">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
....und dieser Deskriptor kann nicht im Block selber liegen, weil man ihn auch zur de-Allokation braucht, und er damit schlecht ist für das Alignment
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771431304936" ID="ID_479377966" MODIFIED="1771431483895" TEXT="Konsequenz: die Speicherverwaltung berührt nicht den Inhalt der Speicherblöcke">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Das hängt direkt mit dem CPU-Cache zusammen; Verwaltungs-Strukturen, die oft überarbeitet werden müssen, sollten kompakt liegen. Damit scheidet die klassische, einfache Freelist-Allokation aus, bei der man nur für freien Speicher <i>und direkt in diesem</i> eine Verwaltungsstruktur mitführt
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771431494416" ID="ID_1111538571" MODIFIED="1771431606417" TEXT="Daher bietet es sich an, alle Verwaltungsinformationen im Metadaten-Record zu konzentrieren">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Dadurch entsteht auch ein Hebel, so daß der Speicher für diese Metadaten-Records <i>selber</i> sehr gut auf das Kachel-Schema paßt
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1770828324568" ID="ID_1432290830" MODIFIED="1770828388601" TEXT="eine massiv parallele Implementierung möglich machen...">
|
||||
<arrowlink COLOR="#5e34c1" DESTINATION="ID_1154484414" ENDARROW="Default" ENDINCLINATION="101;-95;" ID="Arrow_ID_1475255011" STARTARROW="None" STARTINCLINATION="-185;9;"/>
|
||||
<icon BUILTIN="hourglass"/>
|
||||
<node CREATED="1771429539679" ID="ID_567714224" MODIFIED="1771429550678" TEXT="es zeichnet sich bereits das Aufrufmuster ab">
|
||||
<node CREATED="1771429557905" ID="ID_1006520101" MODIFIED="1771429572704" TEXT="die Deskriptoren werden vom Builder angelegt"/>
|
||||
<node CREATED="1771429923834" ID="ID_593032016" MODIFIED="1771429961826" TEXT="die Render-Steuerung könnte eine Kapazitätsplanung beitragen"/>
|
||||
<node CREATED="1771429966098" ID="ID_620022302" MODIFIED="1771429977216" TEXT="der Worker-Thread macht ein Announcement"/>
|
||||
<node CREATED="1771429985051" ID="ID_111399700" MODIFIED="1771430009180" TEXT="in der Node-Invocation werden Buffer sofort und latenzarm erwartet"/>
|
||||
</node>
|
||||
<node CREATED="1771430060637" ID="ID_49105544" MODIFIED="1771430067772" TEXT="das bedeutet vor allem: Verteilung">
|
||||
<node CREATED="1771430069544" ID="ID_300368607" MODIFIED="1771430077276" TEXT="es muß lokale Speicherpools geben"/>
|
||||
<node CREATED="1771430078196" ID="ID_579960502" MODIFIED="1771430115450">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
<u>besonders wichtig</u>: Metadaten <i>wandern über Threadgrenzen</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -113954,6 +114139,19 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1770828236428" ID="ID_669207960" MODIFIED="1770828249582" TEXT="thematisch gehört das in den Bereich »Engine«"/>
|
||||
<node CREATED="1770828250858" ID="ID_177391368" MODIFIED="1770828268013" TEXT="es muß aber im »Low-Level-Model« verankert sein"/>
|
||||
<node CREATED="1771430181729" ID="ID_277533122" MODIFIED="1771430334235" TEXT="das Thema umfaßt auch den Cache und die Ausgabepuffer">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Vor allem der Cache spielt eine erhebliche Rolle, denn er ist der größte Speicherverbraucher; der aktuelle Speicherbedarf muß in der Regel „dem Cache entrissen“ werden — und man verdrängt dabei entweder Inhalte in einen persistenten Cache, oder verliert sie ganz, und mit ihnen die aufgebrachten Renderzeit
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1770668981744" ID="ID_1636601070" MODIFIED="1770674840976" TEXT="Begriffsbildung ordnen">
|
||||
<arrowlink COLOR="#2322ad" DESTINATION="ID_1789434340" ENDARROW="Default" ENDINCLINATION="-1059;-157;" ID="Arrow_ID_1470173021" STARTARROW="None" STARTINCLINATION="-1095;118;"/>
|
||||
|
|
@ -133491,9 +133689,199 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1770828113207" ID="ID_1891198177" MODIFIED="1770828493362" TEXT="Konzeption der Fundemente">
|
||||
<linktarget COLOR="#f50221" DESTINATION="ID_1891198177" ENDARROW="Default" ENDINCLINATION="-700;-67;" ID="Arrow_ID_1175301159" SOURCE="ID_1154484414" STARTARROW="None" STARTINCLINATION="-1164;56;"/>
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1771431677354" ID="ID_315128547" MODIFIED="1771431687124" TEXT="Anforderungen und Nutzungsmuster">
|
||||
<node CREATED="1771431689328" ID="ID_723040917" MODIFIED="1771431694993" TEXT="Zielkonflikt">
|
||||
<node CREATED="1771431702526" ID="ID_1948404302" MODIFIED="1771431723686" TEXT="Speicher zum Rendern soll schnell und ohne Latenz bereitstehen"/>
|
||||
<node CREATED="1771431746896" ID="ID_175515697" MODIFIED="1771431770201" TEXT="Koordination und Verwaltung brauchen einen gewissen Leerlauf"/>
|
||||
<node CREATED="1771431771516" ID="ID_1334749334" MODIFIED="1771431799157" TEXT="aber der Cache möchte jeden verfügbaren Speicher langfristig belegen"/>
|
||||
</node>
|
||||
<node CREATED="1771431847408" ID="ID_1598041479" MODIFIED="1771431857379" TEXT="Latenz / Contention">
|
||||
<node CREATED="1771431922937" ID="ID_767766066" MODIFIED="1771431939583" TEXT="jede zentrale Koordinierung erzwingt Speicher-Synchronisation"/>
|
||||
<node CREATED="1771432287182" ID="ID_447894612" MODIFIED="1771432315056" TEXT="es muß daher thread-local einen kleinen Pool an Speicherblöcken geben"/>
|
||||
<node CREATED="1771432342656" ID="ID_1398418752" MODIFIED="1771432555752" TEXT="das »Anouncement« ermöglicht dem Worker eine Vorbereitung"/>
|
||||
<node CREATED="1771432559475" ID="ID_870538833" MODIFIED="1771433512945" TEXT="Aber hier tritt das »Box-packing«-Problem auf">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Beispiel: es gibt einen Engpaß in der gegebenen Berechnungs-Pipeline; dort werden 10 Blöcke à 10 MiB gebraucht, sowie 10 Blöcke à 1 KiB
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771433520019" ID="ID_1280671929" MODIFIED="1771433571059" TEXT="⟹ lokale Resourcen-Verwaltung notwendig">
|
||||
<node CREATED="1771433596297" ID="ID_530281677" MODIFIED="1771433606524" TEXT="fehlende Resourcen werden sofort bereitgestellt"/>
|
||||
<node CREATED="1771433582282" ID="ID_1769179919" MODIFIED="1771433595357" TEXT="muß Ansammeln überflüssiger Resourcen verhindern"/>
|
||||
<node CREATED="1771433622862" ID="ID_195557143" MODIFIED="1771433800961" TEXT="braucht Triggerschwellen und eine Buchhaltung">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
beispielsweise einen Bonus/Malus Zähler, der inkrementiert wird, wenn ein Block genutzt werden kann, und dekrementiert wird, wenn ein Block übersprungen werden muß, weil er zu klein ist. Es muß denn ein Aufräum-Zykuls getriggert werden, sobald der erste Block in der Liste eine hohe Bonus-Zahl bekommt; in dem Fall sollten alle Blöcke unterhalb eines gewissen Score aufgesammelt und an den zentralen Resourcen-Pool zurück gesandt werden
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1771433802134" ID="ID_372479446" MODIFIED="1771433890336" TEXT="es entsteht ein Messaging mit Speicher-Deskriptoren">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
dabei bekommt jeweils der Empfänger die alleinige Verfügungsgewalt über den am Deskriptor hängenden Block
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1771433907560" ID="ID_1739703978" MODIFIED="1771433914067" TEXT="Verschwendung vs. Pooling">
|
||||
<node CREATED="1771433916820" ID="ID_535507584" MODIFIED="1771433937367" TEXT="der Cache möchte Blöcke (mit Inhalt) möglichst langfristig horten"/>
|
||||
<node CREATED="1771433962120" ID="ID_584068900" MODIFIED="1771434081814" TEXT="die lokalen Verbraucher arbeiten aber nicht mit maßgeschneiderten Zuteilungen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Denn das wäre <i>vermutlich</i> zu aufwendig (vor allem da es den Code komplex macht).
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771434083664" ID="ID_548553172" MODIFIED="1771434555672" TEXT="man könnte Blöcke beim Caching kürzen — das interferiert aber mit dem Pooling">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Dabei gehe ich — vorgreifend — davon aus, daß wir eine Reihe von Pools mit gestaffelter Kachel-Größe verwenden, als Basis-Allokation. Da wir es allerdings mit ziemlich großen Blöcken zu tun haben, können wir uns da nur wenige Staffeln leisten, und auch das nur, wenn es eine dynamische Steuerung gibt.
|
||||
</p>
|
||||
<p>
|
||||
Wenn man nun aber in einer solchen Situation einzelne Cacheln für lange Zeit in den Cache abgibt, oder gar sogar im Cache dauerhaft die Größe reduziert und den Überschuß freigibt, führt das zu einer wachsenden Fragmentierung und behindert die besagte dynamische Steuerung.
|
||||
</p>
|
||||
<p>
|
||||
Letztlich lassen sich diese Probleme <b>ohne Empirie nicht adäquat behandeln</b>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771434566154" ID="ID_324686771" MODIFIED="1771434602865" TEXT="möglicherweise gibt es eine Garbage-Collection im Cache, als Hintergrundprozeß"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1771435558366" ID="ID_1118141898" MODIFIED="1771435564895" TEXT="Einbindung in das Gesamtsystem">
|
||||
<node CREATED="1771435578494" ID="ID_862962078" MODIFIED="1771435581997" TEXT="Aktoren">
|
||||
<node CREATED="1771435596799" ID="ID_613614143" MODIFIED="1771435605338" TEXT="konzeptionell ist das alles »Die Engine«"/>
|
||||
<node CREATED="1771435619446" ID="ID_1113025098" MODIFIED="1771435646493" TEXT="zunächst gibt es jedoch nur den Session-Thread und die Worker(+Scheduler)"/>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1771436265516" ID="ID_1393697571" MODIFIED="1771436282468" TEXT="Frage: wer macht die Verwaltungsarbeit?">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1771436284620" ID="ID_308615584" MODIFIED="1771436305104" TEXT="für das Buffer-Management">
|
||||
<node CREATED="1771436339660" ID="ID_1972323467" MODIFIED="1771436356334" TEXT="muß hier sofort beim Auftreten einer Anforderung reagieren"/>
|
||||
<node CREATED="1771436361243" ID="ID_539469544" MODIFIED="1771436382995" TEXT="es sind aber blockende Aufgaben involviert, wie Heap-Allokation"/>
|
||||
<node CREATED="1771436508078" ID="ID_244113719" MODIFIED="1771436550261">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
⟹ hierfür ist ein dedizierter <b>Service-Thread</b> die einfachste Lösung
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1771436306089" ID="ID_862253994" MODIFIED="1771436308932" TEXT="für den Cache">
|
||||
<node CREATED="1771436577677" ID="ID_636699078" MODIFIED="1771436613780" TEXT="grundsätzlich wäre das eine Hintergrund-Aktivität"/>
|
||||
<node CREATED="1771436614824" ID="ID_1860752437" MODIFIED="1771436629094" TEXT="die Frage ist: wie gut ist die Arbeit modularisierbar?"/>
|
||||
<node CREATED="1771436633557" ID="ID_327567555" MODIFIED="1771436712053" TEXT="relevant ist auch, wie lange das System ohne diese Verwaltungsarbeit überleben kann...">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
konkret, überstehen wir einen 10-Stunden-Render unter Druck (whatever it takes)?
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1770828120216" ID="ID_1112258994" MODIFIED="1770828480214" TEXT="vorläufige Implementierung">
|
||||
<icon BUILTIN="hourglass"/>
|
||||
<node CREATED="1771434625350" ID="ID_87043838" MODIFIED="1771434634233" TEXT="vorgreifende Vereinfachungen">
|
||||
<node CREATED="1771434938648" ID="ID_598910343" MODIFIED="1771435079926" TEXT="Anouncements ignorieren und jeweils per Heap allozieren">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
das aber in Code, der single-Threaded läuft; sofern man beim Implementieren darauf Acht gibt, keine übergreifende Koordinierung zu machen, also nur Aufruf-lokalen State verwendet, kann dieses Muster bereits von einem »naiven« Allokator geleistet werden
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="forward"/>
|
||||
</node>
|
||||
<node CREATED="1771434732657" ID="ID_1779414160" MODIFIED="1771435551701" TEXT="Verwaltung nur lokal im Thread">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Es gibt bei diesem Modell also bereits Code, der im Worker-Thread abläuft und einen thread-local-State hat; auch Announcements werden behandelt. Es gibt aber tatsächlich keine Zentrale, und dem entsprechend auch kein asynchrones Messaging
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<node CREATED="1771434757430" ID="ID_460264122" MODIFIED="1771434936057" TEXT="es gibt dort bereits ein gewisses Pooling">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Also man implementiert bereits eine Liste vorhandener Blöcke und auch schon die Verwendungs-Zähler, aber man kommuniziert nicht mit einer zentralen Renderbuffer-Verwaltung, sondern macht einfach Heap-Allokationen und Deallokationen, schließlich ist der Heap bereits ein ziemlich ausgereifter Resourcen-Manager, und wird auch indirekt durch das virtuelle Memory-Mapping unterstützt (was Segen und Fluch zugleich sein kann)
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771434769658" ID="ID_830753719" MODIFIED="1771434796468" TEXT="aber neu-Allokationen und Freigaben passieren direkt per Heap-Memory"/>
|
||||
</node>
|
||||
<node CREATED="1771435088490" ID="ID_1084049036" MODIFIED="1771435456405" TEXT="Zentraler Pool arbeitet identisch wie die thread-lokale Verwaltung">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Man verwendet also in diesem Schema bereits einen zentralen Pool, der aber nach der gleichen Logik behandelt wird, wie in der lokalen Verwaltung. Einziger Unterschied ist, daß Anfragen hier nicht per API-Aufruf direkt ankommen, sondern über asynchrones Messaging. Ansonsten bedient sich dieser zentrale Pool aber ebenfalls direkt von/zum Heap. Man spekuliert bei diesem Modell lediglich auf einen gewissen Aggregations-Effekt
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1702414560197" ID="ID_1321884127" MODIFIED="1702414571124" TEXT="Verhalten unter echter Last beobachten">
|
||||
|
|
|
|||
Loading…
Reference in a new issue