Commit graph

349 commits

Author SHA1 Message Date
dd37600c4d BufferProvider: setup implementation structure for the pool
- use boost::lockfree to implement the in-queue with new allocations
- use a std::list with an internal administrative record
- automatically ingest the in-queue prior to accessing the pool
2026-04-25 01:41:49 +02:00
e328018b05 BufferProvider: decision to use a free-standing pool with lock-free queue
After several fruitless attempts, I have decided now
to settle for self-contained ''memory pool'' component,
that can be operated **thread-locally** and employs a
**lock-free** message queue for the allotment of memory.

Seemingly the question of how this relates to `BufferMetadata`
must remain unresolved for the time being, until the entire
buffer memory subsystem is available for empirical investigation.
2026-04-24 22:55:25 +02:00
e277913e22 BufferProvider: start planning for the memory handling part
As staring point, it is clear that the `BufferStore` side of the
implementation will rely on a similar structure with a thread-local
base service — which in this case will have to maintain a small pool
of recently used buffer allocations...
2026-04-21 23:30:35 +02:00
3b7877204d BufferProvider: implement and verify the second case for synchronisation
...which happens when a buffer type is referred for the first time
from within a new worker thread, while it is already stored in the
global registry; the full key-chain is down-synced then.
2026-04-20 19:48:20 +02:00
abecd2cbde BufferProvider: implement locking and data synchronisation
...using the first usage situation as guideline,
and verify proper operation through unit-test

- the LocalBufferStage gets a set of thread-local BufferMetadata
- furthermore, it accesses the central hub via dependency-injection
- after each type registration ''from a worker thread'' data is published

As an asside: ensure most metadata registration can ''move'' the TypeHandler
2026-04-20 01:40:15 +02:00
606d98bf9c BufferProvider: establish a new buffer type from within a worker
This test setup defines one of the problematic situations
where a synchronisation is necessary.

__TODO__: actually add locking and that synchronisation to LocalBufferStage
2026-04-19 19:25:30 +02:00
57cd51e3a2 BufferProvider: draft setup for engine-wide coordination hub
What I am building step by step right now is the first draft
of a production-grade render buffer management scheme.
For this I need suitable implementations of `BufferStag` (and `BufferStore`)
These will include a `LocalSlice` to hold thread-local »satelitte services«,
which in turn need a connection to some central coordination hub.

The thread-local instances can access the hub via our `lib::Depend` (I have just
verified that this works as intended, with on-demand creation of the
central instance on first access from some thread. This is important,
since very likely we need to install a dedicated and speficically wired
service instance, which must happen prior to first dependency-request
via `lib::Depend`. And since the worker-threads are created by the Engine,
we get ample opportunity to do so before starting those threads.

Included in this changeset is a first rough draft of the central registry
`EngineBufferMetadata` — I have modelled it analogous to the `SimpleBufferStateRegistry`,
which is the test-level implementation of the `BufferStage` API.
However, we do not want to expose direct buffer allocation operations
on the central hub, and thus I have left out the respecive parts of the API.

Furthermore, I have added an `abandon()` operation, without there beeing
a need for such an operation right now. But since this operation is tricky
and potentially dangerous, I prefer implementing it the correct way,
since I have a clear understanding what this entails at the moment.
2026-04-19 18:02:58 +02:00
1601838037 BufferProvider: reduce synchronisation effort
The recursive synchronisation up the parent-chain can in most cases be skipped,
by relying on the fact that inconsistent data is never stored in the BufferMetadata
table. If thus an entry is locally present and matches the entry from the
other side, then it can be concluded that its parent must also be already in sync.
2026-04-19 15:14:31 +02:00
c05a73d68a BufferProvider: draft mechanism for buffer metadata synchronisation
Since the intention is to run several thread-local instances of `BufferMetadata`
in a concurrent setup, we need a way to publish and exchange chains of
registered type-keys and metadata entries.

The first step is to develop a mechanic for data exchange,
and to define the rules when such synchronisation is (not) allowed.
2026-04-19 01:21:24 +02:00
8d563d1ea9 BufferProvider: lift the family-ID to the BufferStage level
During the last days, I started with analysis to find a way
to operate the `BufferProvider`, as implemented thus far,
within a massively concurrent environment.

Since I intend to create thread-local caches,
the initialisation of the `BufferMetadata` store must be static.

It turns out that the root-ID, which acts like a mandator ID,
is only used at a single code path, when creating or accessing
an abstract type-Key. It is thus easy to extract and relocate
this distinguishing ID into the actual `BufferStage` implementation.
2026-04-17 19:08:46 +02:00
4dc6885665 BufferProvider: complete the clean-up effort
Looking through all my work notes, it seems that all the
problematic aspects are now solved in a satisfactory way.
 * it is clear how to dependency-inject a `BufferProvider`
 * the internals of the `BufferProvider` front-End have been restructured
 * there are now two ''pillars'' of the implementation: `BufferStage` and `BufferStore`
 * both can be subclassed independently
 * `BufferProviderSetup` exposes a proxying-mechanism (used for `DiagnosticBufferProvider`)
 * the `BufferMetadata` have been reviewed and some minor details were rectified
 * after a re-Design of `OutputSlot`, `BuffHandle` can now be used as unified front-End
 * both `DiagnosticBufferProvider` and `DiagnosticOutputSlot` have been rewritten
 * they are now independent, self-contained specialisations, layered on top

Overall, what might seem like a detour, was an important step towards
well-balanced structures and a better understanding of the Render Engine.
2026-04-14 01:22:55 +02:00
2c8ee05a23 OutputSlot: validate and complete redesign (see #1395)
''This is a breakthrough...''
Using the realigned implementation structure in `BufferProvider`,
and especially the ability to establish an overarching context by
passing an connection-ID through the `LocalTag` in the `BufferMetadata`,
it was possible to resolve the longstanding mismatch buried deep within
the `OutputSlot` implementation.

Based on the new internal APIs in `BufferProvider`, it was thus possible
to setup an `OututBufferProxy` that acts as a hub to connect the
`DataSink` handles with the actual `OutputSlot::Connection` implementation.
This change allowed to rectify the convoluted control structure in
`OutputSlot` and finally to manage the Lifecycle properly. Furthermore,
one level of unnecessary implementation-inheritance could be removed,
so that it is no longer necessary to subclass `OutputSlot` in order to
configure the link to a specific output backend.

Using this redesigned internal structure, it was now fairly simple to
re-implement a tracking `DiagnosticOutputSlot` and then to verify proper
integration by passing the `OutputSlotProtocol_test` again.
2026-04-11 01:45:15 +02:00
a0d83b4fe8 Library: investigate design for an opaque inline functor
This is a design study to find out what would be required
to build an opaque function wrapper, similar to `std::function`,
yet without using any heap memory ever.

Such a building block would allow for some interesting options
for a well structured design of elaborate data structures.

This changeset provides an implementation draft.

__Two important findings to note__:
 * it is impossible to get away with just a single function pointer
 * because at the very least we need to invoke the destructor of the
   embedded delegate. Thus something akin to a "manager" is required.
 * this implies that the component would not be so efficient as I hoped,
   since it requires two pointers and requires to emit code for each
   type of delegate.
 * by making the component **NonCopyable**, I avoided the complexities
   of virtual copy support. In case the latter is desired, it would be
   much simpler to switch to a classical OO approach with a VTable
   and use our `PolymorphicValue` wrapper to handle copy and cloning.
2026-04-08 01:53:53 +02:00
bf77e53b4c BufferProvider: obvious convenience function
...to emplace some object into the buffer space.
I wouldn't expect that to be necessary for the real usage,
but it comes in handy for tests, where we often want to place
some sentinel value into a buffer.
2026-03-24 23:48:13 +01:00
a7c3a8d80d Testsuite: fix breakage
- visible Signature of TestFrame changed due to being relocated into the Vault

- attempt to make the WorkForce_test more robust;
  frequently fails on testsuite run after full build;
  so better ''wait'' for the workers to have started working,
  instead of using a fixed delay (that must be extremely short
  and is hard to predict)
2026-03-24 23:19:05 +01:00
473299fb5a OutputSlot: attempt to address deeply rooted structural problems
This changeset attempts to breach into the implementation design of OutputSlot
(while largely retaining the API and the »Output Slot Protocol«).

While the actual problem that brought me to this point can be traced back to some
rather obvious mistake, namely to conflate the `BufferProvider` used as
backing implementation with a `BufferProvider` used as front-end API,
creating the new connections to use an `OutputBufferProxy` unveils some
further long-standing structural mismatch; notably this leads to the
difficulties to get the lifecylce management of `OutputSlot` and `DataSink`
under control.

So I remove one entire level from the implementation,
in a bold move to realign the design with the prospective usage pattern.

Obviously, this breaks a lot of further code, and I need to rewire
the Allocation implementation altogether, and provide a new functor based
implementation for `DataSink`
2026-03-21 00:51:40 +01:00
9b6933b572 OutputSlot: consider how to integrate the proxy provider
...which still looks like a nasty task
 * the good part is, we have a working `BufferProxyAdaptor` now
 * yet this setup does not seem to fit into the `OutputSlot::AllocState`

As an aside, several test definitions need to be relocated to the Vault,
since the whole compound around `BufferProvider` migrated down
2026-03-17 00:48:08 +01:00
ea0ae5f78e BufferProvider: propagate the actual buffer-size info
This is a nasty new requirement, discovered as an aside while looking
into ways to resolve the ''crucial mismatch'' between the `OutputSlot`
and `BufferProvider`, using the proxy-implementation of `BufferProvider`
(thereby expanding on the recent draft with the `BufferProxyAdaptor`)

The point is, if the BufferMetadata will be used beyond the internal coordination
within BufferProvider, then it will be used as part of actual buffer storage.
And this implies that the actual size of the allocation may differ (be greater)
than the nominally required size (since we'll very likely employ some kind
of memory tiling, for reasons of performance).

This leads again to an analysis of `BufferMetadata` usage,
with the conclusion to add the actual storage size directly into the API,
but treat it as an ''extra'' and not integrated into the ''buffer type''

Phew ... quite complex alltogether
2026-03-16 23:45:24 +01:00
94320d2d23 BufferProvider: remove the lock-onlyNew feature
This might have seemed like a good idea, adding an additional ''consistency check''...
However — we ''do have'' a generic check, insofar `BufferMetadata` is a **state engine**.

As long as we're able to prevent, reliably, that the same buffer address
ends up being classified as a different buffer type, this should be enough
to prevent double-use of any buffer (letting aside that `BufferProvider` is
backed by an implementing memory allocator, which in itself should prevent
any double-use.

Removing this feature resolves some ambiguity in the overall design,
and allows to turn `BufferMetadata::lock(type, address)` into a private
implementation function.

In the old code, there were some external access paths directly entering
into that implementation function, which caused a lot of confusion (at least for me...)
2026-03-16 20:37:24 +01:00
7463228d38 BufferProvider: reorganise internal BufferStore API
This refacotring prepares for the planned changes in `OutputSlot`
 * introduce a new compound parameter (tuple) BufferAlloc
 * wire this through all calls involved with storage handling

__Background__:
 * `BufferMetadata` deemed important for the implementation of buffer storage
 * ''new requirement detected'': must be able to handle an actual storage block
   that is ''larger'' than the requested buffer size (⟼ tiling)
 * need compact and uniform info, also for the `BufferProxyAdaptor` callbacks
2026-03-16 00:41:16 +01:00
259d0a5728 BufferProvider: now able to relocate OutputSlot into Vault Layer
The old implementation of `DiagnosticOutputSlot` is now disabled
and will be re-written from scratch, and no longer tangled to `BufferProvider`

 - `OutputManager` remains in Steam-Layer for now
 - the `Timings` and `OutputSlot` are now a self-contained
2026-03-10 23:12:30 +01:00
7dee16ba90 BufferProvider: relocate into Vault Layer
building upon all the preparations done during the last days,
the compound of code connected to the `BufferProvide` can now
be migrated down into the vault:
 - `BuffHandle`
 - `BufferProvider`
 - `BufferMetadata`
 - `BufferProviderSetup`
 - the simple standard implementations
 - `DiagnosticBufferProvider`
 - all directly related unit tests
2026-03-08 00:53:41 +01:00
cc9dbd8a40 BufferProvider: relocate TestFrame and dummy-hash computations
These are generic vehicles to verify computation structures.
Since they are in no way related to our models, they belong into »Vault« layer

Furthermore this reorganisation of test support components is prerequisite
to also move further generic facilities down into the Vault
2026-03-07 23:02:35 +01:00
9c74466778 Tests: build an link a test-support library
This is something I wanted to clean-up since a very long time indeed,
but always postponed it, since it requires a lot of nasty clean-up and disentangling....

Several parts had been stashed away into `src/lib/test`, which are not really related:
 * the testrunner and testsuite builder
 * generic helper utilities
 * specialised test-support facilities, e.g. the EventLog

This changeset introduces a new top-level test folder and a namespace `::test`
Code from this folder is linked into a shared library `libtestsupport.so`,
which resides in the linkage hierarchy between »Vessel« and »Vault«,
yet is no longer part of the Lumiera application and only linked into the test-suite.
2026-03-06 23:16:32 +01:00
20f3252892 Upgrade: down with typename!!
Yet another chainsaw massacre.

One of the most obnoxious annoyances with C++ metaprogramming
is the need to insert `typename` and `template` qualifiers into
most definitions, to help the compiler to cope with the syntax,
which is not context-free.

The recent standards adds several clarifications, so that most
of these qualifiers are redundant now, at least at places where
it is unambiguously clear that only a type can be given.

GCC already supports most of these relaxing rules
(Clang unfortunately lags way behind with support of newer language features...)
2025-07-06 01:19:08 +02:00
afa7ca2e4d Upgrade: switch to C++23 (see #1245)
The Lumiera »Reference Platform« is now upgraded to Debian/Buster, which provides GCC-14 and Clang-20.
Thus the compiler support for C++20 language features seems solid enough, and C++23,
while still in ''experimental stage'' can be seen as a complement and addendum.

This changeset
 * upgrades the compile switches for the build system
 * provides all the necessary adjustments to keep the code base compilable

Notable changes:
 * λ-capture by value now requires explicit qualification how to handle `this`
 * comparison operators are now handled transparently by the core language,
   largely obsoleting boost::operators. This change incurs several changes
   to implicit handling rules and causes lots of ambiguities — which typically
   pinpoint some long standing design issues, especially related to MObjects
   and the ''time entities''. Most tweaks done here can be ''considered preliminary''
 * unfortunately the upgraded standard ''fails'' to handle **tuple-like** entities
   in a satisfactory way — rather an ''exposition-only'' concept is introduced,
   which applies solely to some containers from the STL, thereby breaking some
   very crucial code in the render entities, which was built upon the notion of
   ''tuple-like'' entities and the ''tuple protocol''. The solution is to
   abandon the STL in this respect and **provide an alternative implementation**
   of the `apply` function and related elements.
2025-06-19 01:52:55 +02:00
d888891d84 clean-up: trifles 2025-06-07 23:59:57 +02:00
20392eee1c clean-up: successfully replaced the old fixed type sequence (closes: #987)
This resolves an intricate problem related to metaprogramming with
variadic templates and function signatures. Due to exceptional complexity,
a direct solution was blocked for several years, and required a better
organisation of the support code involved; several workarounds were
developed, gradually leading to a transition path, which could now
be completed in an focused clean-up effort over the last week.

Metaprogramming with sequences of types is organised into three layers:
- simple tasks can be solved with the standard facilities of the language,
  using pattern match with variadic template specialisations
- the ''type-sequence'' construct `Types<T...>` takes the centre stage
  for the explicit definition of collections of types; it can be re-bound
  to other variadic templates and supports simple direct manipulation
- for more elaborate and advanced processing tasks, a ''Loki-style type list''
  can be obtained from a type-sequence, allowing to perform recursive
  list processing task with a technique similar to LISP.
2025-06-07 18:04:59 +02:00
f8517b7011 clean-up: the big anti-bang -- NullType becomes Nil
Since I've convinced myself during the last years that this kind
of typelist programming is ''not a workaround'' — it is even
superior to pattern matching on variadics for certain kinds
of tasks — the empty struct defined as `NullType` got into
more widespread use as a marker type in the Lumiera code base.

It seems adequate though to give it a much more evocative name
2025-06-02 17:46:40 +02:00
8960aed7ba clean-up: ItemWrapper now stands on its own
...initially, this header was a collection of small helpers made on occasion;
one of them, the `ItemWrapper` used in transforming pipelines came
into widespread use and was much augmented and improved over the years.

many other tiny helpers could be replaced by standard library facilities...
2025-05-31 01:21:57 +02:00
d31d4295a4 clean-up: remove gavl_time_t as external dependency
Indeed — this change set is kind of sad.
Because I still admire the design of the GAVL library,
and would love to use it for processing of raw video.
However, up to now, we never got to the point of actually
doing so. For the future, I am not sure if there remains
room to rely on lib-GAVL, since FFmpeg roughly covers
a similar ground (and a lot beyond that). And providing
a plug-in for FFmpeg is unavoidable, practically speaking.

So I still retain the nominal dependency on lib-GAVL
in the Build system (since it is still packaged in Debian).

But it is pointless to rely on this library just for an
external type-def `gavl_time_t`. We owe much to this
inspiration, but it can be expected that we'll wrap
these raw time-values into a dedicated marker type
soon, and we certainly won't be exposing any C-style
interface for time calculations in future, since
we do not want anyone to side-step the Lumiera
time handling framework in favour of working
„just with plain numbers“


NOTE: lib-GAVL hompage has moved to Github:
      https://github.com/bplaum/gavl
2025-05-17 23:12:47 +02:00
555af315b3 Upgrade: improve Doxygen parameters and treat some warnings
- remove obsolete configuration settings
- walk through all settings according to the documentation
  https://www.doxygen.nl/manual/config.html
- now try to use the new feature to rely on Clang for C++ parsing
- walk through the doxygen-warnings.txt and fix some obvious misspellings
  and structural problems in the documentation comments.

With Debian-Trixie, we are now using Doxygen 1.9.8 —
which produces massively better results in various fine points.

However, there are still problems with automatic cross links,
especially from implementation to the corresponding test classes.
2025-04-27 05:00:14 +02:00
a68f145640 Upgrade: fix test-failures(3)
The Boost-Libraries changed their internal implementation
of the formula to chain hash values.

Fortunately, we had already extracted the existing implementation
from Boost 1.67 and incorporated it in-tree, in the Lumiera support libary.
After switching to that `lib:#️⃣:combine()` function, all the graph
computations related to the Scheduler-test-load can be shown to be identical.

So at the moment, the impact is still limited, but this incident highlights
the importance of a controlled, stable (and ideally also portable) hash implementation.
2025-04-25 19:54:28 +02:00
769060b9dd Invocation: extract partial closure functionality
What emerges here, seems to be a generic helper to handle
partial closure of ''tuple-like'' data records. In any case,
this is highly technical meta-programming code and mandates
extraction into a separate header — simplifying `NodeBuilder`
2025-02-16 23:16:46 +01:00
a8231150a5 Library: need remapping of variadic sequence
This is a rather obnoxious limitation of C++ variadics:
the inability to properly match against a mixed sequence with variadics.
The argument pack must always be the last element, which precludes to match
the last or even the penultimate element (which we need here).

After some tinkering, I found a way to recast this as ''rebinding to a remoulded sequence'',
and could package a multitude of related tools into a single helper-template,
which works without any further library dependencies.

🠲 extract into a separate header (`variadic-rebind.hpp`) for ease of use.
2025-01-01 22:02:08 +01:00
806db414dd Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
 * there is no entity "Lumiera.org" which holds any copyrights
 * Lumiera source code is provided under the GPL Version 2+

== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''

The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!

The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
a20e233ca0 Library: now using controlled seed and replaced rand (closes #1378)
After augmenting our `lib/random.hpp` abstraction framework to add the necessary flexibility,
a common seeding scheme was ''built into the Test-Runner.''
 * all tests relying on some kind of randomness should invoke `seedRand()`
 * this draws a seed from the `entropyGen` — which is also documented in the log
 * individual tests can now be launched with `--seed` to force a dedicated seed
 * moreover, tests should build a coherent structure of linked generators,
   especially when running concurrently. The existing tests were adapted accordingly

All usages of `rand()` in the code base were investigated and replaced
by suitable calls to our abstraction framework; the code base is thus
isolated from the actual implementation, simplifying further adaptation.
2024-11-17 19:45:41 +01:00
39d614f55f Library: Testsuite maintenance
- SchedulerStress_test simply takes too long to complete (~4 min)
  and is thus aborted by the testrunner. Add a switch to allow for
  a quick smoke test.

- SchedulerCommutator_test aborts due to an unresolved design problem,
  which I marked as failure

- add some convenience methods for passing arguments to tests
2024-11-16 00:38:57 +01:00
bf41474004 Library: investigate Scheduler test failures
...which turn out not to be due to the PRNG changes
 * the SchedulerCommutator_test was inadvertently broken 2024-04-10
 * SchedulerStress_test simply runs for 4min, which is not tolerated by our Testsuite setup

see also:
5b62438eb
2024-11-15 02:20:36 +01:00
7ed8486774 Library: rework detection of ''same object''
We use the memory address to detect reference to ''the same language object.''
While primarily a testing tool, this predicate is also used in the
core application at places, especially to prevent self-assignment
and to handle custom allocations.

It turns out that actually we need two flavours for convenient usage
 - `isSameObject` uses strict comparison of address and accepts only references
 - `isSameAdr` can also accept pointers and even void*, but will dereference pointers
This leads to some further improvements of helper utilities related to memory addresses...
2024-11-15 00:11:14 +01:00
0b9e184fa3 Library: replace usages of rand() in the whole code base
* most usages are drop-in replacements
 * occasionally the other convenience functions can be used
 * verify call-paths from core code to identify usages
 * ensure reseeding for all tests involving some kind of randomness...

__Note__: some tests were not yet converted,
since their usage of randomness is actually not thread-safe.
This problem existed previously, since also `rand()` is not thread safe,
albeit in most cases it is possible to ignore this problem, as
''garbled internal state'' is also somehow „random“
2024-11-13 04:23:46 +01:00
e82dd86b39 Library: reorganise test helpers and cover logging tracker object
...these features are now used quite regularly,
and so a dedicated documentation test seems indicated.

Actually my intention is to add a tracking allocator to these test helpers
(and then to use that to verify the custom allocator usage of `lib::Several`)
2024-06-16 04:22:29 +02:00
d71eb37b52 Scheduler-test: complete and document stress testing effort (closes #1344)
The initial effort of building a Scheduler can now be **considered complete**
Reaching this milestone required considerable time and effort, including
an extended series of tests to weld out obvious design and implementation flaws.

While the assessment of the new Scheduler's limitation and traits is ''far from complete,''
some basic achievements could be confirmed through this extended testing effort:
 * the Scheduler is able to follow a given schedule effectively,
   until close up to the load limit
 * the ''stochastic load management'' causes some latency on isolated events,
   in the order of magnitude < 5ms
 * the Scheduler is susceptible to degradation through Contention
 * as mitigation, the Scheduler prefers to reduce capacity in such a situation
 * operating the Scheduler effectively thus requires a minimum job size of 2ms
 * the ability for sustained operation under full nominal load has been confirmed
   by performing **test sequences with over 80 seconds**
 * beyond the mentioned latency (<5ms) and a typical turnaround of 100µs per job
   (for debug builds), **no further significant overhead** was found.

Design, Implementation and Testing were documented extensively in the [https://lumiera.org/wiki/renderengine.html#Scheduler%20SchedulerProcessing%20SchedulerTest%20SchedulerWorker%20SchedulerMemory%20RenderActivity%20JobPlanningPipeline%20PlayProcess%20Rendering »TiddlyWiki« #Scheduler]
2024-04-20 01:56:54 +02:00
a46449d5ac Scheduler-test: stable-state run > 1sec
This test completes the stress-testing effort
and summarises the findings
 * Scheduler performs within relevant parameter range without significant overhead
 * Scheduler can operate with full load in stable state, with 100% correct result
2024-04-18 01:39:28 +02:00
177e241060 Scheduler-test: investigate extended loads with different patterns
The behaviour seems consistent and the schedule breaks at the expected point.
At first sight, concurrency seems slightly to low; detailed investigation
however shows that this is due to the structure of the load graph,
and in fact the run time comes close to optimal values.
2024-04-18 01:39:28 +02:00
c934e7f079 Scheduler-test: reduce impact of scale adjustments on breakpoint-search
the `BreakingPoint` tool conducts a binary search to find the ''stress factor''
where a given schedule breaks. There are some known deviations related to the
measurement setup, which unfortunately impact the interpretation of the
''stress factor'' scale. Earlier, an attempt was made, to watch those factors
empirically and work a ''form factor'' into the ''effective stress factor''
used to guide this measurement method.

Closer investigation with extended and elastic load patters now revealed
a strong tendency of the Scheduler to scale down the work resources when not
fully loaded. This may be mistaken by the above mentioned adjustments as a sign
of a structural limiation of the possible concurrency.

Thus, as a mitigation, those adjustments are now only performed at the
beginning of the measurement series, and also only when the stress factor
is high (implying that the scheduler is actually overloaded and thus has
no incentive for scaling down).

These observations indicate that the »Breaking Point« search must be taken
with a grain of salt: Especially when the test load does ''not'' contain
a high degree of inter dependencies, it will be ''stretched elastically''
rather than outright broken. And under such circumstances, this measurement
actually gauges the Scheduler's ability to comply to an established
load and computation goal.
2024-04-18 01:39:27 +02:00
7c2b9a8ba5 Scheduler-test: investigate extended load patterns
...this seems to be the last topic for this investigation of Scheduler behaviour;
the goal is to demonstrate readiness for stable-state operation over an extended period of time
2024-04-18 01:39:26 +02:00
1d4f6afd18 Scheduler-test: complete and document the Load-peak tests
- use parameters known to produce a clean linear model
- assert on properties of this linear model

Add extended documentation into the !TiddlyWiki,
with a textual account of the various findings,
also including some of the images and diagrams,
rendered as SVG
2024-04-12 02:23:31 +02:00
7798ef499c Scheduler-test: adapt assertions to changes in load generation
This amends test code, which was commented-out for some time,
and was affected by the changes in load-graph generation:

a983a506b

These changes typically lead to a simplified topology at the end
of the load graph, since open ends are no longer connected to a
single exit node. In the case here, level 27 is no longer generate,
and level 26 is now comprised of three nodes, two of them with load=2
2024-04-12 02:23:31 +02:00
1316ee2c7f Scheduler-test: adjust contention mitigation as result of testing
Investigate the behaviour over a wider range of job loads,
job count and worker pool sizes. Seemingly the processing
can not fully utilise the available worker pool capacity.

By inspection of trace-dumps, one impeding mechanism could
be identified: the »stickiness« of the contention mitigation.
Whenever a worker encounters repeated contention, it steps up
and adds more and more wait cycles to remove pressure from the
schedule coordination. As such this is fine and prevents further
degradation of performance by repeated atomic synchronisation.
However, this throttling was kept up needlessly after further
successful work-pulls. Since job times of several milliseconds
can be expected on average in media processing, such a long
retention would spread a performance degradation over a duration
of several frames. Thus, the scheme for step-down was changed
to decrease the throttling by a power series rather than just
documenting the level.
2024-04-12 02:23:31 +02:00