Commit graph

164 commits

Author SHA1 Message Date
597d8191c7 Library: code the DataSource template
...turns out challenging, since our intention here
is borderline to the intended design of the Lumiera ETD.
It ''should work'' though, when combined with a Variant-visitor...
2024-03-27 04:07:55 +01:00
59390cd2f8 Library: reorder some pervasively used includes
reduce footprint of lib/util.hpp
 (Note: it is not possible to forward-declare std::string here)

define the shorthand "cStr()" in lib/symbol.hpp

reorder relevant includes to ensure std::hash is "hijacked" first
2024-03-21 19:57:34 +01:00
1f5518e2c8 Library: introduce functions for floating-point comparisons
- rough numeric comparisons (optionally given precision)
- epsilon comparison based on numeric_limits
2024-03-16 03:03:29 +01:00
a6aad5261c Library: complete and verify temp-dir helper
verify also that clean-up happens in case of exceptions thrown;
as an aside, add Macro to check for ''any'' exception and match
on something in the message (as opposed to just a Lumiera Exception)
2024-03-13 02:50:13 +01:00
18b1d37a3d Library: also create unique temporary files
...using the same method for sake of uniformity

Also move the permissions helpers to the file.hpp support functions
and setup a separate unit test for these
2024-03-12 22:54:05 +01:00
a1832b1cb9 Library: base implementation of temp-dir creation
Inspired by https://stackoverflow.com/a/58454949

Verified behaviour of fs::create_directory
 --> it returns true only if it ''indeed could create'' a new directory
 --> it returns false if the directory exists already
 --> it throws when some other obstacle shows up

As an aside: the Header include/limits.h could be cleaned up,
and it is used solely from C++ code, thus could be typed, namespaced etc.
2024-03-12 20:14:29 +01:00
6e8c07ccd6 Library: draft tests to document the new features
Yesterday I decided to include some facilities I have written in 2022
for the Yoshimi-Testsuite. The intention is to use these as-is, and just
to adapt them stylistically to the Lumiera code base.

However — at least some basic documentation in the form of
very basic unit-tests can be considered »acceptance criteria«
2024-03-11 17:44:19 +01:00
580c1f1f68 Scheduler-test: complete instrumentation helper
Verify proper operation under pressure
using a multithreaded stress test
2024-02-15 00:52:59 +01:00
67036f45b0 Scheduler-test: Integration-test now running smoothly
The last round of refactorings yielded significant improvements
 - parallelisation now works as expected
 - processing progresses closer to the schedule
 - run time was reduced

The processing load for this test is tuned in a way to overload the
scheduler massively at the end -- the result must be correct non the less.

There was one notable glitch with an assertion failure from the memory manager.
Hopefully I can reproduce this by pressing and overloading the Scheduler more...
2023-12-18 23:34:10 +01:00
df4ee5e9c1 Scheduler-test: implement pure computation load
..initial gauging is a tricky subject,
since existing computer's performance spans a wide scale

Allowing
 - pre calibration -98% .. +190%
 - single run ±20%
 - benchmark ±5%
2023-12-11 03:10:42 +01:00
beebf51ac7 Scheduler-test: draft a configurable CPU load component
...which can be deliberately attached (or not attached) to the
individual node invocation functor, allowing to study the effect
of actual load vs. zero-load and worker contention
2023-12-10 19:58:18 +01:00
7eca3ffe42 Scheduler-test: a helper for one-time operations
Invent a special JobFunctor...
 - can be created / bound from a λ
 - self-manages its storage on the heap
 - can be invoked once, then discards itself

Intention is to pass such one-time actions to the Scheduler
to cause some ad-hoc transitions tied to curren circumstances;
a notable example will be the callback after load-test completion.
2023-12-08 03:16:57 +01:00
aafd277ebe Chain-Load: rework the pattern for dynamic rules
...as it turns out, the solution embraced first was the cleanest way
to handle dynamic configuration of parameters; just it did not work
at that time, due to the reference binding problem in the Lambdas.
Meanwhile, the latter has been resolved by relying on the LazyInit
mechanism. Thus it is now possible to abandon the manipulation by
side effect and rather require the dynamic rule to return a
''pristine instance''.

With these adjustments, it is now possible to install a rule
which expands only for some kinds of nodes; this is used here
to crate a starting point for a **reduction rule** to kick in.
2023-11-30 02:13:39 +01:00
3d5fdce1c7 Chain-Load: demonstrate use of the expansion rule
...played a lot with the parameters
...behaviour and DOT graphs look plausible
...document three typical examples with statistics
2023-11-29 02:58:55 +01:00
7a22e7f987 Test: helper for transitory manipulations
Use a simple destructor-trick to set up a concise notation
for temporarily manipulating a value for testing.
The manipulation will automatically be undone
when leaving scope
2023-11-08 19:27:08 +01:00
6a7a2832bf Scheduler: simplify usage of microbenchmark helper
as an aside, the header lib/test/microbenchmark.hpp
turns out to be prolific for this kind of investigation.

However, it is somewhat obnoxious that the »test subject«
must expose the signature <size_t(size_t)>.

Thus, with some metaprogramming magic, an generic adaptor
can be built to accept a range of typical alternatives,
and even the quite obvious signature void(void).
Since all these will be wrapped directly into a lambda,
the optimiser will remove these adaptations altogether.
2023-10-30 20:17:16 +01:00
b5e9d67a79 Scheduler: wrap-up and comment test cases thus far
...up to now, Behaviour is as expected
- with some minor discrepancies still to be fixed
- and an effect due to the test-scaffolding
2023-10-27 03:37:24 +02:00
097001d16f Scheduler: investigate timings of dispatch()
...there seemed to be an anomaly of 50...100µs

==> conclusion: this is due to the instrumentation code
    - it largely caused by the EventLog, which was never meant
      to be used in performance-critical code, and does hefty
      heap allocations and string processing.
    - moreover, there clearly is a cache-effect, adding a Factor 2
      whenever some time passed since the last EventLog call

==> can be considered just an artifact of the test setup and
    will have no impact on the scheduler


remark: this commit adds a lot of instrumentation code
2023-10-27 02:53:34 +02:00
a71bcaae43 Scheduler: shorthand notation for work-Function test
To cover the visible behaviour of the work-Function,
we have to check an amalgam of timing delays and time differences.

This kind of test tends to be problematic, since timings are always
random and also machine dependent, and thus we need to produce pronounced effects
2023-10-26 01:14:13 +02:00
c37871ca78 Library/Application: switch Locking from POSIX to C++14
While not directly related to the thread handling framework,
it seems indicated to clean-up this part of the application alongside.

For »everyday« locking concerns, an Object Monitor abstraction was built
several years ago and together with the thread-wrapper, both at that time
based on direct usage of POSIX. This changeset does a mere literal
replacement of the POSIX calls with the corresponding C++ wrappers
on the lowest level. The resulting code is needlessly indirect, yet
at API-level this change is totally a drop-in replacment.
2023-10-13 23:46:38 +02:00
7b25609896 Library: test coverage for self-managed thread
...extract and improve the tuple-rewriting function
...improve instance tracking test dummy objects
...complete test coverage and verify proper memory handling
2023-10-11 21:06:56 +02:00
08c3e76f14 Library: identified design challenges
On a close look, the wrapper design as pursued here
turns out to be prone to insidious data race problems.
This was true also for the existing solution, but becomes
more clear due to the precise definitions from the C++ standard.

This is a confusing situation, because these races typically do not
materialise in practice; due to the latency of the OS scheduler the
new thread starts invoking user code at least 100µs after the Wrapper
object is fully constructed (typically more like 500µs, which is a lot)

The standard case (lib::Thread) in its current form is correct, but borderline
to undefined behaviour, and any initialisation of members in a derived class
would be off limits (the thread-wrapper should not be used as baseclass,
rather as member)
2023-10-07 03:25:39 +02:00
ff052ec5a2 Library/Application: switch Microbenchmark + SyncBarrier tests
...these were already written envisionaging he new API,
so it's more or less a drop-in replacement.

- cant use vector anymore, since thread objects are move-only
- use ScopedCollection instead, which also has the benefit of
  allocating the requires space up-front. Allow to deduce the
  type parameter of the placed elements
2023-10-03 22:56:09 +02:00
201672a0ad Library: reconsider join / stringify API
- it is not directly possible to provide a variadic join(args...),
  due to overload resolution ambiguities

- as a remedy, simplify the invocation of stringify() for the typical cases,
  and provide some frequently used shortcuts
2023-09-29 17:00:13 +02:00
59bb99f653 Library: fix shortcoming with exception-expectations
VERIFY_ERROR allows to check that an expected except is actually thrown.

The implementation was lazy however;
it just investigated the C-style error flag instead of *really* verifying
that an *lumiera::Exception* with the expected flag was caught.

This discrepancy can be a problem when there is a stray error flag set,
or for some reason the error flag gets cleared before the exception
reaches the top-level catch-block in the test.
2023-09-27 01:09:40 +02:00
c183045dfa Library: switch Microbenchmark setup to C++17 threads
Over time, a collection of microbenchmark helper functions was
extracted from occasional use -- including a variant to perform
parallelised microbenchmarks. While not used beyond sporadic experiments yet,
this framework seems a perfect fit for measuring the SyncBarrier performance.

There is only one catch:
 - it uses the old Threadpool + POSIX thread support
 - these require the Threadpool service to be started...
 - which in turn prohibits using them for libary tests

And last but not least: this setup already requires a barrier.

==> switch the existing microbenchmark setup to c++17 threads preliminarily
    (until the thread-wrapper has been reworked).
==> also introduce the new SyncBarrier here immediately
==> use this as a validation test of the setup + SyncBarrier
2023-09-24 18:07:28 +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
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
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
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
fbfbd2a078 Dispatcher+Scheduler: decision to dispose of the TimeAnchor
several years ago, it seemed like a good idea to incorporate
the link between nominal time and wall-clock time into a dedicated
anchor point, which also regulates the continued frame planning.

But it turned out that such a design mixes up several concepts
and introduces confusion regarding the meaning of "real time"
- latency can not be reasonably defined for a whole planning chunk
- skipping or sliding due to missed deadlines can not reasonably handled
  within such an abstract entity; it must be handled rather at the
  level of a playback process
- linking the frame grid generation directly to a planning chunk
  undercuts the possible abstraction of a planning pipeline
2023-05-31 03:27:13 +02:00
e176e54004 Library: adjust and fix semantics of nested 'value_type' binding
This is a subtle and far reaching fix, which hopefully removes
a roadblock regarding a Dispatcher pipeline: Our type rebinding
template used to pick up nested type definitions, especially
'value_type' and 'reference' from iterators and containers,
took an overly simplistic approach, which was then fixed
at various places driven by individual problems.

Now:
 - value_type is conceptually the "thing" exposed by the iterator
 - and pointers are treated as simple values, and no longer linked
   to their pointee type; rather we handle the twist regarding
   STL const_iterator direcly (it defines a non const value_type,
   which is sensible from the STL point of view, but breaks our
   generic iterator wrapping mechanism)
2023-05-23 01:07:53 +02:00
00ca84a2aa test-helper for comparison with expected (string) result
...this is something I should have done since YEARS, really...

Whenever working with symbolically represented data, tests
typically involve checking *hundreds* of expected results,
and thus it can be really hard to find out where the
failure actually happens; it is better for readability
to have the expected result string immediately in the
test code; now this expected result can be marked
with a user-defined literal, and then on mismatch
the expected and the real value will be printed.
2023-05-04 00:48:29 +02:00
52d3231226 Timeline: finish ZoomWindow implementation and boundrary tests 2022-12-18 03:47:40 +01:00
ce1220ee72 Lib: test coverage for rational-int corner cases and integer-log
- detailed documentation of known problematic behaviour
  when working with rational fractions
- demonstrate the heuristic predicate to detect dangerous numbers

- add extensive coverage and microbenchmarks for the integer-logarithm
  implementation, based on an example on Stackoverflow. Surprising result:
  The std::ilog(double) function is of comparable speed, at least for
  GCC-8 on Debian-Buster.
2022-11-14 05:20:37 +01:00
02c5809707 Global-Layer-Renaming: adjust namespace qualification 2018-11-15 23:59:23 +01:00
2d5ebcd5fa Global-Layer-Renaming: adjust header includes 2018-11-15 23:42:43 +01:00
fa6ba76f85 investigate insidious ill-guided conversion
As it turns out, using the functional-notation form conversion
with *parentheses* will fall back on a C-style (wild, re-interpret) cast
when the target type is *not* a class. As in the case in question here, where
it is a const& to a class. To the contrary, using *curly braces* will always
attempt to go through a constructor, and thus fail as expected, when there is
no conversion path available.

I wasn't aware of that pitfall. I noticed it since the recently introduced
class TimelineGui lacked a conversion operator to BareEntryID const& and just
happily used the TimelineGui object itself and did a reinterpret_cast into BareEntryID
2018-10-12 23:42:56 +02:00
258a807e97 EventLog: reorder code to accommodate the split
well... reduction in size of the debug build objects
turns out not to be so large as I hoped. But it is significant anyway,
about 3-4MB on the most affected test classes. Plus from now on we
do not repeat that code on other tests using the same features.
2018-09-20 04:11:00 +02:00
1df5bf5c5e EventLog: split into header and dedicated translation unit (WIP) 2018-09-20 02:19:10 +02:00
9e96effcf1 EventLog: prepare for dedicated translation unit
up to now, EventLog was header only, which seems to cause
a significant bloat in terms of generated code size, especially
in debug builds. One major source for this kind of "template bloat"
is the IterChainSearch, rsp. the filter and transformer iterators.

And since EventLog is not meant for performance critical application code,
but rather serves as helper for writing unit tests, an obvious remedy is
to move that problematic part of the code down into a dedicate translation
unit, instead of using inline functions. To prepare this refactoring,
some var arg (templated) API funcitons need to be segregated.
2018-09-20 01:42:31 +02:00
03a1d58198 EventLog: verify and complete the TestEventLog_test
can now cover all the cases as initially intended,
including backtracking
2018-09-19 02:52:38 +02:00
3994f805b0 EventLog: further bugfix to get the augmented sequencing logic correct.
For the before / after chaining search functions,
we now do one single step in the respective direction before evaluating
the new (next) filter condition. However, we also need to *deactivate* the
previous condition, otherwise that single "step" might cause us to jump
or even exhaust the underlying filter, due to the old filter condition
still being applied.
2018-09-19 01:24:26 +02:00
991b8ace82 EventLog: rectify the quirky logic for before / after chains
due to the lack of real backtracking, the existing solution
relied on a quirk, and started the before / after chained search
conditions /at/ the current element, not after / before it.

Now we're able to remove this somewhat surprising behaviour, yet to do so
we also need to introduce basic "just search" variations of all search
operations, in order to define the initial condition for a chained search.
Without that, the first condition in a chain would never be able to
match on the header entry of the log
2018-09-19 00:21:09 +02:00
0c7996fe90 EventLog: drop-in the new IterChainSerach engine
- need to use dedicated steps in the chain for every added condition now

- seems to break the logic on tests on non-match.
  This doesn't come as a surprise, since backtracking can be expected
  to reveal additional solutions.

NOTE: some tests broken, to be investigated

est-event-log-test.cpp:228: thread_1: verify_callLogging: (log.ensureNot("fun").after("fun").after("fun2"))
2018-09-16 03:02:22 +02:00
9d7ce1e6a4 EventLog: now able to use the CursorGear immediately as state core
...since TreeExplorer automatically does the iterator wrapping for us.
As added benefit, we have now a direct API to control the search direction
2018-09-14 21:06:14 +02:00
75e1eab4bb EventLog: drop-in the new TreeExplorer::mutableFilter
while this is basically a drop-in replacement,
it marks the switch to the monadic evaluation technology,
which is prerequisite for building real backtracking into the search.
2018-09-14 21:06:14 +02:00