Skip to content

Nightly-lane test fixes: strudel worker-clock waits, a refused -exe fails, ownership_semantics passes the collect proof - #4161

Merged
borisbat merged 1 commit into
masterfrom
bbatkin/strudel-reds
Sep 28, 2026
Merged

borisbat merged 1 commit into
masterfrom
bbatkin/strudel-reds

Conversation

@borisbat

@borisbat borisbat commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

Why. The tsan-tests nightly lane fails the strudel worker tests on a busy runner: under tsan on four shared cores the worker renders audio far slower than real time, and the tests budget wall-clock time, so a slow worker fails as if it were stuck. Separately, extended_checks fails run_example_ownership_semantics: a refused -exe build exited 0 without an executable.

What changes.

  • A shared tests/strudel_device/_strudel_device_common.das waits on the worker's own clock (seconds of audio rendered) and fails only when that clock stands still for 30 s of real time.
  • test_worker_heap drops its 90 s total wall cap and reports a stretch a stall cut short; test_worker_no_gc waits on the worker's clock instead of fixed sleeps.
  • test_sound_status_seqbox accepts playing as well as starting right after set_status_update, and plays a 10 s tone so a slow reader cannot see it end.
  • test_vowel's tick test failure message reports the peak and the energy.
  • A refused -exe build fails the process (LLVM EXE: no executable written for ...), like a refused -lib, on both the single-module and the --jit-split-modules path.
  • ownership_semantics.das runs its collect in a main with no locals, so the collect-carrier proof clears it; the llvm_exe_thread_collect fixture's thread and job lambdas carry [unsafe_heap_collect].

Observable behavior.

  • daslang -exe on a program the collect proof refuses: exit 0, no executable -> exit 1 with the reason
  • extended_checks run_example_ownership_semantics: "no such file" -> the example builds and runs
  • tsan worker tests on a contended 4-core box: red about one run in three -> green
  • a worker whose clock never moves: 90 s wall cap -> fails after 30 s with where its clock stopped
  • test_vowel tick failure: expected success, got failure -> the peak and energy it measured

Where to look. wait_worker_until in _strudel_device_common.das, and the relaxed state check in test_sound_status_seqbox.das.

#nightly

Validation, claims, ledger

Validation

  • WSL CI mirror, CI's tsan configure at current master, tests/strudel_device pinned to 4 cores beside 6 busy loops: before, 1 of 3 runs red with the nightly's signature (20 then 0 distinct numbers at 91 s) plus the seqbox playing race; after, 5 of 5 green. Unloaded: 30/30.
  • Controls: a stall timer never reset on a clock advance (a 30 s total budget) fails the loaded warm-up 2 of 2; a worker that never starts fails after 30 s on the stall message.
  • One process compiling tests/linq then tests/strudel_device (the release.yml shape): 2104/2104; the same with the helper named _common fails to compile against linq's module.
  • test_vowel: interpreter, -jit, and test_aot (--target test_aot, dasAudio on, WSL) pass; the fastmath LLVM-AOT lane rebuilt verbatim ran 11489/11489 and the tick test 0/300 red - the one CI failure did not reproduce.
  • -exe fix (WSL, current master, LLVM on): the old example now exits 1 with the new message; the restructured one builds, and its exe and the interpreter run clean; run_examples all pass; llvm_exe_thread_collect 2/2 (refused silently on master); tests/jit_tests 400/403 (3 skipped); a refused --jit-split-modules build exits 1. dasLLVM's module suite (dastest -jit --test modules/dasLLVM/tests, same fastmath build): master 105/130 with 24 failing, this branch 106/130 with 23 - the one difference is llvm_exe_thread_collect; the rest fail identically on both (llvm_jit_debug_info 8, llvm_jit_link 6, llvm_vector_math 5, llvm_jit_global_lookup 2, llvm_tune_profiles 1, llvm_exe_split_lto 1).
  • Not run: the full preflight; the Windows build here has audio off, so these tests ran only in WSL.

Claims - stated, not tested

  • The relaxed seqbox check no longer tells a seed of playing from a seed of starting in set_status_update; an empty box still fails.

Not done

  • The one-off test_vowel red under fastmath LLVM-AOT: LLVM-AOT targets the host CPU and the runners vary; not reproducible on a Zen 2 box without AVX-512. Ledgered.
  • llvm_exe_split_lto fails 1/7 on master: it looks for a LOG_INFO announce line that the default DAS_LOG_LEVEL drops. It and llvm_exe_thread_collect run in no CI lane, which is how both rotted unseen. Ledgered.
  • make-pr --no-preflight prints "all mechanical gates green" without running review-md or ast-verify: ledgered as a tool fix.

Copilot AI balanced review requested due to automatic review settings September 28, 2026 17:22
@borisbat

Copy link
Copy Markdown
Collaborator Author

daspkg_index / index_sweep is red on every run since dasSDL3 (Windows-only) joined the index - see #4158's comment; not this PR's, and this watch ignores that lane.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The changes are test-only, low-risk, and internally consistent, but they alter concurrency/timing synchronization whose flakiness-elimination can only be confirmed by the author's runtime validation under sanitizers, warranting human sign-off.

