-
Notifications
You must be signed in to change notification settings - Fork 160
add c/c++ testing infrastructure and tests + fix for clock internal and jack client timing issues #1867
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
looks like a GitHub action error when checking out the incoming changes. may need to manually retry. |
|
hm. something is up with the addition of the test framework submodules within the GitHub i think i will remove the c/c++ test action from this pr, and add it as a follow up pr rebased on top of this work once it's reviewed and merged in. hopefully that will resolve it. |
|
ha! ok well that was silly of me. forgot to actually commit the added submodules. works. 🎉 |
670d824 to
f36029c
Compare
|
Excellent! I’m not going to have time to give this a close review but the overall shape looks good and I think getting it in sooner is better.
Never mind the above, this looks like the rebase and merge will leave a neat history, great stuff! |
|
What an incredible contribution! I've reviewed this a bit and generally approve -- though echoing @Dewb 's original comment I would like to see @65c139a in particular split up into one There are some potential changes in behavior regarding the clock fixes, so I think we should take our time reviewing in that case. But overall the test additions look nice and are well documented. |
|
Happy to take some time to split up the changes and the tests. Reorganizing the commits might make it a bit easier to observe the failing tests and review the changes that allow them to pass. I will try if possible to stack commits so that they are:
This should sort the work nicely. |
… mapping - implements automatic test discovery in tests/wscript. - discovers test_*.cpp files and builds one binary per directory. - mirrors test paths to system sources (tests/matron/test_foo.cpp → matron/src/foo.c). - handles snake_case and CamelCase variants. - includes test runner self-tests for validation of test runner integrity. updates root wscript to register test command and enable waf_unit_test feature. sets C++14 standard which is required by trompeloeil and safe to change to.
provides common test entry point for all test binaries.
formats test files (.c, .h, .cpp, .hpp) alongside system sources.
validates raised cosine window: array size, value range [0,1], and endpoints. adds out-of-class definition for raisedCosShortLen to crone/src/Window.cpp required by tests.
- rise/decay/negative/zero behaviors, getPos range and monotonicity - includes taper_vu_table_stub test helper which provides simple linear lookup table
validates IEC-60268 perceptual taper: output range [0,1], saturation above unity, monotonic non-decreasing behavior across amplitude range, and precise anchor points at 0.1/0.5/0.9 against actual lookup table interpolation.
d4b5482 to
31ceb09
Compare
|
not gonna block this, but these changes make the clock code difficult to read (and modify). i wonder if that's possible to fix the original integer overflow problem in jack instead, for instance? as to testability modifications, they reduce readability too, although to a lesser extent. i would like to raise a concern on what's the value of these tests being executed on every change (after the code has already been tested)? |
774dad7 to
e949621
Compare
|
Hi @tlubke, thanks for the review and feedback.
Thanks! I'm really excited for this addition.
I've rearranged the commits and pushed.
Agreed. I am happy to report that I have been able to run scripts like |
|
Hi @artfwo, thanks for having a look and for the feedback! I spent some time reworking the changes to The jack client integer overflow is addressed with e949621. Regarding your concern about the value of these tests: I feel strongly that they improve the codebase. I've made sure to include caching in the GitHub action to attempt to reduce the latency of building. The tests themselves are extremely fast. They deterministically exercise and showcase aspects of the code that previously required manual testing. They run on each future change and contribution to ensure there are no regressions to expected behavior. Introducing seams into existing code does make it a bit more challenging to read, but seams are light touch and allow control and testability without requiring major refactor/rewrite. Happy to discuss more. Again, thanks for having a look. |
right, but what i meant was - if bit depth of |
|
Thanks for the added clarity here! I will definitely have another look when I'm back at my desk. In the meantime if you have a moment, I would be curious to know if you have more thoughts on what the solution might look like here practically based on your note. Pseudo code would be fine. More soon. |
well, my idea is that there won't be a need for any (pseudo) code, if jack returns 64-bit frame counter. |
|
another option could be using jack function |
|
@artfwo Thanks again for your response.
If jack were to receive an update to its API to operate in 64-bit frames, the wrap logic would basically become a no-op where
I hadn't tried this. The documentation for Digging a little bit into the implementation details of The 32-bit frames that jack produces are not a bug, and it turns out the recommended solution is in the JACK audio documentation:
This function is where After marinating with the code for a while and reviewing these docs, I am convinced that the changes to the norns |
i haven't investigated the code thoroughly, but doesn't that mean that it already does all the work necessary to get the monotonic driver time in seconds (basically what we need for the clock)? is non-linearity actually something we should worry about, given that softcut and supercollider may have non-linear clocks too? |
No. I did dig into this a bit and using the We need to do the work of maintaining the last frame and stay in frames as a unit for the wrap logic. This keeps the norns internal clock locked to the audio clock. I wouldn't recommend changing this as it would introduce drift/jitter/etc., relative to the audio output.
Softcut and Supercollider operate linearly and are locked to the hardware sample clock. Using |
|
oh well, that's a bummer. i've raised a jack issue about the size of |
cf37aca to
40384e2
Compare
|
I've pushed the update to the I updated the test scaffolding slightly to properly seed the internal state for the wrap scenarios, and everything continues to pass. 🎉 |
|
Thanks @artfwo for the discussion and for taking a look. It was good for me to comb through the details on the |
- switch args parsing to snprintf (truncates, and terminates). - wire up -f framebuffer. - add framebuffer accessor - update help text.
40384e2 to
05f67e8
Compare
|
@colinmcardell github is complaining that the cpp test isn't passing, any ideas? https://github.com/monome/norns/actions/runs/20679127201/job/59370833961 |
I will have a look next time I'm at my desk. Thanks. |
|
I've had a look, the test was passing fine locally, but it seems to be flaky on the more constrained Github CI. I've patched up a flaky test. I will open a PR with the fix soon. |
what
adds c/c++ testing infrastructure with doctest and trompeloeil frameworks, automatic test discovery in
tests/wscript, c/c++ test workflow to github actions, documentation and contribution notes, and the beginnings of test coverage across matron and crone components.the unit tests included in this pr showcase multiple approaches of test coverage (mocks, stubs, test seams, etc.) and exercising code to ensure the expected behavior. these initial tests establish testing patterns and providing a nice reference along with the documentation.
also included in this pr are various important fixes for clock time tracking (see details below), as well as minor threading, and args parsing issues discovered during test development.
fixes #1863
how
see included
tests/README.mdfor detailed documentation on how the testing infrastructure works.testing infrastructure
tests/wscriptthat mirrors test paths to source treetest.shwrapper script to build and run testsclang_format.shincluded coverage
NORNS_TESTpreprocessor seams for exposing private interfaces during tests without changes to the core codedocumentation
tests/README.mdwith detailed examples and patternsCONTRIBUTING.mdwith testing guidelinesimprovements discovered during initial test coverage implementation
clock internal
issue
clock loop enters catchup spiral when experiencing lag (potentially scheduler delays, JACK stalls, system suspend, NTP adjustments), causing timing jitter for minor lag, burst publishing for moderate lag, or complete CPU lockup for severe lag. when time jumps forward,
next_tick_time - current_timebecomes large and negative, producing invalid timespec values, stalled thread sleeps, and frozen tempo updates.mentioned here #1865.
fix
clamp negative sleep values to zero before timespec conversion. rebase
next_tick_timeforward when schedule falls more than one tick behind.test
stub
clock_nanosleepfor virtual time control, jump forward by hours, verify valid sleep calculations and continued tempo publishing.jack_client
issue
JACK's 32-bit frame counter wraps after ~25 hours (48kHz), causing time to jump backward 25 hours and breaking all tempo/scheduling. out-of-order reads between calls can also cause time to decrease slightly.
a simple repro for this is to load up the
firstlightscript, let it run for ~25 hours, and watch the animation hang.related to clock internal above and also mentioned here #1865.
fix
maintain 64-bit monotonic frame counter tracking high/low 32 bits separately. detect wraps when low bits cross from high to low range and increment high bits. enforce monotonicity with mutex-protected read-modify-write operations.
test
stub JACK frame values, simulate wraparound (
0xFFFFFFF0→0x00000020), verify monotonic time across boundary and consistent multi-threaded reads.additional improvements
args: switch tosnprintffor safe truncation, wire up-fframebuffer flag which wasn't connected previouslyevent_types.h: decouple heavy includes, add opaquelo_messagetypenotes
wscript), this is a safe change.