BufferProvider: find a solution for processing allocations
Implementing the `EngineBufferManager` the desired way, with the ability to post allocation requests asynchronously, raises the difficult question of who will ultimately perform the allocation / deallocation and further management work. The point is that this management effort takes up capacity originally assigned for the render workers themselves, either by implicitly pushing aside those threads, or as a dedicated processing assigned to some worker. In the current stage of development it seems impossible to decide upon the proper mechanism to schedule this excess work explicitly. The solution proposed hereby however circumvents this dilemma, insofar it allows to implement the synchronous, fallback processing in terms of the asynchronous processing, just performed exclusively within the current thread. Unless some processing will be scheduled explicitly (which can be added as performance optimisation later on), the handling of a direct allocation request will ''fold down'' into the current worker eventually, thereby using it's processing capability without the need of any explicit scheduling.
This commit is contained in:
parent
7c44cac3df
commit
5a47b099be
4 changed files with 399 additions and 38 deletions
|
|
@ -23,6 +23,7 @@
|
||||||
** blocks of memory. The contract is that the local memory user has to
|
** blocks of memory. The contract is that the local memory user has to
|
||||||
** return those blocks reliably to the EngineBuffrerManager, which
|
** return those blocks reliably to the EngineBuffrerManager, which
|
||||||
** itself is also an \ref AllocReceiver.
|
** itself is also an \ref AllocReceiver.
|
||||||
|
** @todo 5/2026 the plan is to use pooling allocators for the render buffers //////////////////////////////TICKET #1430
|
||||||
**
|
**
|
||||||
** @see EnginePufferManager_test
|
** @see EnginePufferManager_test
|
||||||
** @see LocalBufferStore_test
|
** @see LocalBufferStore_test
|
||||||
|
|
@ -76,12 +77,69 @@ namespace mem {
|
||||||
requestQueue_.consume_all ([this](AllocRequest request)
|
requestQueue_.consume_all ([this](AllocRequest request)
|
||||||
{
|
{
|
||||||
REQUIRE (request.receiver);
|
REQUIRE (request.receiver);
|
||||||
BufferAllocator allocator;
|
Alloc alloc = doPerformAllocation (request.sizRequest);
|
||||||
Alloc alloc = allocator.allocate (request.sizRequest);
|
ENSURE (not alloc.empty());
|
||||||
ENSURE (alloc.mem);
|
|
||||||
request.receiver->supply (alloc);
|
request.receiver->supply (alloc);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Alloc
|
||||||
|
EngineBufferManager::requestAllocation (size_t sizRequest)
|
||||||
|
{
|
||||||
|
processPendingRequests();
|
||||||
|
return doPerformAllocation (sizRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo 5/2026 this is a preliminary placeholder implementation,
|
||||||
|
* since any requests will just be passed-through to the heap allocator.
|
||||||
|
* The plan is to use a system of buffer pools eventually... ///////////////////////////////////////TICKET #1430
|
||||||
|
*/
|
||||||
|
Alloc
|
||||||
|
EngineBufferManager::doPerformAllocation (size_t sizRequest)
|
||||||
|
{
|
||||||
|
BufferAllocator allocator;
|
||||||
|
Alloc alloc = allocator.allocate (sizRequest);
|
||||||
|
if (not alloc.empty())
|
||||||
|
{
|
||||||
|
allocated_ += alloc.siz;
|
||||||
|
leased_ += alloc.siz;
|
||||||
|
++cnt_;
|
||||||
|
}
|
||||||
|
return alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
EngineBufferManager::doRedeemAllocation (Alloc alloc)
|
||||||
|
{
|
||||||
|
REQUIRE (not alloc.empty());
|
||||||
|
ENSURE (allocated_ >= alloc.siz);
|
||||||
|
ENSURE (leased_ >= alloc.siz);
|
||||||
|
ENSURE (cnt_ >= 1 );
|
||||||
|
|
||||||
|
BufferAllocator allocator;
|
||||||
|
allocated_ -= alloc.siz;
|
||||||
|
leased_ -= alloc.siz;
|
||||||
|
--cnt_;
|
||||||
|
allocator.deallocate (alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @remark this API becomes relevant if we actually use a pool */
|
||||||
|
size_t
|
||||||
|
EngineBufferManager::size() const
|
||||||
|
{
|
||||||
|
return cnt_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
EngineBufferManager::empty() const
|
||||||
|
{
|
||||||
|
return 0 == cnt_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}} // namespace vault::mem
|
}} // namespace vault::mem
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,8 @@ namespace mem {
|
||||||
{
|
{
|
||||||
Buff* mem;
|
Buff* mem;
|
||||||
size_t siz;
|
size_t siz;
|
||||||
|
|
||||||
|
bool empty() const { return not bool(mem); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -118,17 +120,124 @@ namespace mem {
|
||||||
using RequestQueue = boost::lockfree::queue<AllocRequest>;
|
using RequestQueue = boost::lockfree::queue<AllocRequest>;
|
||||||
RequestQueue requestQueue_;
|
RequestQueue requestQueue_;
|
||||||
|
|
||||||
|
/// diagnostic bookkeeping
|
||||||
|
size_t allocated_{0};
|
||||||
|
size_t leased_{0};
|
||||||
|
size_t cnt_{0};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EngineBufferManager()
|
EngineBufferManager()
|
||||||
: AllocReceiver{}
|
: AllocReceiver{}
|
||||||
, requestQueue_{INQUEUE_SIZ}
|
, requestQueue_{INQUEUE_SIZ}
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
size_t size() const;
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************//**
|
||||||
|
* Core function: satisfy a request for allocation
|
||||||
|
* @return an \ref Alloc struct representing the desired allocation,
|
||||||
|
* can be empty to signal that the request can not be satisfied.
|
||||||
|
* @warning whoever accepts a non-empty result from this call
|
||||||
|
* is **responsible** to [return](\ref AllocReceiver::supply)
|
||||||
|
* this allocation eventually, to prevent memory leakage.
|
||||||
|
*/
|
||||||
|
Alloc requestAllocation (size_t sizRequest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard access point: request an allocation
|
||||||
|
* that will be dispatched asynchronously to the given receiver.
|
||||||
|
* @remark without any temporal guarantees, this request will be
|
||||||
|
* processed eventually, placing an \ref Alloc into the
|
||||||
|
* [receiver's inqueue](\ref AllocReceiver::supply)
|
||||||
|
* @warning when the returned Alloc is [non-empty](\ref Alloc::empty),
|
||||||
|
* the receiver is responsible for returning it after use.
|
||||||
|
*/
|
||||||
|
void async_requestAllocation (AllocRequest const&);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle all enqueued asynchronous requests
|
||||||
|
* and perform pending management and allocation work.
|
||||||
|
* @remark this function can be invoked as a batch job;
|
||||||
|
* it acquires a lock and then handles the backlog.
|
||||||
|
*/
|
||||||
|
void processPendingRequests();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** process all pending requests in the queue */
|
/** process all pending requests in the queue */
|
||||||
void handleAllocRequests();
|
void handleAllocRequests();
|
||||||
|
|
||||||
|
/** performs the actual allocation work */
|
||||||
|
Alloc doPerformAllocation (size_t sizRequest);
|
||||||
|
void doRedeemAllocation (Alloc);
|
||||||
|
|
||||||
|
/** a »backdoor« for unit testing */
|
||||||
|
friend class BufferManagerDiagnostic;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline void
|
||||||
|
EngineBufferManager::async_requestAllocation (AllocRequest const& req)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
EngineBufferManager::processPendingRequests()
|
||||||
|
{
|
||||||
|
inQueue_.consume_all ([this](Alloc alloc){ doRedeemAllocation (alloc); });
|
||||||
|
handleAllocRequests();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** wrapper to inspect internals from a unit test */
|
||||||
|
class BufferManagerDiagnostic
|
||||||
|
: util::MoveOnly
|
||||||
|
{
|
||||||
|
EngineBufferManager const& globalPool_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BufferManagerDiagnostic (EngineBufferManager const& manager)
|
||||||
|
: globalPool_{manager}
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool
|
||||||
|
isEmpty()
|
||||||
|
{
|
||||||
|
return globalPool_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
size()
|
||||||
|
{
|
||||||
|
return globalPool_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
bytesAllocd()
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED ("alloc state diagnostic");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
bytesLeased()
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED ("alloc state diagnostic");
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1430 : add pool diagnostics here if we actually switch to pooled allocations
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** entrance point to inspection for test */
|
||||||
|
inline BufferManagerDiagnostic
|
||||||
|
watch (EngineBufferManager const& manager)
|
||||||
|
{
|
||||||
|
return BufferManagerDiagnostic{manager};
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace vault::mem
|
}} // namespace vault::mem
|
||||||
#endif /*VAULT_MEM_ENGINE_BUFFR_MANAGA_H*/
|
#endif /*VAULT_MEM_ENGINE_BUFFR_MANAGA_H*/
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,14 @@
|
||||||
//#include "lib/depend-inject.hpp"
|
//#include "lib/depend-inject.hpp"
|
||||||
//#include "lib/thread.hpp"
|
//#include "lib/thread.hpp"
|
||||||
//#include "lib/error.hpp"
|
//#include "lib/error.hpp"
|
||||||
|
#include "lib/symbol.hpp"
|
||||||
#include "test/diagnostic-output.hpp"////////////TODO
|
#include "test/diagnostic-output.hpp"////////////TODO
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
//using std::this_thread::yield;
|
//using std::this_thread::yield;
|
||||||
//using lib::Thread;
|
//using lib::Thread;
|
||||||
|
using lib::Literal;
|
||||||
|
|
||||||
namespace vault {
|
namespace vault {
|
||||||
namespace mem {
|
namespace mem {
|
||||||
|
|
@ -66,7 +69,8 @@ namespace test {
|
||||||
// seedRand();
|
// seedRand();
|
||||||
|
|
||||||
demonstrate_AllocatorInterface();
|
demonstrate_AllocatorInterface();
|
||||||
verify_DataTransfer();
|
verify_syncRequest();
|
||||||
|
verify_asyncRequest();
|
||||||
verify_lulz();
|
verify_lulz();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,9 +111,34 @@ namespace test {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** @test */
|
/** @test show that a direct request for allocation is honored */
|
||||||
void
|
void
|
||||||
verify_DataTransfer()
|
verify_syncRequest()
|
||||||
|
{
|
||||||
|
EngineBufferManager manager;
|
||||||
|
SHOW_EXPR(watch(manager).isEmpty())
|
||||||
|
|
||||||
|
Alloc alloc = manager.requestAllocation (555);
|
||||||
|
CHECK (not alloc.empty());
|
||||||
|
CHECK (alloc.siz >= 555);
|
||||||
|
|
||||||
|
SHOW_EXPR(watch(manager).bytesAllocd())
|
||||||
|
SHOW_EXPR(watch(manager).bytesLeased())
|
||||||
|
|
||||||
|
// can use that memory
|
||||||
|
char* buf = reinterpret_cast<char*> (alloc.mem);
|
||||||
|
string ranS{lib::randStr(555-1)};
|
||||||
|
auto* p = std::copy (ranS.begin(), ranS.end(), buf);
|
||||||
|
SHOW_EXPR(p - buf)
|
||||||
|
*p = '\0';
|
||||||
|
CHECK (ranS == buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** @test show that an working allocation request across thread boundaries */
|
||||||
|
void
|
||||||
|
verify_asyncRequest()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -116126,6 +116126,11 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
||||||
<linktarget COLOR="#fe512a" DESTINATION="ID_1866513124" ENDARROW="Default" ENDINCLINATION="1101;-48;" ID="Arrow_ID_216610784" SOURCE="ID_389538548" STARTARROW="None" STARTINCLINATION="-1061;50;"/>
|
<linktarget COLOR="#fe512a" DESTINATION="ID_1866513124" ENDARROW="Default" ENDINCLINATION="1101;-48;" ID="Arrow_ID_216610784" SOURCE="ID_389538548" STARTARROW="None" STARTINCLINATION="-1061;50;"/>
|
||||||
<icon BUILTIN="bell"/>
|
<icon BUILTIN="bell"/>
|
||||||
</node>
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1721238814245" ID="ID_611835362" MODIFIED="1778544742963" TEXT="Schwierigkeit: Steuern des Aufwands für Buffer-Allokation">
|
||||||
|
<arrowlink COLOR="#fd374b" DESTINATION="ID_1302229619" ENDARROW="Default" ENDINCLINATION="-1530;-92;" ID="Arrow_ID_1216327685" STARTARROW="None" STARTINCLINATION="-1173;55;"/>
|
||||||
|
<linktarget COLOR="#fe512a" DESTINATION="ID_611835362" ENDARROW="Default" ENDINCLINATION="1101;-48;" ID="Arrow_ID_1590540822" SOURCE="ID_166765181" STARTARROW="None" STARTINCLINATION="-1013;69;"/>
|
||||||
|
<icon BUILTIN="bell"/>
|
||||||
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node BACKGROUND_COLOR="#c8b6c1" CREATED="1729963571896" HGAP="-82" ID="ID_780325179" MODIFIED="1729963839764" TEXT="Schablone" VSHIFT="23">
|
<node BACKGROUND_COLOR="#c8b6c1" CREATED="1729963571896" HGAP="-82" ID="ID_780325179" MODIFIED="1729963839764" TEXT="Schablone" VSHIFT="23">
|
||||||
<edge COLOR="#be05a9"/>
|
<edge COLOR="#be05a9"/>
|
||||||
|
|
@ -146174,7 +146179,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
||||||
</html></richcontent>
|
</html></richcontent>
|
||||||
<icon BUILTIN="help"/>
|
<icon BUILTIN="help"/>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1777325501367" ID="ID_586279034" MODIFIED="1777325521405" TEXT="tatsächlich wollen wir hier eine explizit gemanagete Server-Komponente"/>
|
<node CREATED="1777325501367" ID="ID_586279034" MODIFIED="1778507800975" TEXT="tatsächlich wollen wir hier eine explizit gemanagete Server-Komponente">
|
||||||
|
<arrowlink COLOR="#fde6d2" DESTINATION="ID_1303340175" ENDARROW="Default" ENDINCLINATION="690;28;" ID="Arrow_ID_795971086" STARTARROW="None" STARTINCLINATION="862;34;"/>
|
||||||
|
</node>
|
||||||
<node CREATED="1777325699181" ID="ID_1392466705" MODIFIED="1777325832394" TEXT="Dependency-Factory kann auf abstrakte Basisklasse konfiguriert werden">
|
<node CREATED="1777325699181" ID="ID_1392466705" MODIFIED="1777325832394" TEXT="Dependency-Factory kann auf abstrakte Basisklasse konfiguriert werden">
|
||||||
<richcontent TYPE="NOTE"><html>
|
<richcontent TYPE="NOTE"><html>
|
||||||
<head/>
|
<head/>
|
||||||
|
|
@ -146543,6 +146550,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1778205040426" ID="ID_609664480" MODIFIED="1778205118401" TEXT="weiteres Problem: Race mit Ende des Worker-Thread">
|
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1778205040426" ID="ID_609664480" MODIFIED="1778205118401" TEXT="weiteres Problem: Race mit Ende des Worker-Thread">
|
||||||
<linktarget COLOR="#e01436" DESTINATION="ID_609664480" ENDARROW="Default" ENDINCLINATION="-1139;0;" ID="Arrow_ID_649333039" SOURCE="ID_1402352728" STARTARROW="None" STARTINCLINATION="707;0;"/>
|
<linktarget COLOR="#e01436" DESTINATION="ID_609664480" ENDARROW="Default" ENDINCLINATION="-1139;0;" ID="Arrow_ID_649333039" SOURCE="ID_1402352728" STARTARROW="None" STARTINCLINATION="707;0;"/>
|
||||||
<icon BUILTIN="messagebox_warning"/>
|
<icon BUILTIN="messagebox_warning"/>
|
||||||
|
|
@ -146568,14 +146577,13 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html></richcontent>
|
</html></richcontent>
|
||||||
|
<linktarget COLOR="#ff1b15" DESTINATION="ID_931645192" ENDARROW="Default" ENDINCLINATION="-857;174;" ID="Arrow_ID_801625969" SOURCE="ID_1394284825" STARTARROW="None" STARTINCLINATION="171;-11;"/>
|
||||||
<icon BUILTIN="clanbomber"/>
|
<icon BUILTIN="clanbomber"/>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1778372162541" ID="ID_1423477043" MODIFIED="1778372391306">
|
<node CREATED="1778372162541" ID="ID_1423477043" MODIFIED="1778372391306">
|
||||||
<richcontent TYPE="NODE"><html>
|
<richcontent TYPE="NODE"><html>
|
||||||
<head>
|
<head/>
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<p>
|
||||||
das ist zwar nur ein Grenzfall
|
das ist zwar nur ein Grenzfall
|
||||||
|
|
@ -146584,50 +146592,38 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
||||||
 — aber er stellt das gesamte Konzept in Frage
|
 — aber er stellt das gesamte Konzept in Frage
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html></richcontent>
|
||||||
</richcontent>
|
|
||||||
<richcontent TYPE="NOTE"><html>
|
<richcontent TYPE="NOTE"><html>
|
||||||
<head>
|
<head/>
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<p>
|
||||||
Es handelt sich ganz klassisch um einen »Race« — das heißt, diese Situation ist in keinster Weise regulär vorgesehen, und dürfrte auch auch schwierig zu reproduzieren sein; sie sollte daher nicht der Maßstab sein, an dem das Konstrukt insgeseamt ausgerichtet wird. Leider aber führt diese Situation zur <i>memory corruption,</i> wenn wir das bisher ausgearbeitete Konzept umsetzen
|
Es handelt sich ganz klassisch um einen »Race« — das heißt, diese Situation ist in keinster Weise regulär vorgesehen, und dürfrte auch auch schwierig zu reproduzieren sein; sie sollte daher nicht der Maßstab sein, an dem das Konstrukt insgeseamt ausgerichtet wird. Leider aber führt diese Situation zur <i>memory corruption,</i> wenn wir das bisher ausgearbeitete Konzept umsetzen
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html></richcontent>
|
||||||
</richcontent>
|
|
||||||
<node CREATED="1778372393169" ID="ID_1109770264" MODIFIED="1778372505015" TEXT="Schwierigkeit: der LocalMemPool weiß nicht, was er angefordert hat">
|
<node CREATED="1778372393169" ID="ID_1109770264" MODIFIED="1778372505015" TEXT="Schwierigkeit: der LocalMemPool weiß nicht, was er angefordert hat">
|
||||||
<richcontent TYPE="NOTE"><html>
|
<richcontent TYPE="NOTE"><html>
|
||||||
<head>
|
<head/>
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<p>
|
||||||
denn andernfalls könnte man versuchen, über eine Spezialbehandlung im Destruktor die gesendete Speicher-Anforderung irgendwie stornieren (wiewohl auch dabei noch ein Race auftreten könnte)
|
denn andernfalls könnte man versuchen, über eine Spezialbehandlung im Destruktor die gesendete Speicher-Anforderung irgendwie stornieren (wiewohl auch dabei noch ein Race auftreten könnte)
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html></richcontent>
|
||||||
</richcontent>
|
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1778372507757" ID="ID_228507573" MODIFIED="1778372578208" TEXT="eine Möglichkeit wäre, eine zusätzliche Sicherung im empfangenden Code vorzusehen">
|
<node CREATED="1778372507757" ID="ID_228507573" MODIFIED="1778372578208" TEXT="eine Möglichkeit wäre, eine zusätzliche Sicherung im empfangenden Code vorzusehen">
|
||||||
<richcontent TYPE="NOTE"><html>
|
<richcontent TYPE="NOTE"><html>
|
||||||
<head>
|
<head/>
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<p>
|
||||||
So ähnlich wie der ZombieCheck...
|
So ähnlich wie der ZombieCheck...
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html></richcontent>
|
||||||
</richcontent>
|
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1778372538869" ID="ID_398624236" MODIFIED="1778373145721" TEXT="diese Sicherung müßte allerdings wirksam werden vor dem ersten tatsächlichen Speicherzugriff">
|
<node CREATED="1778372538869" ID="ID_398624236" MODIFIED="1778373145721" TEXT="diese Sicherung müßte allerdings wirksam werden vor dem ersten tatsächlichen Speicherzugriff">
|
||||||
<richcontent TYPE="NOTE"><html>
|
<richcontent TYPE="NOTE"><html>
|
||||||
<head>
|
<head/>
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<p>
|
||||||
Erläuterung...
|
Erläuterung...
|
||||||
|
|
@ -146653,10 +146649,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html></richcontent>
|
||||||
</richcontent>
|
|
||||||
</node>
|
|
||||||
</node>
|
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
|
|
@ -146689,12 +146682,31 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
||||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776819169143" ID="ID_1367745941" MODIFIED="1777050391595" TEXT="Schnittstelle für asynchrones Messaging bedenken">
|
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776819169143" ID="ID_1367745941" MODIFIED="1777050391595" TEXT="Schnittstelle für asynchrones Messaging bedenken">
|
||||||
<arrowlink COLOR="#fefab1" DESTINATION="ID_1503539674" ENDARROW="Default" ENDINCLINATION="-233;10;" ID="Arrow_ID_451160831" STARTARROW="None" STARTINCLINATION="92;5;"/>
|
<arrowlink COLOR="#fefab1" DESTINATION="ID_1503539674" ENDARROW="Default" ENDINCLINATION="-233;10;" ID="Arrow_ID_451160831" STARTARROW="None" STARTINCLINATION="92;5;"/>
|
||||||
<icon BUILTIN="flag-yellow"/>
|
<icon BUILTIN="flag-yellow"/>
|
||||||
|
<node CREATED="1778593688734" HGAP="35" ID="ID_730263664" MODIFIED="1778593713957" TEXT="Kern: die Verarbeitungs-Funktionalität" VSHIFT="-9">
|
||||||
|
<node CREATED="1778593747927" ID="ID_1315127845" MODIFIED="1778593770426" TEXT="sollte auf alle Allokator- und Aufräum-Arbeit kaskadieren"/>
|
||||||
|
<node CREATED="1778593720983" ID="ID_1339362365" MODIFIED="1778594032492" TEXT="Trick: diesen Zugang explizit auch public aufrufbar machen">
|
||||||
|
<linktarget COLOR="#fefbd6" DESTINATION="ID_1339362365" ENDARROW="Default" ENDINCLINATION="-30;50;" ID="Arrow_ID_1537514504" SOURCE="ID_308671982" STARTARROW="None" STARTINCLINATION="57;3;"/>
|
||||||
|
<linktarget COLOR="#e7f3c5" DESTINATION="ID_1339362365" ENDARROW="Default" ENDINCLINATION="273;14;" ID="Arrow_ID_74341588" SOURCE="ID_1723782536" STARTARROW="None" STARTINCLINATION="226;-11;"/>
|
||||||
|
<icon BUILTIN="idea"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776819181261" ID="ID_1026628741" MODIFIED="1776819956356" TEXT="alternative synchrone Schnittstelle bereitstellen">
|
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1776819181261" ID="ID_1026628741" MODIFIED="1776819956356" TEXT="alternative synchrone Schnittstelle bereitstellen">
|
||||||
<icon BUILTIN="flag-yellow"/>
|
<icon BUILTIN="flag-yellow"/>
|
||||||
<node CREATED="1777324291441" ID="ID_336948545" MODIFIED="1777324316333" TEXT="ist relevant für »sofort«-Allokation (Fallback)"/>
|
<node CREATED="1777324291441" ID="ID_336948545" MODIFIED="1777324316333" TEXT="ist relevant für »sofort«-Allokation (Fallback)"/>
|
||||||
<node CREATED="1776819226503" ID="ID_1059062619" MODIFIED="1777051865655" TEXT="sollte kongruent zum Messaging sein"/>
|
<node CREATED="1776819226503" ID="ID_1059062619" MODIFIED="1777051865655" TEXT="sollte kongruent zum Messaging sein"/>
|
||||||
<node CREATED="1776819244365" ID="ID_933815031" MODIFIED="1776819258406" TEXT="aber stets ein »pull« vom lokalen Manager"/>
|
<node CREATED="1778593890737" ID="ID_308671982" MODIFIED="1778594041691" TEXT="sollte idealerweise die asynchrone Lösung inkludieren">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head/>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
...so daß es tatsächlich nur eine Lösung gibt, nämlich die Asynchrone, die dann hier aber sofort im aktuellen Thread komplett durchläuft. Wie sich zeigt, ist das nicht bloß ein Kniff, um Duplikation im Code zu vermeiden, sondern löst <i>wie von selbst</i> eine schwierige architektonische Aufgabe
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html></richcontent>
|
||||||
|
<arrowlink COLOR="#fefbd6" DESTINATION="ID_1339362365" ENDARROW="Default" ENDINCLINATION="-30;50;" ID="Arrow_ID_1537514504" STARTARROW="None" STARTINCLINATION="57;3;"/>
|
||||||
|
</node>
|
||||||
|
<node CREATED="1776819244365" ID="ID_933815031" MODIFIED="1778593872888" TEXT="erfolgt stets als »pull« vom lokalen Manager"/>
|
||||||
</node>
|
</node>
|
||||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1777324327301" ID="ID_1965528564" MODIFIED="1777324340058" TEXT="lege zunächst einen »naiven« Memory-Manager an">
|
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1777324327301" ID="ID_1965528564" MODIFIED="1777324340058" TEXT="lege zunächst einen »naiven« Memory-Manager an">
|
||||||
<icon BUILTIN="flag-yellow"/>
|
<icon BUILTIN="flag-yellow"/>
|
||||||
|
|
@ -146715,8 +146727,100 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
||||||
<node CREATED="1777324494396" ID="ID_23718162" MODIFIED="1777324511253" TEXT="möglicherweise ist eine dynamische Steuerung notwendig + fall-Back auf den Heap-Allokator"/>
|
<node CREATED="1777324494396" ID="ID_23718162" MODIFIED="1777324511253" TEXT="möglicherweise ist eine dynamische Steuerung notwendig + fall-Back auf den Heap-Allokator"/>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1777324560690" ID="ID_318881353" MODIFIED="1777324567396" TEXT="Rahmen per Test abstecken">
|
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1778507655159" ID="ID_662701381" MODIFIED="1778507661951" TEXT="Setup und Lebenszyklus">
|
||||||
<node COLOR="#338800" CREATED="1777339205760" ID="ID_1644044904" MODIFIED="1777339355233" TEXT="demonstrate_AllocatorInterface">
|
<icon BUILTIN="hourglass"/>
|
||||||
|
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1778507710093" ID="ID_86258163" MODIFIED="1778507821841" TEXT="jemand muß die Instanz erzeugen">
|
||||||
|
<icon BUILTIN="yes"/>
|
||||||
|
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1778507726771" ID="ID_1303340175" MODIFIED="1778507800975" TEXT="Notwendig sofern irgend etwas konfitguriert und verdrahtet werden soll">
|
||||||
|
<linktarget COLOR="#fde6d2" DESTINATION="ID_1303340175" ENDARROW="Default" ENDINCLINATION="690;28;" ID="Arrow_ID_795971086" SOURCE="ID_586279034" STARTARROW="None" STARTINCLINATION="862;34;"/>
|
||||||
|
<icon BUILTIN="messagebox_warning"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1778507988939" ID="ID_48400467" MODIFIED="1778508004878" TEXT="Klären: wer bearbeitet angeforderte Allokationen?">
|
||||||
|
<icon BUILTIN="help"/>
|
||||||
|
<node CREATED="1778508010370" ID="ID_681344982" MODIFIED="1778508200989" TEXT="Fallback-Lösung: der Anforderer selbst (synchron)">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head/>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
Möglicherweise ist diese Lösung gar nicht so dramatisch schlecht...
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Allerdings wird dadurch der Aufwand für Allokationen und Speichermanagement zum Blocker und kann auch andere Threads behindern; wie schädlich das aber tatsächlich in der Praxis wird, hängt davon ab wie gut der »local Pool«-Ansatz wirkt
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html></richcontent>
|
||||||
|
</node>
|
||||||
|
<node CREATED="1778508213822" ID="ID_251628069" MODIFIED="1778508354641" TEXT="Irgendjemand muß es ja machen — auf Kosten des Rendering">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head/>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
Da wir nur N Kerne haben, muß letztlich immer dafür Rechenkapazität von einem Worker verdrängt werden (es sei denn, man hat <i>so viele Kerne,</i> daß man einfach mal einen Kern für »Sonstiges« beiseite stellen kann)
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html></richcontent>
|
||||||
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#e2dbb4" CREATED="1778592973322" ID="ID_1723782536" MODIFIED="1778593812308" TEXT="hybrid-Lösung: der synchrone Fall schiebt den asynchronen Fall">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head/>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
Das ist ein Kniff (für den ich einige Zeit gebraucht habe, um ihn zu sehen): wenn es gelingt, die synchrone Lösung komplett durch die asynchrone Lösung zu implementieren, dann impliziert der Aufruf dieser synchronen Lösung daß effektiv ein »sub-Job« mit der aktuell aufgesammelten Allokator-Arbeit im aktuellen Worker läuft. Das ist zwar ein ziemlich trickreicher Ansatz, hat aber die Schönheit daß man <i>eigentlich gar nichts dafür tun muß </i>— insofern wäre damit jede andere Lösung (Hintergrund-Thread, dedizierter Job) nur noch eine optionale Performance-Optimierung
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html></richcontent>
|
||||||
|
<arrowlink COLOR="#e7f3c5" DESTINATION="ID_1339362365" ENDARROW="Default" ENDINCLINATION="273;14;" ID="Arrow_ID_74341588" STARTARROW="None" STARTINCLINATION="226;-11;"/>
|
||||||
|
<icon BUILTIN="forward"/>
|
||||||
|
</node>
|
||||||
|
<node CREATED="1778508357967" ID="ID_1467114460" MODIFIED="1778508767506" TEXT="naheliegende Lösung: Hintergrundthread">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head/>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
Dieser würde dann periodisch schlafen und die Queue bedienen. Nach außen bleibt das komplett transparent und der Code ist einfach; allerdings kann das dazu führen daß andere Worker zwischen den Cores migrieren, außerdem wird das System insgesamt komplexer (es braucht einen separaten Service mit eigenem Lebenszyklus). Sofern allerdings der Aufwand für die Allokations-Arbeit gegenüber dem Rendering vernachlässigbar ist, und weniger als ein OS-Schedule-Slice benötigt, dürfte sich der Einfluß auf die Performance in Grenzen halten — unter diesen Voraussetzungen allerdings könnte der jeweilge Worker diese Arbeit auch gleich selber machen
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html></richcontent>
|
||||||
|
</node>
|
||||||
|
<node CREATED="1778508802711" ID="ID_202726246" MODIFIED="1778512058723" TEXT="Service-Job absetzen">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head/>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
In dem Moment, wo so eine Anforderung auftritt, wird ein Service-Job abgesetzt, mit einer Priorität, die noch zu diskutieren wäre. Möglicherweise müßte die Steuerung sogar dynamisch sein, denn es handelt sich um eine »opportunistische« Parallelisierung, die nur sinnvoll ist, wenn der eigentliche Worker <i>inzwischen schon mal anfangen kann.</i> Denn sonst besteht die Gefahr von duplizierten Allokationen, wenn kurz darauf der Speicher definitiv im Worker gebraucht wird, und daher direkt, synchron angefordert. Das läßt sich nicht verhindern, da wir nicht »buch führen« über die Anforderungen, und auch nicht aggregieren, da der Aufwand hierfür im Regelfall verschwendet wäre. Eine weitere relevante Frage ist die nach dem insgesamt anfallenden Aufwand; da Anfragen, aber auch die die Rückgabe von Allokationen asynchron über Queues erfolgt, steht zu erwarten daß sich jeweils einge dieser »kleinen Handgriffe« ansammeln. Dem steht gegenüber, daß das Scheduling eines Jobs einen erheblichen Aufwand verursacht, der im Verhältnis um 1-2 Größenordnungen über dem Aufwand für ein Mutex-Lock und eine globale Allokation liegt.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html></richcontent>
|
||||||
|
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1721238837562" HGAP="125" ID="ID_166765181" MODIFIED="1778592944008" STYLE="bubble" TEXT="Schwierigkeit: Aufwand und Priorisierung" VSHIFT="83">
|
||||||
|
<edge COLOR="#ff5d00" STYLE="sharp_linear"/>
|
||||||
|
<arrowlink COLOR="#fe512a" DESTINATION="ID_611835362" ENDARROW="Default" ENDINCLINATION="1101;-48;" ID="Arrow_ID_1590540822" STARTARROW="None" STARTINCLINATION="-1013;69;"/>
|
||||||
|
<arrowlink COLOR="#fe512a" DESTINATION="ID_1302229619" ENDARROW="Default" ENDINCLINATION="1101;-48;" ID="Arrow_ID_1850718826" STARTARROW="None" STARTINCLINATION="-888;56;"/>
|
||||||
|
<icon BUILTIN="bell"/>
|
||||||
|
<node CREATED="1721239003353" HGAP="24" ID="ID_295105344" MODIFIED="1778592923479" STYLE="fork" TEXT="wann ist es sinnvoll einen Service-Job einzusezen?" VSHIFT="13">
|
||||||
|
<font NAME="SansSerif" SIZE="8"/>
|
||||||
|
</node>
|
||||||
|
<node CREATED="1778512183643" ID="ID_660207569" MODIFIED="1778512206019" STYLE="fork" TEXT="Dringlichkeit ⟷ Ansammeln von Arbeit">
|
||||||
|
<edge COLOR="#ff5d00" STYLE="sharp_linear" WIDTH="thin"/>
|
||||||
|
<font NAME="SansSerif" SIZE="8"/>
|
||||||
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#e3dcaf" COLOR="#990000" CREATED="1778547854514" HGAP="18" ID="ID_270935803" LINK="https://issues.lumiera.org/ticket/1429" MODIFIED="1778547925898" TEXT="#1429 control effort for global buffer allocator " VSHIFT="11">
|
||||||
|
<edge COLOR="#ffa500"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1778507847611" ID="ID_1394284825" MODIFIED="1778507972282" TEXT="Race wegen terminierendem Thread">
|
||||||
|
<arrowlink COLOR="#ff1b15" DESTINATION="ID_931645192" ENDARROW="Default" ENDINCLINATION="-857;174;" ID="Arrow_ID_801625969" STARTARROW="None" STARTINCLINATION="171;-11;"/>
|
||||||
|
<icon BUILTIN="clanbomber"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1777324560690" ID="ID_318881353" MODIFIED="1778507667074" TEXT="Rahmen per Test abstecken">
|
||||||
|
<icon BUILTIN="pencil"/>
|
||||||
|
<node COLOR="#9b0b61" CREATED="1778591274938" ID="ID_540360328" MODIFIED="1778591296515" TEXT="EngineBufferManager_test">
|
||||||
|
<icon BUILTIN="info"/>
|
||||||
|
</node>
|
||||||
|
<node COLOR="#338800" CREATED="1777339205760" ID="ID_1644044904" MODIFIED="1778591283255" TEXT="demonstrate_AllocatorInterface">
|
||||||
<richcontent TYPE="NOTE"><html>
|
<richcontent TYPE="NOTE"><html>
|
||||||
<head/>
|
<head/>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -146727,6 +146831,37 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
||||||
</html></richcontent>
|
</html></richcontent>
|
||||||
<linktarget COLOR="#47c9c9" DESTINATION="ID_1644044904" ENDARROW="Default" ENDINCLINATION="6;-56;" ID="Arrow_ID_1619156849" SOURCE="ID_1470622255" STARTARROW="None" STARTINCLINATION="-20;33;"/>
|
<linktarget COLOR="#47c9c9" DESTINATION="ID_1644044904" ENDARROW="Default" ENDINCLINATION="6;-56;" ID="Arrow_ID_1619156849" SOURCE="ID_1470622255" STARTARROW="None" STARTINCLINATION="-20;33;"/>
|
||||||
</node>
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1778595475430" ID="ID_992537338" MODIFIED="1778597417344" STYLE="fork" TEXT="Diagnose-Zugang schaffen: watch(manager)">
|
||||||
|
<icon BUILTIN="pencil"/>
|
||||||
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1778599970816" ID="ID_346337478" MODIFIED="1778599973845" TEXT="verify_syncRequest">
|
||||||
|
<icon BUILTIN="pencil"/>
|
||||||
|
<node CREATED="1778599985224" ID="ID_1402142899" MODIFIED="1778599992550" TEXT="eine Allokation machen"/>
|
||||||
|
<node CREATED="1778599993498" ID="ID_1315033221" MODIFIED="1778600012854" TEXT="Diagnose der belegten Bytes checken"/>
|
||||||
|
<node CREATED="1778600013692" ID="ID_245317435" MODIFIED="1778600031040" TEXT="was in den Speicher schreiben">
|
||||||
|
<icon BUILTIN="help"/>
|
||||||
|
<icon BUILTIN="smiley-neutral"/>
|
||||||
|
<node CREATED="1778600033770" ID="ID_340804822" MODIFIED="1778600056398" TEXT="das beweist nicht wirklich viel">
|
||||||
|
<icon BUILTIN="messagebox_warning"/>
|
||||||
|
</node>
|
||||||
|
<node CREATED="1778600042853" ID="ID_1647620526" MODIFIED="1778600051898" TEXT="dieses Problem ist semi-entscheidbar">
|
||||||
|
<icon BUILTIN="idea"/>
|
||||||
|
</node>
|
||||||
|
<node CREATED="1778600072731" ID="ID_722954132" MODIFIED="1778600088111">
|
||||||
|
<richcontent TYPE="NODE"><html>
|
||||||
|
<head/>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
wenigstens <i>demonstriert es die Nutzbarkeit</i>
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html></richcontent>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1778599975152" ID="ID_1790536650" MODIFIED="1778599980968" TEXT="verify_asyncRequest">
|
||||||
|
<icon BUILTIN="hourglass"/>
|
||||||
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1777330585249" ID="ID_1415692101" MODIFIED="1777330598348" TEXT="Ergebnis / Einsichten">
|
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1777330585249" ID="ID_1415692101" MODIFIED="1777330598348" TEXT="Ergebnis / Einsichten">
|
||||||
<icon BUILTIN="forward"/>
|
<icon BUILTIN="forward"/>
|
||||||
|
|
@ -171421,6 +171556,36 @@ std::cout << tmpl.render({"what", "World"}) << s
|
||||||
<linktarget COLOR="#943456" DESTINATION="ID_1232029805" ENDARROW="Default" ENDINCLINATION="-284;-16;" ID="Arrow_ID_173708448" SOURCE="ID_167266149" STARTARROW="None" STARTINCLINATION="155;234;"/>
|
<linktarget COLOR="#943456" DESTINATION="ID_1232029805" ENDARROW="Default" ENDINCLINATION="-284;-16;" ID="Arrow_ID_173708448" SOURCE="ID_167266149" STARTARROW="None" STARTINCLINATION="155;234;"/>
|
||||||
<icon BUILTIN="flag-yellow"/>
|
<icon BUILTIN="flag-yellow"/>
|
||||||
</node>
|
</node>
|
||||||
|
<node CREATED="1778511996967" ID="ID_708815431" MODIFIED="1778512001168" TEXT="Betriebssteuerung">
|
||||||
|
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1721238814245" ID="ID_1302229619" MODIFIED="1778544742966" TEXT="Aufgabe: Buffer-Allokation steuern">
|
||||||
|
<linktarget COLOR="#fd374b" DESTINATION="ID_1302229619" ENDARROW="Default" ENDINCLINATION="-1530;-92;" ID="Arrow_ID_1216327685" SOURCE="ID_611835362" STARTARROW="None" STARTINCLINATION="-1173;55;"/>
|
||||||
|
<linktarget COLOR="#fe512a" DESTINATION="ID_1302229619" ENDARROW="Default" ENDINCLINATION="1101;-48;" ID="Arrow_ID_1850718826" SOURCE="ID_166765181" STARTARROW="None" STARTINCLINATION="-888;56;"/>
|
||||||
|
<icon BUILTIN="bell"/>
|
||||||
|
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1778547854514" HGAP="36" ID="ID_1695116908" LINK="https://issues.lumiera.org/ticket/1429" MODIFIED="1778547956862" TEXT="#1429 control effort for global buffer allocator " VSHIFT="10">
|
||||||
|
<icon BUILTIN="flag-yellow"/>
|
||||||
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1778547971007" ID="ID_1189474796" MODIFIED="1778548102342">
|
||||||
|
<richcontent TYPE="NODE"><html>
|
||||||
|
<head/>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
es ist nicht einmal klar wie <i>wir vorläufig damit umgehen</i>
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html></richcontent>
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head/>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
...denn es <b>muß hier etwas getan werden</b>, sonst funktioniert das System überhaupt nicht — ist es sinnvoll, zunächst die Anforderungen stets synchron zu handhaben?
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html></richcontent>
|
||||||
|
<font NAME="SansSerif" SIZE="11"/>
|
||||||
|
<icon BUILTIN="messagebox_warning"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
<node CREATED="1697933502816" ID="ID_1155890066" MODIFIED="1697933560271" TEXT="Laststeuerung">
|
<node CREATED="1697933502816" ID="ID_1155890066" MODIFIED="1697933560271" TEXT="Laststeuerung">
|
||||||
<linktarget COLOR="#7d55a6" DESTINATION="ID_1155890066" ENDARROW="Default" ENDINCLINATION="-78;310;" ID="Arrow_ID_1724375377" SOURCE="ID_338601496" STARTARROW="None" STARTINCLINATION="-372;-24;"/>
|
<linktarget COLOR="#7d55a6" DESTINATION="ID_1155890066" ENDARROW="Default" ENDINCLINATION="-78;310;" ID="Arrow_ID_1724375377" SOURCE="ID_338601496" STARTARROW="None" STARTINCLINATION="-372;-24;"/>
|
||||||
<node CREATED="1697933512163" ID="ID_394926401" MODIFIED="1697933535592" TEXT="Zeitgesteuertes Rendern">
|
<node CREATED="1697933512163" ID="ID_394926401" MODIFIED="1697933535592" TEXT="Zeitgesteuertes Rendern">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue