diff --git a/src/steam/engine/buffer-metadata.hpp b/src/steam/engine/buffer-metadata.hpp index dfc70c647..3967b2e38 100644 --- a/src/steam/engine/buffer-metadata.hpp +++ b/src/steam/engine/buffer-metadata.hpp @@ -43,8 +43,6 @@ ** once we have to build a metadata store that works well in a massively ** concurrent environment, where requests for state transition emanate ** any time form within all worker threads! - ** @todo 2/2026 Do we really have to _store_ the actual buffer address into the - ** metadata::Entry, as opposed to just using this information for hash computation? ** ** @see buffer-provider.hpp ** @see BufferMetadata_test @@ -277,6 +275,9 @@ namespace engine { * instance. For the latter, Entry serves as representation and access point * to the individual metadata; this includes using the TypeHandler for * building and destroying buffer structures. + * + * @remark 2/2026 the plan is to use this entry beyond metadata handling + * and especially to describe a buffer within a layered allocator */ class Entry : public Key diff --git a/src/steam/engine/buffer-provider.cpp b/src/steam/engine/buffer-provider.cpp index c5d52812d..e8f6067e6 100644 --- a/src/steam/engine/buffer-provider.cpp +++ b/src/steam/engine/buffer-provider.cpp @@ -140,6 +140,10 @@ namespace engine { * the client should be prepared for exceptions. The #announce operation allows * to establish a reliably available baseline. * @todo 2/2025 might need to accept a cache key as additional parameter //////////////////////////////////TICKET #1392 : get cache key from computation to the cache backend + * @todo 2/2026 my intention is to use metadata::Entry within a threadsafe allocator + * to pass buffers around. For this to be possible, buffer-metadata.hpp needs + * some refactoring, and then the BufferStore::provideBuffer would have to + * return a metadata::Entry */ BuffHandle BufferProvider::lockBuffer (BuffDescr const& type) diff --git a/src/steam/engine/buffer-proxy-provider.hpp b/src/steam/engine/buffer-proxy-adaptor.hpp similarity index 72% rename from src/steam/engine/buffer-proxy-provider.hpp rename to src/steam/engine/buffer-proxy-adaptor.hpp index 3852f924b..39ec4d449 100644 --- a/src/steam/engine/buffer-proxy-provider.hpp +++ b/src/steam/engine/buffer-proxy-adaptor.hpp @@ -1,8 +1,8 @@ /* - BUFFER-PROXY-PROVIDER.hpp - Adapter to access existing allocation via buffer handling protocol + BUFFER-PROXY-ADAPTOR.hpp - Adaptor to access existing allocation via buffer handling protocol Copyright (C) - 2024, Hermann Vosseler + 2024,2026 Hermann Vosseler   **Lumiera** is free software; you can redistribute it and/or modify it   under the terms of the GNU General Public License as published by the @@ -11,17 +11,17 @@ */ -/** @file buffer-proxy-provider.hpp +/** @file buffer-proxy-adaptor.hpp ** Adapter to expose a given memory block through a BuffHandle. - ** This allows to integrate a specific data access (e.g. related to input / output) - ** with the buffer lifecycle protocol as defined by BufferProvider. + ** This implementation building-block allows to integrate some specific data access + ** (e.g. related to input / output) through the buffer lifecycle protocol as defined by BufferProvider. ** @todo BROKEN as of 12/2024 //////////////////////////////////////////////////////////////////////////////TICKET #1387 : can not properly compose BufferProvider ** @see output-slot.hpp ** @see output-proxy-provider-test.cpp */ -#ifndef STEAM_ENGINE_BUFFER_PROXY_PROVIDER_H -#define STEAM_ENGINE_BUFFER_PROXY_PROVIDER_H +#ifndef STEAM_ENGINE_BUFFER_PROXY_ADAPTOR_H +#define STEAM_ENGINE_BUFFER_PROXY_ADAPTOR_H #include "lib/error.hpp" @@ -51,11 +51,19 @@ namespace engine { /** - * Adapter to expose access to data blocks via BuffHandle and the BufferProvider protocol. - * @todo WIP-WIP 12/2024 this is a design sketch to explore extension capabilities of BufferProvider - * @todo 2/2026 broken by refactoring of BufferProvider //////////////////////////////////////////////TICKET #1410 : refactoring to separate external and implementation API + * Adapter to expose access controlled access to some memory resource + * through a [»Buffer Type«](\ref BuffDescr) and a BuffHandle as front-end, + * in accordance with the BufferProvider protocol. + * + * This template is an implementation building block and needs to be instantiated + * with a policy or configuration to define the flexible parts of the behaviour + * - what a Buffer Type means + * - is there only one resource or is this setup statefull? + * - callback functors for the lifecycle stages related to the client's access + * @todo WIP-WIP 2/2026 used as prototype to forge a path ahead to resolve + * the structural problems with OutputSlot vs. BufferProvider ///////////////////////////////////////TICKET #1415 : prototyping to resolve structural mismatch between OutputSlot / DataSink / BufferProvider */ - class BufferProxyProvider + class BufferProxyAdaptor : util::NonCopyable { @@ -106,8 +114,8 @@ namespace engine { public: - template> - BufferProxyProvider (LIS&& listener) + template> + BufferProxyAdaptor (LIS&& listener) : passThroughProvider_{std::forward (listener)} { } @@ -130,4 +138,4 @@ namespace engine { }} // namespace steam::engine -#endif /*STEAM_ENGINE_BUFFER_PROXY_PROVIDER_H*/ +#endif /*STEAM_ENGINE_BUFFER_PROXY_ADAPTOR_H*/ diff --git a/src/steam/engine/buffer-proxy-provider.cpp b/src/steam/engine/buffer-proxy-provider.cpp deleted file mode 100644 index f26628109..000000000 --- a/src/steam/engine/buffer-proxy-provider.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - BufferProxyProvider - Adapt existing allocation for access through the Buffer protocol - - Copyright (C) - 2024, Hermann Vosseler - -  **Lumiera** is free software; you can redistribute it and/or modify it -  under the terms of the GNU General Public License as published by the -  Free Software Foundation; either version 2 of the License, or (at your -  option) any later version. See the file COPYING for further details. - -* *****************************************************************/ - - -/** @file buffer-proxy-provider.cpp - ** Implementation details of a forwarding BufferProvider stub implementation. - */ - - -#include "lib/error.hpp" -#include "steam/engine/buffer-proxy-provider.hpp" -//#include "steam/engine/buffer-metadata.hpp" -//#include "lib/util.hpp" - -//using util::isSameAdr; - -namespace steam { -namespace engine { - - // storage for the default-marker constants -// const TypeHandler TypeHandler::RAW{}; - - - namespace { // impl. details and definitions - -// const uint DEFAULT_DESCRIPTOR = 0; - - } - - - /** build a new - */ -// BufferProvider::BufferProvider (Literal implementationID) -// : meta_(new BufferMetadata (implementationID)) -// { } -// -// BufferProvider::~BufferProvider() { } - - - /** @internal verify the given descriptor. - */ - - - -}} // namespace engine diff --git a/src/steam/engine/type-handler.hpp b/src/steam/engine/type-handler.hpp index d20055dac..097cef335 100644 --- a/src/steam/engine/type-handler.hpp +++ b/src/steam/engine/type-handler.hpp @@ -77,8 +77,8 @@ namespace engine { HashVal hash{0}; boost::hash_combine (hash, typeid(CTOR).hash_code()); boost::hash_combine (hash, typeid(DTOR).hash_code()); - return hash; - } + return hash; ////////////////////////////////////////////////////////////////////////////TICKET #1411 : this qualification fails to distinguish different bindings of the same type + } ///////////////// (notably different constructor argument values for the same class type to emplace) }//(End)placement-new helpers diff --git a/tests/core/steam/engine/node-base-test.cpp b/tests/core/steam/engine/node-base-test.cpp index 663f28524..0c6a639e0 100644 --- a/tests/core/steam/engine/node-base-test.cpp +++ b/tests/core/steam/engine/node-base-test.cpp @@ -283,7 +283,7 @@ namespace test { // and get a new buffer to capture the output BuffHandle buffOut = provider.lockBufferFor (-99); CHECK (buff.accessAs() == r1); - CHECK (buffOut.accessAs() == -55); ///////////////////////////////////////OOO should be -99 --> aliasing of buffer meta records due to bug with hash generation + CHECK (buffOut.accessAs() == -55); /////////////////////////////////////////////////////////TICKET #1411 : should be -99 --> aliasing of buffer meta records due to bug with hash generation // configure the Manifold-2 with this input and output buffer m2.inBuff.createAt (0, buff); @@ -291,13 +291,13 @@ namespace test { CHECK (m2.inBuff[0].isValid()); CHECK (m2.inBuff[0].accessAs() == r1 ); CHECK (m2.outBuff[0].isValid()); - CHECK (m2.outBuff[0].accessAs() == -55); ////////////////////////////////OOO should be -99 + CHECK (m2.outBuff[0].accessAs() == -55); //////////////////////////////////////////////////TICKET #1411 : should be -99 // connect arguments to buffers m2.connect(); CHECK (isSameAdr (m2.inArgs, buff.rawStorage())); CHECK (isSameAdr (m2.outArgs, buffOut.rawStorage())); - CHECK (*m2.outArgs == -55); ////////////////////////////////OOO should be -99 + CHECK (*m2.outArgs == -55); //////////////////////////////////////////////////TICKET #1411 : should be -99 m2.invoke(); CHECK (buffOut.accessAs() == r1+1); @@ -335,12 +335,12 @@ namespace test { BuffHandle buffI2 = provider.lockBufferFor (-22); CHECK (buffI0.accessAs() == r1 ); // (result from Example-1) CHECK (buffI1.accessAs() == r1+1); // (result from Example-2) - CHECK (buffI2.accessAs() == -55 ); ///////////////////////////////////////OOO should be -22 + CHECK (buffI2.accessAs() == -55 ); /////////////////////////////////////////////////////////TICKET #1411 : should be -22 // prepare a compound buffer and an extra buffer for output... BuffHandle buffO0 = provider.lockBufferFor (Sequence{-111,-222,-333}); BuffHandle buffO1 = provider.lockBufferFor (-33); CHECK ((buffO0.accessAs() == Sequence{-111,-222,-333})); - CHECK (buffO1.accessAs() == -55 ); ///////////////////////////////////////OOO should be -33 + CHECK (buffO1.accessAs() == -55 ); /////////////////////////////////////////////////////////TICKET #1411 : should be -33 // configure the Manifold-3 with these input and output buffers m3.inBuff.createAt (0, buffI0); @@ -355,20 +355,20 @@ namespace test { auto& [o00,o01,o02] = *oa0; CHECK (*ia0 == r1 ); CHECK (*ia1 == r1+1); - CHECK (*ia2 == -55 ); /////////////////////////////////////////////////////OOO should be -22 + CHECK (*ia2 == -55 ); ///////////////////////////////////////////////////////////////////////TICKET #1411 : should be -22 CHECK ( o00 == -111); CHECK ( o01 == -222); CHECK ( o02 == -333); - CHECK (*oa1 == -55 ); /////////////////////////////////////////////////////OOO should be -33 + CHECK (*oa1 == -55 ); ///////////////////////////////////////////////////////////////////////TICKET #1411 : should be -33 m3.invoke(); CHECK (*ia0 == r1 ); // Input buffers unchanged CHECK (*ia1 == r1+1); - CHECK (*ia2 == -55 ); /////////////////////////////////////////////////////OOO should be -22 + CHECK (*ia2 == -55 ); ///////////////////////////////////////////////////////////////////////TICKET #1411 : should be -22 CHECK ( o00 == *ia0+1); // Output buffers as processed by the function CHECK ( o01 == *ia1+1); CHECK ( o02 == *ia2+1); - CHECK (*oa1 == -55 + *ia0+*ia1+*ia2); ///////////////////////////////////////////OOO should be -33 + CHECK (*oa1 == -55 + *ia0+*ia1+*ia2); /////////////////////////////////////////////////////////////TICKET #1411 : should be -33 //_________________________________ @@ -407,12 +407,12 @@ namespace test { m4.outBuff.createAt(0, buffO1); CHECK (*ia0 == r1 ); // existing values in the buffers.... CHECK (*ia1 == r1+1); - CHECK (*ia2 == -55 ); /////////////////////////////////////////////////////OOO should be -22 - CHECK (*oa1 == -55 + *ia0+*ia1+*ia2); ///////////////////////////////////////////OOO should be -33 + CHECK (*ia2 == -55 ); ///////////////////////////////////////////////////////////////////////TICKET #1411 : should be -22 + CHECK (*oa1 == -55 + *ia0+*ia1+*ia2); /////////////////////////////////////////////////////////////TICKET #1411 : should be -33 m4.connect(); m4.invoke(); // processing combines input buffers with parameters - CHECK (*oa1 == (r2+r3) * (r1 + r1+1 -55)); /////////////////////////////////////OOO should be -22 + CHECK (*oa1 == (r2+r3) * (r1 + r1+1 -55)); ///////////////////////////////////////////////////////TICKET #1411 : should be -22 //______________________________________ diff --git a/tests/core/steam/engine/output-proxy-provider-test.cpp b/tests/core/steam/engine/output-proxy-provider-test.cpp index 3e5118e4c..2608976eb 100644 --- a/tests/core/steam/engine/output-proxy-provider-test.cpp +++ b/tests/core/steam/engine/output-proxy-provider-test.cpp @@ -19,7 +19,7 @@ #include "lib/test/run.hpp" //#include "steam/play/diagnostic-output-slot.hpp" -#include "steam/engine/buffer-proxy-provider.hpp" +#include "steam/engine/buffer-proxy-adaptor.hpp" #include "steam/engine/test-rand-ontology.hpp" @@ -40,6 +40,7 @@ namespace test { * @todo 2/2026 broken by refactoring of BufferProvider //////////////////////////////////////////////TICKET #1410 : refactoring to separate external and implementation API * @todo however, something along this lines *must* * be made possible, somehow, for OutputSlot... + * @todo 2/2026 now using this setup for prototyping /////////////////////////////////////////////////TICKET #1415 : explore this design idea through prototyping */ class OutputProxyProvider_test : public Test { @@ -54,7 +55,7 @@ namespace test { lastState = state; }; // setup with notification callback - BufferProxyProvider proxPro{listener}; + BufferProxyAdaptor proxPro{listener}; // Assuming some data block is »given« seedRand(); diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index a9afb091e..1cd6fc7d1 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -100099,6 +100099,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + @@ -110348,7 +110352,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -111035,6 +111039,10 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + @@ -111965,12 +111973,20 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - - + + + + + + + - + + + + + @@ -111978,6 +111994,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + @@ -112035,6 +112054,10 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + @@ -112257,8 +112280,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + + @@ -112294,13 +112317,14 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + - + + - + @@ -112311,9 +112335,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 @@ -112330,12 +112352,11 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + - - - +

siehe test-tracking-test.cpp @@ -112348,17 +112369,24 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + - - + + + + + + + @@ -112380,8 +112408,11 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + + + + + @@ -113222,12 +113253,184 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + + + + + + + + + + +

+ Somit sind wir in exakt der gleichen Situation wie mit dem DiagnosticBufferProvider, und mutmaßlich ist auch die Problemlage dieselbe (mehr noch, ich kann mich noch erinnern, daß ich mir 2013 die Arbeit leicht machen wollte, indem ich die BufferProvider-Implementierung etwas dekoriere und durchreiche) +

+ +
+
+ + + + +

+ Und zwar mit der Technologie, die wir letzten Sommer für die FrOSCon recherchiert und vorgestellt haben; es passiert also hoffentlich sehr bald und definitiv noch in diesem »Vertical Slice«. Jedwede Aufräum-Arbeit in diesem Bereich ist darauf auszurichten +

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

+ "ungültiger Maschinenbefehl" +

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

+ ...so ist das eingebunden; das heißt, das hier ist auch die tatsächliche Implementierung — gleiches Anti-Pattern wie beim HeapMemProvider +

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

+ das heißt, es gibt ein Set aller beobachteten Frame-Nummern, und dazu ein Time-Grid; neue Frames werden über einen »wire-tap«-Aufruf eingespeist, der in der regulären Implementierung sitzt +

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

+ ...fragt sich, warum? +

+
    +
  • + fehlten mir die Fähigkeiten bzw. die Routine und das Selbstvertrauen, so etwas in absehbarer Zeit hochzuziehen? (durchaus plausibel) +
  • +
  • + hatte ich ein Schlechtes Gewissen, weil dieser Scheiß so aufwendig wird? (sehr plausibel im Rückblick auf die Historie des Projekts) +
  • +
  • + hab ich es so zusammengedengelt, weil ich mich daran erinnern kontne, vor einem Jahr etwas Ähnliches schon mal zusammengedengelt zu haben? (möglich, würde die kognitive Dissonanz mildern) +
  • +
+ +
+
+ + + + +

+ Diesen Schluß kann ich ziemlich sicher aus meinem eigenen Code ziehen (ich weiß ja, wie ich ticke).... +

+

+ 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) +

+ + +
+
+ + + + +

+ Auf dem Weg einer systematischen Analyse wäre ich (mein typisches Mindset zugrunde gelegt) niemals darauf gekommen, diese Kongruenz zwischen den Interfaces zu sehen. Erfahrungsgemäß finde ich solche Dinge immer erst durch eine extrem mühsame Empirie, viel Aufräumen, und unvorstellbar langwierige Reflexionen. Das alles ist mir hier erstpart geblieben +

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

+ es stellt sich sofort die Aufgabe: +

+

+ wie baut man einen Proxy-Buffer-Store ? +

+ +
+ + + +
+ + + + +
@@ -113324,13 +113527,335 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
- + - + + + + + + + + + + + + + + + + + + + + + + + + + +

+ wirklich selbsterklärend wäre nur: buffDescr.adapt<TY>(args...) +

+ +
+ + + +

+ ...das hätte aber den Nachteil, daß dann der Header buffhandle.hpp auch den Header type-handler.hpp anziehen müßte; das ist bisher nicht der Fall. Allerdings für buffer-provider.hpp schon, und so schlimm ist TypeHandler auch wieder nicht, er zieht das Function-Metaprogramming an, was praktisch jeder Header im Engine-Kern tut. +

+ +
+ +
+
+ + + + +

+ Der Fall, den ich im Auge habe: +

+
    +
  • + man befindet sich im Rahmen einer Library, die eine bestimmte Puffergröße vorgibt +
  • +
  • + nun möchte man in Einzelfällen da einen Overlay darüber projizieren, oder im Buffer etwas speziell einrichten (z.B. einen Header konfigurieren) +
  • +
  • + anstatt das durch Hilfsfunktionen im Binding-Code auszudrücken, definiert man Klassen. Das macht den Sachverhalt, explizit, klar, dokumentierbar und testbar +
  • +
+ + +
+
+ + + + + +

+ ...und nützt Einrichtungen, die aus Symmetrie-Gründen schon geschaffen wurden, derzeit aber unbenutzt bleiben; bei sowas besteht die Gefahr, daß später ein Wartungs-Programmierer den ungenutzten Zweig zurückbaut, und dann noch später ein weiterer Wartungs-Programmierer die Symmetrie nicht bemerkt, und ein Desaster anrichtet. Ja, dieses Pattern hab ich mehrfach in meiner Tätigkeit bei der Bank erlebt. +

+ +
+
+
+ + + + + +

+ 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 +

+ + +
+
+ + + + +

+ ...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 +

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

+ ...und in dem Fall wäre sogar automatisch für die richtige Vererbungs-Ordnung zwischen den Typen gesorgt +

+ + +
+
+ + + + +

+ ...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. +

+ + +
+ +
+ + + + +

+ 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). +

+ + +
+ + + + + + +

+ 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. +

+ + +
+ +
+ + + + +

+ das heißt: diese Betrachtung spricht sogar für dieses Feature +

+ + +
+ + + +

+ ...man macht also etwas für den user explizit sichtbar, was intern sowiso passiert. +

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

+ es ist eine Lüge des Zeitgeitstes, daß es nur um »Probleme lösen« ginge +

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

+ es geht hier nur um die Syntax +

+ + +
+ +
+ + + + +

+ noch genauer: ich halte diese eine Variante für erstrebenswert +

+ + +
+
+ + + + +

+ ....also die vorgegebene Systematik einer Library noch einpacken in Marker-Typen, und dann sogar noch spezielle Strukturen im Buffer anlegen +

+ + +
+
+ + + + +

+ das ist meine Vorstellung — und gründet nicht in Erfahrung +

+ + +
+ + + +

+ 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). +

+ + +
+
+ + + + + + + + + + +
    +
  • + das ungelöste Problem #1411 Aliasing von TypeHandler instanzen; ich sehe da keine elegante Lösung... +
  • +
  • + das ganze Design schwebt im luftleeren Raum +
  • +
+ + +
+
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

+ Hab mich davon vorgestern überzeugt: unser Design ist inhärent sicher, solange man explizit von einem Type-Descriptor ein Handle erzeugen muß; denn erst an der Stelle, und nur an der Stelle wird die Speicher-Adresse in den Hash eingerechnet. Es geht hier also ehr um eine Frage der logischen Konsistenz: wir können nicht feststellen, in welcher Relation verschiedene TypeHandler zueinander stehen; daher machen wir sie alle untereinander unvergleichbar +

+ +
+
+
+
+
+
+
+ + + - + @@ -113342,10 +113867,133 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + + + + + +

+ aus Gründen der Konsistenz; das Schema mit einem Zugriffs-Adaptor hat sich bewährt und gefält mir gut +

+ +
+
+ + + + +

+ 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) +

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

+ und auch ein dazu passender Descriptor; beides zusammen verbauen wir ja im Node-Network. +

+ +
+
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -114039,9 +114687,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. @@ -114052,9 +114698,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 @@ -114065,9 +114709,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 @@ -114078,9 +114720,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 @@ -114091,9 +114731,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 @@ -114115,11 +114753,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + - - - +

besonders wichtig: Metadaten wandern über Threadgrenzen @@ -114127,6 +114763,30 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + + + + + + + + + + + + + + + + + + + + + @@ -114141,9 +114801,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 @@ -133701,68 +134359,54 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - - +

Beispiel: es gibt einen Engpaß in der gegebenen Berechnungs-Pipeline; dort werden 10 Blöcke à 10 MiB gebraucht, sowie 10 Blöcke à 1 KiB

- -
+
- - - +

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

- -
+
- - - +

dabei bekommt jeweils der Empfänger die alleinige Verfügungsgewalt über den am Deskriptor hängenden Block

- -
+
- - - +

Denn das wäre vermutlich zu aufwendig (vor allem da es den Code komplex macht).

- -
+
- - - +

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. @@ -133774,8 +134418,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Letztlich lassen sich diese Probleme ohne Empirie nicht adäquat behandeln.

- -
+
@@ -133791,16 +134434,13 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - - +

⟹ hierfür ist ein dedizierter Service-Thread die einfachste Lösung

- -
+
@@ -133808,9 +134448,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - - +

konkret, überstehen wir einen 10-Stunden-Render unter Druck (whatever it takes)? @@ -133823,63 +134461,62 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + + + + + + + + - - - +

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

- -
+
- - - +

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

- -
+ - - - +

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)

- -
+
- - - +

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

- -
+
@@ -133888,6 +134525,53 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+ + + + + + + +

+ Das gilt für Output, für das Starten der Play-Connection, und natürlich für den Builder +

+

+ Alle anderen Komponenten dagegen sind definitv nicht prototypisch, sondern sollen die Grundlage und Integration der echten Engine bilden. +

+ +
+
+ + + + +

+ bis zu diesem Zeitpunkt haben wir stets nur Dummy-Player, Dummy-Generatoren und eine Dummy-Architektur verwendet +

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