Commit graph

1158 commits

Author SHA1 Message Date
4c0e58849a Activity-Lang: define test cases for basic Activities 2023-08-22 17:37:58 +02:00
4e6ee0ec9c Activity-Lang: notification to Gate now working
...also diagnostics helper now able to trace notifications
...and additionally the Gate now triggers as planned
2023-08-21 18:23:57 +02:00
108a5e7ca5 Activity-Lang: work out activation-dispatch-notification sequence
...attempt to get this intricate state machine sorted out

Notification turned out quite tricky, since it may emanate
from a concurrently executed phase and we try to avoid having
to protect the gate directly with a lock; rather we re-dispatch
the notification through the queue, which indirectly also ensures
that the worker de-queuing the NOTIFY-Activity operates in
management mode (single threaded, holding the GroomingToken)
2023-08-21 17:32:52 +02:00
abc29eaa31 Activity-Lang: complete implementation for Gate (conditional)
Decision how to handle a failed Gate-check
- spin forward (re-scheduler) by some time amount
- this spin-offset parameter is retrieved from the Execution Context
- thus it will be some kind of engine parameter

With these determinations and the framework for the Execution Context
it is now possible to code up the logic for Gate check, which in turn
can then be verified by the watchGate diagnostics
2023-08-20 02:39:57 +02:00
8a85e57235 Activity-Lang: setup to watch a Gate-Activity
ouch... this becomes kindof convoluted,
due to the lack of dynamic extension points
2023-08-20 01:35:14 +02:00
f0d71672d8 Activity-Lang: allow to inject the activation detector
...by prepending it into existing wiring
2023-08-20 00:59:47 +02:00
7debaaca48 Activity-Lang: adaptor to watch existing Activity's activation
due to technical limitations this requires to wire the adaptor
as replacement for the subject Activity, so that it can capture
and log the activation, and then pass it on to its watched subject
2023-08-19 19:06:44 +02:00
d9f2909b07 Activity-Lang: simple activation working 2023-08-19 17:48:38 +02:00
49435c8aca Activity-Lang: investigate / fix string conversion
...turns out that util::toString does not explicitly handle pointers differently,
for very good reasons; this function must always work, always produce a simple and
compact representation, and it must be possible to instantiate the template
and take a function reference (which precludes adding an overload for pointers)
2023-08-19 02:27:06 +02:00
3784bd7252 Activity-Lang: build activation detector
...using a HOOK-Activity as prepended adaptor,
optionally forwarding the activation to the inferior
2023-08-18 19:37:44 +02:00
9cdfdf3d18 Activity-Lang: activate a Job invocation
this verifies the most relevant core operation,
which is to trigger a job computation and pass arguments.
2023-08-18 16:54:35 +02:00
8c36e0a93b Activity-Lang: diagnostics for Activity and Execution Context 2023-08-18 16:25:09 +02:00
dd44373166 Activity-Lang: a way how to provide a faked Execution Context
...basically just delegated to DiagnosticFun instances,
yet the actual setup is somwewhat tricky to get right
2023-08-17 19:37:38 +02:00
1c6ee62c1a Activity-Lang: allow to verify invocation param in test
requires to supplement EventLog matching primitives
to pick and verify a specific positional argument.

Moreover, it is more or less arbitrary which job invocation parameters
are unpacked and exposed for verification; we'll have to see what is
actually required for writing tests...
2023-08-15 20:03:01 +02:00
161f604cbd Activity-Lang: setup a mocked JobFunctor for diagnostics
...now step by step building up the scaffolding
to build and verify Activity terms...
2023-08-15 18:52:51 +02:00
ab7f506f4b Activity-Lang: failure will certainly not be signalled to the Job
doing so would contradict the fundamental architecture,
all kinds of failures and timeouts need to be handled within
Scheduler-Layer-2 rather.

Jobs are never aborted, nor do they need to know if and when they are invoked
2023-08-15 17:18:30 +02:00
94528d67dc Activity-Lang: complete first test verification tool
...now able to verify that arbitrary functions have been invoked
...all of this is still preparatory work
2023-08-15 02:23:40 +02:00
e3f1aa4f7c Activity-Lang: support negative assertions for tests
Testcase (detect function invocation) passes now as expected


Some Library / Framework changes

- rename event-log-test.cpp
- allow the ExpectString also to work with concatenated expectation strings


Remark: there was a warning in the comment in event-log.hpp,
pointing out that negative assertions are shallow.

However, after the rework in 9/2018 (commit: d923138d1)
...this should no longer be true, since we perform proper backtracking,
leading to an exhaustive search.
2023-08-14 19:25:56 +02:00
25ad461a28 Activity-Lang: switch invocation detection to delegated matcher
ActivityMatch inherits privately from the EventMatch object,
and is thus able to delegate relevant matching queries, but
also to provide high-level special matchers.

This new design resolves the ambiguity regarding function arguments.
Moreover, we can now record the current sequence-Number as *attribute*
in the respective log record (this is the benefit of using structured
log entries instead of just a textual log), thereby avoiding the various
pitfalls with explicit bracketing sequence-number log entries

bottom line: this reworked design seems to be a better fit,
even while technically the implementation with the wrapped matcher
is somewhat ugly...
2023-08-14 02:05:13 +02:00
ff4acb04d7 Activity-Lang: investigate ways to verify invocation sequences
The EventLog seems to provide all the building blocks, but we need
some higher level special matchers (and maybe we also want to hide
some of the basic EventLog matchers). A soulution might be to wrap
the EventMatcher and delegate all follow-up builder calls.

This seems adequate, since the EventLog-Matcher is basically used as black box,
building up more elaborate matchers from the provided basic matchers...


Spent some time again to understand how EventLog matching works.

My feelings towards this piece of code are always the same: it is
somewhat too "tricky", but I am not aware of any other technique
to get this degree of elaborate chained matching on structured records,
short of building a dedicated matching engine from scratch.

The other alternative would be to use a flat textual log (instead of
the structured log records from EventLog), but then we'd have to
generate quite intricate regular expressions from the builder,
and I'm really doubtful it would be easier and clearer....
2023-08-13 20:49:30 +02:00
6e42e81546 Activity-Lang: draft invocation verification 2023-08-01 21:42:18 +02:00
111c05a1f9 Activity-Lang: introduce a callback hook
...primarily intended for testing,
but could be helpful as generic extension point later on...
2023-08-01 15:37:56 +02:00
49f2e34e4c Library: extract type rebinding helper
...turns out this is entirely generic and not tied to the context
within ActivityDetector, where it was first introduced to build a
mock functor to log all invocations.

Basically this meta-function generates a new instantiation of the
template X, using the variadic argument pack from template U<ARGS...>
2023-08-01 14:52:20 +02:00
db1adb63a7 Activity-Lang: draft a diagnostic helper
...for coverage of the Activity-Language,
various invocations of unspecific functions must be verified,
with the additional twist that the implementation avoids indirections
and is thus hard to rig for tests.

Solution-Idea: provide a λ-mock to log any invocation into the
Event-Log helper, which was created some years ago to trace GUI communication...
2023-07-31 21:53:16 +02:00
26c2e835c3 Activity-Lang: setup skeleton of the activation function
- complete spec of Activity processing
- define the invocation structure
- implement basic cases of activation
2023-07-30 22:06:06 +02:00
4f29d436b3 Activity-Lang: draft patterns of execution
essentially define a concept how to ''perform'' render activities in the Scheduler.
This entails to specify the operation patterns for the four known base cases
and to establish a setup for the implementation.
2023-07-28 02:21:59 +02:00
28b3900284 Block-Flow: final adjustments from performance test (closes: #1311)
Further extensive testing with parameter variations,
using the test setup in `BlockFlow_test::storageFlow()`

- Tweaks to improve convergence under extreme overload;
  sudden load peaks are now accomodated typically < 5 sec

- Make the test definition parametric, to simplify variations

- Extract the generic microbenchmark helper function

- Documentation
2023-07-22 06:07:35 +02:00
049ca833a0 Block-Flow: optimise parameters for performance
There seems to be a ''sweet spot'' for somewhat larger Epoch sizes around 500 slots.
At least in the test setup used here, which works with a load of 200 Frames / sec,
which is significantly over the typical value of 50fps (video + audio) for simple playback.

The optimisation of averaged allocation times can not be much improved **below 30ns**.

Overall, this can be considered a good result,
since this allocation scheme does way more than just allocate memory,
it also provides a means to track dependencies and lifecycle.

__For context__:
 - we should strive at processing one frame in ~ 10ms
 - for 10 Activity records per Frame, we currently use < 0.5 µs for
   memory and dependency management in the scheduler
 - this leaves enough room for the further administrative efforts
   (priority queue, job planning, buffer management)
2023-07-21 04:34:04 +02:00
d557c540bf Block-Flow: tweaks to get down on par with the standard heap allocator
... while this a comparison of apples and oranges, since the standard
heap allocator does not offer any dependency and lifecycle managmenet,
while the BlockFlow scheme developed here is much more complex and
offers a lifetime and dependency control specifically tailored to
the needs of the Scheduler.

Anyway, with the latest tweaks and refactorings, the test case
now shows averaged times per allocation on a comparable level
(both in the range of ~30ns)
2023-07-21 01:52:07 +02:00
2977076b7f Block-Flow: switch to using the reworked config
BUT -> +50% runtime in -O3  (+20ns)

Investigation seems to indicate
 - that the increased (+1 Epochs, 10 -> 11) moving average
   caused the Algo to perform worse (strong effect)
 - that the Optimiser has problems with boost::rational, which however
   yields only a minute effect (+5ns), and only on the critical path

The access via Meyers Singleton has no adverse effect,
rather the new setup gives a tiny benefit (46ns -> 37ns).
Surprisingly, the increased pre-allocation has no observable effect.
2023-07-20 21:47:18 +02:00
ca502aa826 Block-Flow: introduce config through a policy mix-in
...measured running time reproduced unaltered for -O3
2023-07-20 19:28:20 +02:00
5803fed544 Block-Flow: draft for re-arranged configuration
On the long run, there will be a central Render Engine parametrisation;
some parameters can even be expected to be dynamic; thus prepare the
BlockFlow allocator to fit in with this expectation
2023-07-20 16:46:54 +02:00
14a5200cc0 Block-Flow: more runtime observation and fine-tuning
For comparison: use individual managment by refcount.
This supports the conclusion that BlockFlow is more than just a
custom allocator; it also supports a non-trivial lifetime management,
and this comes at a cost.

Playing around with various load patterns uncovers further weak spots
in the regulation mechanism. As a remedy, introduce a stronger feed-back
and especially set the target load factor from 100% -> 90%
to add some headroom to absorb intermittent load peaks

Presumably ''much more observation and fine-tuning'' will be necessary
under real-world load conditions (⟹ Ticket #1318 for later)
2023-07-19 03:29:09 +02:00
c008858d8f Block-Flow: investigate, fix and fine-tune Epoch size control
- BUG: must prevent the Epoch size to become excessive low
- Problem: feedback signal should not be overly aggressive

Fine-Tuning:
- Dose for Overflow-compensation is delicate
- Moving average and Overflow should be balanced
- ideally the compensatory actions should be one order of magnitude
  slower than the characteristic regulation time

Improvement: perform Moving-Average calculations in doubles
2023-07-18 21:23:00 +02:00
c7d6f3e24c Block-Flow: Load-Test indicates problem in Epoch control
...leading to PATHETICALLY bad timing comparison
...it seems clear that the Epoch-Step went to zero
   (which was neither anticipated, nor protected against)

However, even individual heap allocations fare surprisingly well
under full optimisation; just they don't solve our problem with
tracking dependencies; the most simplest solution that would
also fulfil this requirement would be using shared_ptr
2023-07-18 01:59:17 +02:00
c1001064e3 Block-Flow: draft Load/Stress-Test
- use a midrange load scenario
- but play this at saturation level
2023-07-17 18:36:12 +02:00
a4365a24f8 Block-Flow: feed size regulation on clean-up
Generate a signal based on actual Epoch length and
observed fill ratio, assuming even distribution of load.
2023-07-17 04:32:10 +02:00
9d040dc49c Block-Flow: compute exponential moving average
..as a heuristic to regulate optimal Epoch duration;
when Epochs are discarded, the effective fill factor can be used
to guess an Epoch duration time, which would (in hindsight)
lead to perfect usage of storage space
2023-07-17 03:00:56 +02:00
bd353d768a Block-Flow: detect and react on Epoch overflow
..using a simplistic implementation for now: scale down the
Epoch-stepping by 0.9 to increase capacity accordingly.
This is done on each separate overflow event, and will be
counterbalanced by the observation of Epoch fill ratio
performed later on clean-up of completed Epochs
2023-07-16 20:47:39 +02:00
6d75a82932 Block-Flow: introduce backlink into AllocationHandle
further implementation makes clear that the AllocationHandle,
which is the primary usage front-end, has to rely both on
services of the underlying ExtentFamily allocator, as well
as on the BlockFlow itself for managing the Epoch spacing.
2023-07-16 18:03:27 +02:00
e4b74f3ae1 Block-Flow: handle Epoch overflow
...draft of control logic, does not work correct in all cases
2023-07-16 03:06:02 +02:00
dce65104aa Block-Flow: select suitable Epoch for new allocation 2023-07-15 21:37:58 +02:00
cb2ee9466b Block-Flow: add diagnostics and define further expectations
- fix a bug in IterExplorer: when iterating a »state core« directly,
  the helper CoreYield passed the detected type through ValueTypeBindings.
  This is logically wrong, because we never want to pick up some typedefs,
  rather we always want to use the type directly returned from CORE::yield()
  Here the iterator returns an Epoch&, which itself is again iterable
  (it inherits from std::array<Activity, N>). However, it is clear
  that we must not descent into such a "flatMap" style recursive expansion

- draft a simple scheme how to regulate Epoch lengths dynamically

- add diagnostics to pinpoint a given Activity and find out into which
  Epoch it has been allocated; used to cover the allocator behaviour
2023-07-15 18:54:59 +02:00
7167ad6d96 Block-Flow: define expected behaviour for Epoch association
...how new Activities are placed into Epochs, incl. overflow
2023-07-14 05:03:01 +02:00
d0fd7f32a9 Block-Flow: verify handling of Activity records within the Epoch 2023-07-14 01:51:00 +02:00
af8f84a72d Block-Flow: complete simple use case (see #1311)
- add preliminary deadline-check (directly instead of using the Activity)
- with this shortcut, now able to implement discarding obsoleted Epochs
- Iteration and use of the underlying `ExtentFamily` is also settled by now

💡 ''Implementation concept for the allocation scheme complete and validated''
2023-07-13 19:43:22 +02:00
5055ba7144 Block-Flow: rationalise iterator usage
...with the preceding IterableDecorator refactoring,
the navigation and access to the storage extents can now be
organised into a clear progression

Allocator::iterator -> EpochIter -> Epoch&

Convenience management and support functions can then be
pushed down into Epoch, while iteration control can be done
high-level in BlockFlow, based on the helpers in Epoch
2023-07-13 18:35:10 +02:00
5a8463acce Block-Flow: allow optionally to supply sanity checks
Especially for the BlockFlow allocator, sanity checks are elided
for performance reasons; yet, generally speaking, it can be a very bad idea
to "optimise" away sanity checks. Thus an additional adaptor is provided
to layer such checks on top of an existing core; and IterEplorer now
always wires in this additional adaptor, and so the original behaviour
is now restored in this respect (and for the largest part of the code base)
2023-07-13 16:46:43 +02:00
42ac55ea7b Block-Flow: promote IterableDecorator
While at first sight just a superficial variation of the existing IterStateWrapper,
it became clear with the evolution of the IterExplorer framework that
this setup represents a distinct concept, and especially lends itself
for complex and cohesive collaboration in a layered pipeline. Which
may, or may not be a good idea, depending on the circumstances.

Now, for the implementation of the scheduler memory allocation scheme,
another twist is added to the picture: we can not effort the sanity checks
on each access, even more so when layering / adapting iterators, where
it is essential that the optimiser can remove all unnecessary warts.
2023-07-13 16:29:06 +02:00
946f7c17f7 Block-Flow: implement opening a new Epoch
..this is the most simple case, where no Epochs are opened yet
..add diagnostics to inspect alloc count and deadlines
..add accessors for the first/last underlying Extent
2023-07-13 04:41:58 +02:00
180c6b8d84 Block-Flow: define next steps to construct
...continue to proceed test-driven
...scheduler internals turn out to be intricate and cohesive,
   and thus the only hope is to adhere to strict testing discipline
2023-07-13 01:51:21 +02:00
18904e5b58 Block-Flow: completed implementation of low-level cyclic extent storage
..verified boundary cases for expansion while retaining addresses
of currently active extents...
2023-07-12 21:55:50 +02:00
824a626c2e Block-Flow: investigate proper working of on-demand allocation
Library: add "obvious" utility to the IterExplorer, allowing to
         materialise all contents of the Pipeline into a container

...use this to take a snapshot of all currently active Extent addresses
2023-07-12 19:19:41 +02:00
f5813a1f29 Block-Flow: veryfy proper handling of extent reuse
- use a checksum to prove that ctor / dtor of "content" is not invoked
- let the usage of active extents "wrap around" so that the mem block is re-used
- verify that the same data is still there
2023-07-12 04:53:30 +02:00
6409e0eb36 Block-Flow: implement iteration and expansion of ExtentFamily
The low-level allocator is basically implemented now,
but we still need to check thoroughly that the tricky
wrap-around and expansion logic behaves sane...
(see #1311)
2023-07-11 03:52:24 +02:00
3b929cf014 Block-Flow: better setup for iterator implementation
Using a Storage* within a wrapper as "pos" will work,
but is borderline trickery, since it amounts to subverting
the idea behind IterAdapter (which is to encapsulate a target
pointer with some control-logic in the managing container).

Using the same storage size and implementation overhead,
it is much more straight-forward to package the complete
iteration logic into a »State Core«, which in this case
however maintains a back-link to the ExtentFamily.
2023-07-11 02:03:50 +02:00
3401f18c2c Block-Flow: consider usage in ActivityTerm and rectify iteration
Iteration should just yield an Reference to an Extent,
thereby hiding all details of the actual raw storage (char[]).
This can be achieved by usind a wrapper type around a pointer
into the managing vector; from this pointer we may convert
into a vector::iterator with the trick described here

https://stackoverflow.com/a/37101607/444796


Furthermore, continued planning of the Activity-Language,
basically clarified the complete usage scenario for now;
seems all implementable right away without further difficulties
2023-07-11 01:08:26 +02:00
e86cb017a5 Block-Flow: implement cyclic usage of an extent pool
..with the ability to grow on demand..
..possibly add the new extents in the middle, by first allocating at the end
  and then using the std::rotate() algo to bring them to the point
  in the middle where new extents are required
2023-07-10 05:40:50 +02:00
c1b16349f2 Block-Flow: define next steps for implementation of low-level allocator 2023-07-09 04:03:02 +02:00
ccf0710903 Block-Flow: maintain an »Epoch« within the raw allocation Extent
- the idea is to use slot-0 in each extent for administrative metadata
- to that end, a specialised GATE-Activity is placed into slot-0
- decision to use the next-pointer for managing the next free slot
- thus we need the help of the underlying ExtentFamily for navigating Extents

Decision to refrain from any attempt to "fix" excessive memory usage,
caused by Epochs still blocked by pending IO operations. Rather, we
assume the engine uses sane parametrisation (possibly with dynamic adjustment)
Yet still there will be some safety limit, but when exceeding this limit,
the allocator will just throw, thereby killing the playback/render process
2023-07-09 01:32:27 +02:00
533112a4b0 Block-Flow: provide specialised ctor notation
...now able to create instances for all the relevant Activity verbs
2023-07-07 03:41:30 +02:00
f34ecafa1a Block-Flow: consider data storage for render activities
- decision to favour small memory footprint
- rather use several Activity records to express invocation
- design Activity record as »POD with constructor«
- conceptually, Activity is polymorphic, but on implementation
  level, this is "folded down" into union-based data storage,
  layering accessor functions on top
2023-07-06 16:35:42 +02:00
4ac995548a Block-Flow: identify required API operations
- decision how to handle the Extent storage (by forced-cast)
- decision to place the administrative record directly into the Extent

TODO not clear yet how to handle the implicit limitation for future deadlines
2023-07-05 15:12:20 +02:00
022d40a8cf Block-Flow: initial draft of ExtentFamily storage
using a simple yet performant data structure.
Not clear yet if this approach is sustainable

- assuming that no value initialisation happens for POD payload
- performance trade-off growth when in wrapped-state vs using a list
2023-07-04 04:42:53 +02:00
23a6fbdf4f Scheduler: investigate modes of operation
- analysis of Activity usage
- derive possible memory management schemes
- research regarding asynchronous IO
- decision regarding the memory management scheme
2023-07-03 18:40:37 +02:00
4176576db0 Scheduler: consider what operations are necessary for layer-1
....still about to find out what kinds of Activities there are,
and what reasonably to implement on layer-2 vs. layer-1

It is clear that the worker will typically invoke a doWork()
operation on layer-2, which in turn will iterate layer-1.

Each worker pulls and performs internal managmenet tasks exclusively
until encountering the next real render task, at which point it will
drop an exclusion flag and then engage into performing the actual
extended work for rendering...
2023-06-27 03:21:10 +02:00
3b6519a7c0 Scheduler: pass activity marker (low-level)
- define a simple record to represent the Activity
- define a handle with an ordering function
- low-level functions to...
  + accept such a handle
  + pick it from the entrace queue
  + pass it for priorisation into the PriQueue
  + dequeue the top priority element
2023-06-26 02:16:50 +02:00
bdcfc94b57 Scheduler: implementation technology
- use Boost-Lockfree as entrance queue for instructions
- use the STL Heap-Algo and Priority-Queue adaptor for time order
2023-06-25 01:02:12 +02:00
3169ba88ad Scheduler: devise the arrangement of basic components
- define organisation of vault-layer namespaces
- define the ground plan of the scheduler implementation
2023-06-24 03:14:17 +02:00
d109f5e1fb bye bye Monad (closes #1276)
after completing the recent clean-up and refactoring work,
the monad based framework for recursive tree expansion
can be abandoned and retracted.

This approach from functional programming leads to code,
which is ''cool to write'' yet ''hard to understand.''

A second design attempt was based on the pipeline and decorator pattern
and integrates the monadic expansion as a special case, used here to
discover the prerequisites for a render job. This turned out to be
more effective and prolific and became standard for several exploring
and backtracking algorithms in Lumiera.
2023-06-22 20:23:55 +02:00
42f4e403ac Job-Planning: rework of dispatcher and pipeline builder complete (see #1301)
An extended series of refactoring and partial rewrites resulted
in a new definition of the `Dispatcher` interface and completes
the buildup of a Job-Planning pipeline, including the ability
to discover prerequisites and compute scheduling deadlines.

At this point, I am about to ''switch to the topic'' of the `Scheduler`,
''postponing'' the completion of the `RenderDrive` until the related
questions regarding memory management and Scheduler interface are settled.
2023-06-22 03:55:09 +02:00
8c78e50730 Job-Planning: extended deadline integration test
- allow to configure the expected job runtime in the test spec
- remove link to EngineConfig and hard-wire the engine latency for now

... extended integration testing reveals two further bugs ;-)
... document deadline calculation
2023-06-21 04:04:11 +02:00
1f840730a0 Job-Planning: build and verify complete pipeline
- strip the builder
- add a terminal / front-end with convenience functions
- verify integration, incl multi-step prerequisites and deadlines
2023-06-20 01:46:44 +02:00
848bb6fb86 Job-Planning: implement handling of deadlines for prerequisites
...simple implementation
...decide *not* to cache the deadlines for now (possibly quadratic!)
...Test GREEN
2023-06-19 18:28:01 +02:00
b8309e5565 Job-Planning: define expectation for prerequisites 2023-06-19 16:58:32 +02:00
dc1bbfc918 Job-Planning: rework pipeline to enable dependency planning
This finishes the last series of refactorings; the basic concept
remains the same, but in the initial version we arranged the expander
function in the pipeline to maintain a Tuple (parent, child) for the
JobTickets. Unfortunately this turned out to be insufficient, since
JobTicket is effectively const and responsible for a complete Sement,
so there is no room to memorise a Deadline for the parent dependency.

This leads to the better idea to link the JobPlanning aggregators
themselves by parent-child references, which is possible since the
whole dependency chain actually sits in the stack embedded into the
Expander (in the pipeline)
2023-06-19 03:56:11 +02:00
2b92dab377 Library: change »assignment« of ItemWrapper to destroy-create
This very deep change (which requires almost complete rebuild)
was prompted by the need to process an object (JobPlanning),
which holds several references and is thus move-only, in the
middle of a complex processing pipeline with child expansion.

If this works out well, a long-standing and obnoxious problem
with transforming iterators would be solved, albeit by incurring
a (presumably small) performance overhead, since now the new
value is no longer *assigned*, but rather the existing payload
is destroyed and a new instance is copy/move constructed into
the inline buffer.

The primary purpose (and widely used in Lumieara) is to have a
Lambda create a new Object, which is then returned by value
and thus immediately moved into this inline buffer, where it
resides for further use (as long as the enclosing pipeline
stays alive). Unless such an object does very elaborate
allocations and registrations behind the scene, the
expense of assigning vs creating should be the same.
2023-06-19 02:33:50 +02:00
9ef3d98de7 Job-Planning: replace FrameCoord by direct references
...in the hope that the Optimiser is able to elide those references entirely,
when (as is here the case) they point into another field of a larger object compound
2023-06-19 01:51:48 +02:00
a1c1456849 Job-Planning: dispose of FrameCoord in pipeline and Dispatcher interface
...as a preparation for solving a logical problem with the Planning-Pipeline;
it can not quite work as intended just by passing down the pair of
current ticket and dependent ticket, since we have to calculate a chained
calculation of job deadlines, leading up to the root ticket for a frame.

My solution idea is to create the JobPlanning earlier in the pipeline,
already *before* the expansion of prerequisites, and rather to integrate
the representation of the dependency relation direcly into JobPlanning
2023-06-18 03:50:48 +02:00
661d768fad Job-Planning: frame number now additionally required in FrameCoord
...which was the reason why the test failed;
the calculation works as expected


PS: rename JobPlanningSetup_test to JobPlanningPipeline_test
2023-06-17 03:10:57 +02:00
6228c623b4 Job-Planning: implement braindead deadline calculation
...using hard coded values instead of observation of actual runtimes,
but at least the calculation scheme (now relocated from TimeAnchor to JobPlanning)
should be a reasonable starting point.

TODO: test fails...
2023-06-16 04:09:38 +02:00
73a9e4495a Job-Planning: code up simplest use case 2023-06-16 01:50:11 +02:00
b9f8356afc Job-Planning: investigate input data
- collect list of entities to be picked up from the dispatcher-pipeline
- as it turns out: there is no sensible use for the realTimeDeadline in
  in the FrameCoord record ==> remove it
2023-06-15 18:24:25 +02:00
a551314e80 Job-Planning: start rework of the planning data aggregation
The initial implementation effort for Player and Job-Planning
has been reviewed and largely reworked, and some parts are now
obsoleted by the reworked alternative and can be disabled.

The basic idea will be retained though: JobPlanning is a
data aggregator and performs the final step of creating a Job
2023-06-15 03:51:07 +02:00
f84517547b Dispatcher-Pipeline: coordination of base tick and prerequisite expansion
- had to fix a logical inconsistency in the underlying Expander implementation
  in TreeExplorer: the source-pipeline was pulled in advance on expansion,
  in order to "consume" the expanded element immediately; now we retain
  this element (actually inaccessible) until all of the immediate
  children are consumed; thus the (visible) state of the PipeFrameTick
  stays at the frame number corresponding to the top-level frame Job,
  while possibly expanding a complete tree of flexible prerequisites

This test now gives a nice visualisation of the interconnected states
in the Job-Planning pipeline. This can be quite complex, yet I still think
that this semi-functional approach with a stateful pipeline and expand functors
is the cleanest way to handle this while encapsulating all details
2023-06-14 18:12:41 +02:00
08dfe1007c Dispatcher-Pipeline: verify the expansion of prerequisites
- fix a bug in the MockDispatcher, when duplicating the ExitNodes.
  A vector-ctor with curly braces will be interpreted as std::initializer_list

- add visualisation of the contents appearing at the end of the pipeline

*** something still broken here, increments don't happen as expected
2023-06-14 04:20:50 +02:00
542017aa65 Dispatcher-Pipeline: mocked Dispatcher implementation complete (closes: #1294)
`steam/engine/mock-dispatcher.hpp |cpp` now integrates this
''complete mock setup for render jobs and frame dispatching.''
The exising `DummyJob` has been slightly adapted and renamed
to `MockJob` and is tightly integrated with the other mocks.

The implementation of a `MockDispatcher` necessitated to change
the use of `MockJobTicket`. The initial attempts used a complete
mock implementation, but this approach turned out not to be viable.
Instead — based on the ideas developed for the mock setup —
now the prospective real implementation of `JobTicket` is available
and will be used by the mock setup too. Instead of a synthetic spec,
now a setup of recursively connected `ExitNode`(s) is used; the latter
seems to develop into some kind of Facade for the render node network.

Based on this mock setup, we can now demonstrate the (mostly) complete
Job-Planning pipeline, starting from a segmentation up to render jobs,
and verify proper connectivity and job invocation.
✔
2023-06-13 20:23:33 +02:00
0b9705692b Dispatcher-Pipeline: now (finally) able to implement MockDispatcher
MockSupport_test      : PASS
JobPlanningSetup_test : PASS(as far as defined)
2023-06-13 03:47:42 +02:00
122addbff5 Dispatcher-Pipeline: expected behaviour of (mock)Dispatcher 2023-06-13 00:15:16 +02:00
2031a58775 Dispatcher-Pipeline: decide upon the translation into portIDX
- has to be prepared / supported by the RenderEnvironmentClosure
- actual translation happens when building the Dispatcher-Pipeline
- implementation delegate through
    virtual size_t Dispatcher::resolveModelPort (ModelPort)
2023-06-12 19:21:14 +02:00
e6dcb6253c Dispatcher-Pipeline: resolve further problems with re-entrant allocation
...ouch this was insidious: the STL implementation for list does not
return a pointer to the element just allocated, but rather retrieves
and dereferences the back() / front() iterator after returning from emplace_back|front()

...which in case of re-entrant allocations is something wildly different
than the initial allocation. Thus a *cheap* and dirty placeholder implementation
just using a STL container is not possible, and we need at least
to code up likewise cheesy placeholder implementation by hand.
- separate allocation and ctor all
- use an inline buffer in the STL container
- explicitly handle ctor failures to discard allocation
- NOT THREADSAFE and likely WASTFUL in terms of performance


==> MockSupport_test now back to GREEN after complete refactoring
2023-06-12 17:21:41 +02:00
bf3e612c55 Dispatcher-Pipeline: create hook for self-validation
...later to be extended into the render nodes network
2023-06-12 01:18:59 +02:00
0933d2bba8 Dispatcher-Pipeline: simplify JobTicket and remove channel differentiation
The existing implementation of the Player from 2012~2015 inclduded
an additional differentiation by media channel (for multichannel media)
and would build a separate CalcStream for each channel.

The in-depth analysis conducted for the ongoing »Vertical Slice« effort
revealed that this differentiation is besides the point and would never
be materialised: Since -- by definition -- all media processing has
to be done by the engine, also the generation of the final output format
including any channel multiplexing will happen in render nodes.
The only exception would be when only a single channel of multichannel
media is extracted -- yet this case would then translate into a
dedicated ModelPort.

Based on this reasoning, a lot of complexity (and some contradictions)
within the JobTicket implementation can be removed -- together with
some further leftovers of the fist attempt to build JobTickets always
from a Mock specification (we now use construction by the Segment,
based on an ExitNode, which is the expected actual implementation
for production setup)
2023-06-12 00:04:45 +02:00
b18e79d077 Dispatcher-Pipeline: solve allocation of JobTicket instances
...by defining a new scheme for access to custom allocators
...and then passing a reference to such an accessor into the
   JobTicket ctor, thereby allowing the ticket istelf recursively
   to place further JobTicket instances into the allocation space

--> success, test passes (finally)
2023-06-11 04:37:38 +02:00
f25ec2f5ef Dispatcher-Pipeline: switch JobTicket creation to use ExitNode directly
Up to now, a draft/mock implementation was used, relying on a »spec tuple«,
which was fabricated by MockJobTicket. But with the introduction of
NodeGraphAttachment, the MockSequence now generates a nested ExitNode structure,
and thus the JobTicket will be created through the "real" ctor, and
no longer via MockJobTicket.

Thus it is possible to skip this whole interspersed »spec tuple«,
since ExitNode *is* already this aggregated / abstracted Spec
2023-06-10 04:52:40 +02:00
2c3b85a122 Dispatcher-Pipeline: allocate JobTicket in Segment
PROBLEM: can not implement Spec-generation, since
 - we must use a λ for internal allocation of JobTickets
 - but recursive type inference is not possible

Will thus need to abandon the Spec-Tuple and relocate this
traversal-and-generation code into JobTicket itself
2023-06-09 02:48:38 +02:00
c246c21e41 Dispatcher-Pipeline: remould Segment for on-demand JobTicket generation
Use another unit-test (FixtureSegment_test) to guide and cover
the transition from the existing fake-implementation to the
actual implementation, where the JobTicket will be generated
on-demand, from a NodeGraphAttachment
2023-06-08 03:21:43 +02:00
0c57a61545 Dispatcher-Pipeline: implement Generation of fake-ExitNodes
...similar to the Generation of complete JobTickets in the initial implementation
2023-06-08 00:28:44 +02:00
f6af4c6a16 Dispatcher-Pipeline: prepare test for the new NodeGraphAttachment
It turns out that the real (not mocked) implementation of JobTicket creation
is already required now for this planned (mock)Dispatcher setup;
moreover, this real implementation turns out to be almost identical
to the mock implementation written recently -- just nested structure
of prerequiste JobTickets need to be changed into a similar structur
of ExitNodes

-- as an aside: rearrange various tests to be more in-line
   with the envisioned architecture of playback and engine
2023-06-07 04:03:00 +02:00
3b2e5db7b4 Dispatcher-Pipeline: consider how to access render nodes from job
...this opens up yet another difficult question and a host of new problems
- how are prerequisites detected or arranged by the Builder
- how are prerequisites represented?
- what is an ExitNode in terms of implementation? A subclass of ProcNode?
- how will the actual implementation of JobTicket creation (on-demand) work?
- how to adapt the Mock implementation, while retaining the Specification
  for Segments and prerequisites?
2023-06-06 04:25:12 +02:00