Review effort: Balanced
Findings: None

What changed in this PR

This PR makes the strudel device-audio tests robust to slow execution under the tsan-tests nightly lane, where a sanitizer build on a contended runner renders audio far slower than real time. Previously the tests budgeted wall-clock time, so a slow-but-working worker failed as if stuck. The tests now synchronize on the worker's own playback clock (seconds of audio rendered) and fail only when that clock genuinely stalls (no advance for 30 s of real time). It also improves a test_vowel failure message to report the measured peak/energy.

Changes:

  • Adds a shared _strudel_device_common.das module (worker_seconds, wait_worker_until with a stall-timer that resets on each clock advance) and reuses it across the worker tests.
  • Refactors test_worker_heap to poll on worker time (dropping the 90 s wall cap and reporting a stalled stretch) and relaxes test_sound_status_seqbox to accept playing as well as starting, with a 10 s tone so a slow reader can't see it end.
  • Adds energy tracking and a descriptive failure message to test_vowel.
File Description
tests/​strudel_device/​_strudel_device_common.das New shared helper: worker clock accessor and stall-aware wait_worker_until (2-arg + convenience 1-arg overloads).
tests/​strudel_device/​test_worker_heap.das Drops local clock/wait helpers and the wall cap; sample_stretch now polls via a block, adds a finished flag surfaced in the assertion message.
tests/​strudel_device/​test_worker_no_gc.das Replaces fixed sleeps with wait_worker_until; uses the shared module.
tests/​strudel_device/​test_sound_status_seqbox.das Accepts starting or playing after registration; plays a 10 s tone; updated test description.
tests/​strudel/​test_vowel.das Accumulates energy and reports peak/energy in the tick-test failure message.

Verification highlights: ref_time_ticks→int64, get_time_usec→int (so WORKER_STALL_MS * 1000 = 30,000,000 stays in int range); success(tb; a; msg="") supports the added messages; the continue if→return if rewrite is correct because a $-block return is block-scoped (confirmed against daslib/lint.das:1390); _-prefixed helpers are excluded from test discovery (dastest/fs.das:106); and no stale references to the removed WALL_CAP_MS/old signatures remain.


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@borisbat

Copy link
Copy Markdown
Collaborator Author

extended_checks (darwin15, all) fails in run_example_ownership_semantics (the compiled ownership_semantics.das.exe is not found to run) - the same red hit today's runs of other branches (aleksisch/string-null-byte job 109027108367, achurkin/jit-sanitize job 108994941763; that branch's later run passed), so it is intermittent on master's code, not this PR's. This watch ignores that lane.

…fused -exe fails; ownership_semantics passes the collect proof

The tsan-tests nightly lane failed test_worker_heap ("7 then 0 distinct numbers" at the 90 s wall
cap) and test_worker_no_gc (no heap published 2.5 s in). Under tsan on a contended 4-core runner the
worker renders audio at a fraction of real time, so a wall-clock budget fails a slow worker as if it
were stuck. tests/strudel_device/_strudel_device_common.das waits on the worker's own clock - seconds
of audio rendered - and fails only when it stands still for 30 s of real time: test_worker_heap drops
its total wall cap and reports a stretch the stall cut short, and test_worker_no_gc waits on the
worker's clock instead of fixed sleeps. The module name is unique: a second `_common` loses to
tests/linq's shared one when a single process compiles the whole suite.

test_sound_status_seqbox read `playing` right after set_status_update under the same load - the
audio thread picked the sound up before the read. The box still must not read empty; `starting` or
`playing` both pass, and the tone runs 10 s so a descheduled reader cannot see it finish.

A refused -exe build now fails the process: the exe branch of llvm_jit_run logged the refusal
and returned success, so extended_checks' example runner compiled `ownership_semantics.das`
"clean" and then found no .exe to run. The example itself trips the collect-carrier proof -
`main` held a Terminal across its heap_collect - so the collect now runs in a `main` with no
locals and the checks move to their own function. The llvm_exe_thread_collect fixture's thread
and job lambdas collect on stacks the host starts empty; they and `main` carry
[unsafe_heap_collect], as the proof's escape for that case intends.

test_vowel_filter_tick_produces_output failed once under fastmath LLVM-AOT and does not reproduce;
its failure message now carries the peak and the energy, where a NaN shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@borisbat
borisbat force-pushed the bbatkin/strudel-reds branch from 1356a85 to 3d87033 Compare September 28, 2026 18:27
Copilot AI review requested due to automatic review settings September 28, 2026 18:27
@borisbat borisbat changed the title Strudel device tests wait on the worker's clock; test_vowel names its peak Nightly-lane test fixes: strudel worker-clock waits, a refused -exe fails, ownership_semantics passes the collect proof Sep 28, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

It alters the LLVM JIT executable-generation driver's failure behavior and the GC collect-carrier proof semantics — subtle codegen/runtime areas whose end-to-end correctness was validated only in the author's local WSL build and warrants human sign-off.

Review effort: Balanced
Findings: None

@borisbat
borisbat merged commit 593a9af into master Sep 28, 2026
69 checks passed
@borisbat
borisbat deleted the bbatkin/strudel-reds branch September 28, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants