diff --git a/src/lib/builder-qualifier-support.hpp b/src/lib/builder-qualifier-support.hpp index 5513f7cc8..3f9e32cdc 100644 --- a/src/lib/builder-qualifier-support.hpp +++ b/src/lib/builder-qualifier-support.hpp @@ -31,7 +31,7 @@ ** @warning since these qualifiers manipulate by side-effect, it is up to the user to ensure ** consistent settings and behaviour (typically within a terminal `build()` function). ** @note the `qualify()` function accepts the qualifier functors by-reference; thus it is up - ** to the user to either pass them by-value, by reverence or even by perfect forwarding. + ** to the user to either pass them by-value, by reference or even by perfect forwarding. ** ** @see BuilderQualifierSupport_test ** @see ElementBoxWidget as usage example diff --git a/src/steam/engine/buffer-provider.hpp b/src/steam/engine/buffer-provider.hpp index 500250a09..f6e8a9cc4 100644 --- a/src/steam/engine/buffer-provider.hpp +++ b/src/steam/engine/buffer-provider.hpp @@ -202,7 +202,7 @@ namespace engine { public: virtual ~BufferStage() { } ///< this is an interface - virtual ID defineBufferType (size_t, TypeHandler) =0; + virtual ID defineBufferType (size_t, TypeHandler =TypeHandler::RAW, LocalTag =LocalTag::UNKNOWN) =0; virtual ID lookup (HashVal) =0; virtual ID mark_locked (ID typeKey, Buff*, LocalTag) =0; virtual ID mark_emitted (HashVal stateKey) =0; diff --git a/src/steam/engine/buffer-proxy-adaptor.hpp b/src/steam/engine/buffer-proxy-adaptor.hpp index 39ec4d449..91bad8bfb 100644 --- a/src/steam/engine/buffer-proxy-adaptor.hpp +++ b/src/steam/engine/buffer-proxy-adaptor.hpp @@ -29,7 +29,9 @@ #include "lib/meta/util.hpp" //#include "lib/hash-value.h" #include "steam/engine/buffer-provider.hpp" -#include "steam/engine/buffer-metadata.hpp" +#include "steam/engine/buffer-provider-setup.hpp" +#include "steam/engine/heap-mem-buffer-store.hpp" +#include "steam/engine/simple-buffer-state-registry.hpp" //#include "steam/engine/engine-ctx.hpp" //#include "steam/engine/type-handler.hpp" //#include "steam/engine/buffer-local-tag.hpp" @@ -67,64 +69,91 @@ namespace engine { : util::NonCopyable { - using Listener = std::function; - - class ForwardingBufferProvider - : public BufferProvider /////////////////////////////////////////////////////////////TICKET #1410 : its clear now (2/26) that this must be some other base type; maybe we'll offer the ability to decorate, directly through BufferProviderSetup? + class PreRiggedBufferStage + : public SimpleBufferStateRegistry { - Listener listener_; - -#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to while BufferProvider is being refactored... - /* === BufferProvider API === */ - - uint - prepareBuffers (uint, HashVal) override - { - NOTREACHED ("this part of the API should not be used"); - return 1; // can not sensibly do anything for "pre-allocation", - } // other than telling the caller that we only "have one buffer to provide" - - BuffHandle - provideLockedBuffer (HashVal typeID) override - { - /////////////////////////////////////////////////////////////////////////////////////TICKET #1387 : BufferProvider default impl. is lacking means to compose and delegate -// return buildHandle (typeID, asBuffer(newBlock.accessMemory()), &newBlock); - } - - void - mark_emitted (HashVal, LocalTag const&) override - { - - } - - void - detachBuffer (HashVal, LocalTag const&, Buff&) override - { - - } -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code public: - ForwardingBufferProvider (Listener listener) - : BufferProvider{} - , listener_{std::move (listener)} + PreRiggedBufferStage() + : SimpleBufferStateRegistry{"ResourceProxy"} { } }; - ForwardingBufferProvider passThroughProvider_; + class ProxyBufferStore + : public BufferProviderSetup::Store + { + Buff* + asBuffer (LocalTag targetMarker) + { + void* buffMem{targetMarker}; + return static_cast (buffMem); + } + + uint + prepareBuffers (uint,size_t,HashVal) override + { + WARN (engine, "Announce invoked on a Proxy Buffer Provider; " + "Implies misuse as generic BufferProvider"); + return 1; + } + + Slot + provideBuffer (size_t,HashVal, LocalTag targetMarker) override + { + TODO ("invoke LOCK callback"); + return {asBuffer(targetMarker), targetMarker}; + } + + void + mark_emitted (size_t,HashVal, LocalTag const&) override + { + TODO ("invoke EMIT callback"); + } + + void + detachBuffer (size_t,HashVal,Slot) override + { + TODO ("invoke RELEASE callback"); + } + + }; + + class PassThroughBufferProvider + : public BufferProviderSetup + { + + public: + PassThroughBufferProvider () + : BufferProviderSetup{*this} + { } + + auto buildStage() { return std::make_unique(); } + auto buildStore() { return std::make_unique(); } + + BuffDescr + registerBuffer (void* buff, size_t siz) + { + REQUIRE (siz); + REQUIRE (buff); + auto& typeKey = bufferStage_->defineBufferType (siz, TypeHandler::RAW, LocalTag(buff)); + return buildDescriptor (typeKey); + } + }; + + PassThroughBufferProvider proxyProvider_; public: - template> - BufferProxyAdaptor (LIS&& listener) - : passThroughProvider_{std::forward (listener)} + BufferProxyAdaptor() + : proxyProvider_{} { } template BuffHandle lockBuffer (TAR& dataBlock) { - //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1387 : impossible due to inner contradictions in BufferProvider and OutputSlot - UNIMPLEMENTED ("setup type handler and then create a locked BuffHandle"); + BuffDescr buffType = proxyProvider_.registerBuffer(&dataBlock, sizeof(TAR)); + ENSURE (buffType.isValid()); + return buffType.lockBuffer(); } }; diff --git a/src/steam/engine/diagnostic-buffer-provider.cpp b/src/steam/engine/diagnostic-buffer-provider.cpp index ef3ab2f93..ff82a658d 100644 --- a/src/steam/engine/diagnostic-buffer-provider.cpp +++ b/src/steam/engine/diagnostic-buffer-provider.cpp @@ -166,9 +166,9 @@ namespace engine { } ID - defineBufferType (size_t buffSiz, TypeHandler handlerFunctions) + defineBufferType (size_t buffSiz, TypeHandler handlerFunctions, LocalTag localTag) { - return stage_->defineBufferType (buffSiz, move(handlerFunctions)); + return stage_->defineBufferType (buffSiz, move(handlerFunctions), localTag); } ID diff --git a/src/steam/engine/simple-buffer-state-registry.hpp b/src/steam/engine/simple-buffer-state-registry.hpp index 20a4e0985..0d606e1cf 100644 --- a/src/steam/engine/simple-buffer-state-registry.hpp +++ b/src/steam/engine/simple-buffer-state-registry.hpp @@ -70,9 +70,9 @@ namespace engine { } ID - defineBufferType (size_t buffSiz, TypeHandler handlerFunctions) + defineBufferType (size_t buffSiz, TypeHandler handlerFunctions, LocalTag localTag) { - return lookup (metadata_.key (buffSiz, move (handlerFunctions))); + return lookup (metadata_.key (buffSiz, move (handlerFunctions), localTag)); } // deliberately: create storage, and return reference to it ID diff --git a/tests/core/steam/engine/output-proxy-provider-test.cpp b/tests/core/steam/engine/output-proxy-provider-test.cpp index 2608976eb..c59484a3d 100644 --- a/tests/core/steam/engine/output-proxy-provider-test.cpp +++ b/tests/core/steam/engine/output-proxy-provider-test.cpp @@ -49,13 +49,8 @@ namespace test { { size_t seenID{0}; BufferState lastState{NIL}; - auto listener = [&](size_t id, BufferState state) - { - seenID = id; - lastState = state; - }; // setup with notification callback - BufferProxyAdaptor proxPro{listener}; + BufferProxyAdaptor proxPro{}; // Assuming some data block is »given« seedRand(); diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 1cd6fc7d1..2bc700a06 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -104865,7 +104865,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -104880,7 +104880,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -105062,7 +105062,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + @@ -112341,8 +112342,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) 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 nicht passiert

- -
+
@@ -112362,8 +112362,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) siehe test-tracking-test.cpp

- - +
@@ -113381,8 +113380,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) In der Tat hatte ich nämlich die beiden Protokolle nicht im Zusammenhang entworfen, durchdacht und implementiert, und auch die Parallelen im Ablauf sind mir kaum aufgefallen (nur so ein Gefühl, daß das nach einem etablierten Schema läuft). Da ich überhaupt nie bis zu dem Punkt gekommen bin, Daten ausgeben zu müssen (ich hab ja nicht einmal die Nodes gebaut bekommen, sondern nur einige sehr elaborierte Mocks gebaut), ist mir auch nie aufgefallen, daß man ja aus der Engine heraus diesen Lebenszyklus anstoßen muß. Ich dachte mir vermutlich bloß, "das wird dann der StateProxy schon richten" (den hatte ich mir ja als Blanko-Adapter eingebaut, um überhaupt vom Boden wegzukommen)

- - +
@@ -113589,8 +113587,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + @@ -113613,8 +113610,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Es ist überhaupt nicht klar, wie nütztlich tatsächlich die Möglichkeit wäre, Objekte in Bufer zu pflanzen. Ich selber natürlich würde das exzessiv nutzen und könnte mir vorstellen, da massiv darauf aufzubauen, um das Library-Binding zu systematisieren. Da das Thema aber immer noch sehr weit weg liegt, kann ich kaum einschätzen, ob mir da andere Leute folgen würden mit dem Ansatz

- - +
@@ -113624,8 +113620,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ...das gilt zwar auch für das schon bestehende API, aber bei diesem muß man direkt zusammen mit dem TypeHandler auch einen Size-Parameter angeben

- -
+ @@ -113642,8 +113637,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ...und in dem Fall wäre sogar automatisch für die richtige Vererbungs-Ordnung zwischen den Typen gesorgt

- - +
@@ -113653,8 +113647,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ...abgesehen davon, daß wir einen Buffer-Descriptor speichern, und diesem dann viele Einzelbuffer zuordnen können. Aber der Umstand, daß zwei reine Buffer-Typen untereinander verknüpft sind, wirkt sich (im bisher gegebenen Design-Horizont) überhaupt nirgends aus.

- -
+
@@ -113665,8 +113658,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Hier denke ich an den Fall, daß duch dieses Feature nun einige Fälle hierarchisch dargestellt werden, andere Fälle aber weiterhin nicht. Das stellt zwar kein tatsächliches Problem dar (weil die Hierarchie egal ist, derzeit).

- - + @@ -113677,8 +113669,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Das heißt konkret: die beiden beschriebenen Fälle landen beim gleichen Buffer-Type, und der ist tatsächlich immer hierarchisch. Selbst wenn man alles »auf einen Schuß« angegeben hat; denn wir speichern stets zuerst einen generischen Key nur mit der Size.

- - +
@@ -113689,8 +113680,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) das heißt: diese Betrachtung spricht sogar für dieses Feature

- - + @@ -113698,8 +113688,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ...man macht also etwas für den user explizit sichtbar, was intern sowiso passiert.

- -
+
@@ -113722,8 +113711,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) es ist eine Lüge des Zeitgeitstes, daß es nur um »Probleme lösen« ginge

- - +
@@ -113737,8 +113725,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) es geht hier nur um die Syntax

- - + @@ -113749,8 +113736,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) noch genauer: ich halte diese eine Variante für erstrebenswert

- - +
@@ -113760,8 +113746,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ....also die vorgegebene Systematik einer Library noch einpacken in Marker-Typen, und dann sogar noch spezielle Strukturen im Buffer anlegen

- -
+
@@ -113771,8 +113756,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) das ist meine Vorstellung — und gründet nicht in Erfahrung

- -
+ @@ -113780,8 +113764,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Ich habe nämlich selber noch nie mehr mit irgend einer Media-handling-Library gearbeitet, über kleine Beispiele und etwas Verwenden der Lib-Soundfile hinausgehend. Ich hab mir nur die Doku und Beipsiele der großen Libs mal angeschaut, und hatte dann das Gefühl, daß ich weiß wie der Hase läuft (und außerdem, daß ich nicht den Kern von Lumiera um solche Libraries herumbauen möchte, keine einzige von denen überzeugt mich, ich würde es nicht so machen wie "die". Beachte die Überheblichkeit meinerseits).

- -
+
@@ -113802,8 +113785,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + + @@ -113886,13 +113869,12 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) will sagen, hier nicht »nach den Sternen greifen« — wir wollen kein generisches Diagnose-Tool, das dann später mal für reale Output-Sinks brauchbar wäre (das ist mutmaßlich gar nicht möglich)

- - +
- + @@ -113970,7 +113952,13 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + + + + + @@ -113985,6 +113973,383 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + + +

+ Ich bin da immer wieder von Scala „verdorben“ : dort kann man wunderbar ad hoc eine kleine eingebettete Konfigurationssprache schaffen, da man lokale Bindings leicht überall hin transportieren kann. Aber C++ ist in der Hinsicht sehr defensiv und rigide gestaltet. Das ist auch gut so, denn es gibt keinen Garbage Collector, also kann man auch nich mal eben ein Objekt in die Luft werfen. +

+ +
+
+ + + + +

+ in der Tat: man rennt hier gegen die compile-time-Barrier +

+ +
+ + + +

+ Meta-Processing passiert im Compiler und resultiert in einer Typ-Definition. Dieses kann sich niemals auf Zustand zur Laufzeit beziehen. Man kann das maximal bis an den Punkt dehnen, wo ein neuer Typ zum Zeitpunkt der Instantiierung geschaffen wird. Weiter kommt man niemals. Meistens kommt man damit aber trotzdem über die Runden, da die Instantiierung auch eine Lambda-Funktion als Argument bekommen kann. Dann wird der resultierende Typ jedoch komplett generisch. Auch daran führt kein Weg vorbei +

+ +
+
+ + + + + + + +

+ ...weil ich dann dort eine noch speziellere Situation vorgefunden habe, und dafür ein äußterst komplexes und präzises Gebilde gebaut habe, das in diesem streng abgesteckten Rahmen adäquat ist. Im Grunde habe ich hier nicht vorgesehen, daß Client-Code dieses Framework verwendet, sondern in der Regel durch die bereitgestellten Front-ends geht. Aber prinzipiell wäre dieser Konfigurations-Builder auch für Client-Code offen +

+ +
+ +
+
+ + + + + + + + + +

+ ...weil sie erhebliche Komplexitäten völlg gradlinig löst, ohne dabei erstichlich zu »rudern«;
das ist aber nicht die Art von »Eleganz«, die sich durch "alles passiert von selber richtig" auszeichnet — also nichts für die Freunde von »Zen« (was auch immer die unter "Zen" verstehen wollen9 +

+ +
+
+ + + + +

+ Am Ende bekommt der äußere ThreadLifecycle - Konstruktor eine Instanz dieses Builders, initialisiert erst alle Basis-Klassen, und ruft dann das Lambda in dem Builder auf, aus dem Konstruktor-Rump. Ganz innen im Lambda befindet sich eine Funktion, die den Thread startet. Aber oben drüber werden beliebig viele Dekorator-Schichten gelegt +

+ +
+
+
+
+
+ + + + + + + +

+ wobei hier nicht die typische Situation für Library-Code vorliegt: es ist nicht zu erwarten, daß diese Einrichtung in großer Breite und zum Schaffen einer Abstraktion eingesetzt wird. Vielmehr handelt es sich um ein Baukasten-System, das die zu erwartenden 3-5 Anwendungen hoffentlich auf ein gemeinsames Schema bringt und etwas zugänglicher macht +

+ +
+
+ + + + + + + + + + + + + + + + +

+ vor allem Flexibilität und Segregation; ohne diesen Fokus zu ändern ist hier keine Verbesserung möglich +

+ +
+ +
+
+ + + + + + + + +

+ besteht nur aus zwei unique-Ptr, die die PImpls halten +

+ +
+
+
+
+ + + + + + +

+ BuffHandle handle = proxPro.lockBuffer (dataBlock) +

+ +
+
+ + + + +

+ Das war eine Einsicht beim Konstruieren der neuen Render-Node-Implementierung. Siehe MediaWeavingPattern::shed (Feed& feed, TurnoutSystem&, OptionalBuff outBuff) +

+

+ +

+

+ Wir benötigen den Ausgabepuffer nur an einer einzigen Stelle auf top-Level. Dorthin wird er direkt als Aufrufparameter eingebracht, in einem optional<BuffHandle>. Wir brauchen also bloß ein BuffHandle »auf die Faust« +

+ +
+ +
+ + + + + + + + + + +

+ also ohne vorher überhaupt erst einen Buffer-Descriptor anzulegen; dieser wird vielmer on-the-fly erzeugt (bzw. wiedergefunden, wenn es ihn in der Registry schon gibt) +

+ +
+
+ + + + +

+ man würde eine alternative Implementierung machen für lockBuffer +

+ +
+
+ + + + + +

+ er würde alle Aufrufe als NOP implementieren, ggfs. Exceptions werfen +

+ +
+
+ + + + + +

+ und sofern man den Zugrif auf die Metadaten regelt, hätte man hier den gesamten State (und jeder Client bekommt einen separaten Key) +

+ +
+
+ + + + + + + + + + + + + + +

+ hierbei würde ein spezielle Sub-Typ erzeugt, der bereits mit einem LocalTag für eine bestimmte Buffer-Adresse markiert ist. In einer Output-Komponente, die einen Satz von Buffern zur Verfügung hat (z.B. Double-Buffering), wären das eben nur die tatsächlich bekannten und vorhandenen Buffer +

+ +
+
+ + + + +

+ sie beruht auf einer internen Zusatz-Konvention: den Inhalt des LocalTag als Buffer-Adresse wieder herauszugeben +

+ +
+
+ + + + +

+ Vorausgesetzt, die Metadaten sind Threadsafe, dann verbieten sie, einen konkreten Entry anzulegen, wenn es genau diesen bereits gibt (weil ein anderer Client exakt diesen Buffer-Typ incl. LocalTag gesperrt hat) +

+ +
+
+ + + + + + + + +

+ das würde tatsächlich bereits genügen, um dieses Feature umzuseten, denn die interne Implementierung erzeugt (seit der Überarbeitung 2024) bereits automatisch kaskadierte Datentypen in einer standardisierten Reihenfolge. Man würde also jeweils einen neuen BufferType anlegen, der aber ggfs automatisch unter einem Basis-Typ einsortiert wird. +

+ +
+
+ + + + +

+ Hierfür würde sprechen, daß es sich, logisch betrachtet, eben um separate »refining«-Schritte handelt, undman das direkt auf dem Implementierungs-API ausdrückt (anstatt sich auf eine clevere Implementierung zu verlassen) +

+ +
+
+
+ + + + +

+ ...und im Besonderen noch nicht geklärt ist, welche Bedeutung diesen hierarchischen Typen überhaupt zukommt. +

+ +
+ + + + +

+ Stattdessen soll man immer einen neuen Typ anlegen, der ja implizit eine Qualifizierung in bis zu zwei Schritten macht. Zudem spielt die hierarchische Struktur der Buffer-Types derzeit effektiv keine Rolle. +

+ +
+
+ + + + +

+ ...derzeit sind sie das nicht, sondern sind nur potentiell gefährlich, da für eine bestimmte Adresse zwei Registrierungen gemacht werden könnten.  In der derzeitigen Ausgestaltung des BufferProvider ist das allerdings nicht möglich, da lockBuffer stets von einem bestimmten Buffer-Descriptor ausgeht. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +

+ ...und kann aber keinen rechten Grund finden, es zu rechtfertigen.... +

+ + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + +

+ was ich hier mache ist Implementation-Reuse, und nicht das Verwenden eines Kontrakts. Wenngleich auch alle Aspekte des Kontrakts formal erfüllt sind +

+ +
+
+
+
+ + + + + + + + + + + + + + + + + +
@@ -114693,8 +115058,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) 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.

- - +
@@ -114704,8 +115068,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) 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

- -
+
@@ -114715,8 +115078,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ....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

- -
+
@@ -114726,8 +115088,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) 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 und direkt in diesem eine Verwaltungsstruktur mitführt

- -
+
@@ -114737,8 +115098,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Dadurch entsteht auch ein Hebel, so daß der Speicher für diese Metadaten-Records selber sehr gut auf das Kachel-Schema paßt

- -
+
@@ -114761,8 +115121,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) besonders wichtig: Metadaten wandern über Threadgrenzen

- - +
@@ -114776,8 +115135,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -114807,8 +115166,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) 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

- - +
@@ -134454,8 +134812,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) konkret, überstehen wir einen 10-Stunden-Render unter Druck (whatever it takes)?

- - +