Repository navigation
Fix macOS + determinism CI: Release rejectSimKey guard; preemption-tolerant system timing tests - #46
Merged
Conversation
… timing tests Two red jobs on master after M1-CFG-01 (cf6c850): 1. Determinism check — 'Build Release (g++)' failed: src/laige-sim/config.cpp:585 — 'kConfigHotReloadRejectedMessage' was not declared in scope. rejectSimKey (the hot-reload rejection helper) names a debug-only message constant (config.h declares it under #ifndef NDEBUG) but the helper itself was not guarded, so the Release build (the only Release build in CI, the detcheck job's pair B) errored. Guard rejectSimKey with #ifndef NDEBUG: the Release poll/create paths return early and never reach the helper, and compiling it out keeps both trees warning-free (unguarded it is an error; declared-but-unused it would be -Wunused-function under -Werror). 2. macOS arm64 — SystemTiming.OverBudgetSystemWarnsAtTheDocumentedMultiplier failed: the test assumed the 6.5 ms busy-wait burn stays under the 15 ms (3x the 5 ms budget) critical threshold — 'the margin holds even under preemption' — but a shared-runner deschedule stretched the run past 3x, so the documented budget_critical ERROR fired in addition to the warn and the exact-entry-count assertion failed (2 entries, expected 1). Preemption can only stretch a measured run, never shorten it, so the test now branches on the measured time: nominal (warn only) vs stretched (warn + same-tick critical), with the counters, rate-limit summaries, and entry counts asserted per branch. Every possible measured time maps to a consistent, documented state — the test is immune to the preemption that failed it. - EventsFollowTheErrorGrammar had the identical latent flake (its warn-only system's event sequence depended on whether preemption stretched it past 3x): both systems now carry the 2 ms budget so both event classes fire on every tick deterministically. - The two healthy-path tests' 1 ms budgets are the same flake family (a >1 ms preemption on a microsecond noop tick fires a warn and breaks the silence assertion): budgets raised to 100 ms, the shared-runner noise floor this repo already treats as negligible (the archetype churn's preemption-immunity rationale). Validated: full CI detcheck job replica green locally (4 build configs: reference Debug g++, clang++ Debug, Debug+ASan clang++, Release g++; baseline sanity, synthetic self-check, pairs A and B both backends); laige-sim_tests full suite green in the Debug tree; the stretched branch exercised with a forced 16 ms burn (scratch build, both branches' assertions pass); clang/ASan/TSan trees build and pass the system_timing entry.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the two red jobs on master after #45 (run 35603728019).
1. Determinism check —
Build Release (g++)compile errorsrc/laige-sim/config.cpp:585:kConfigHotReloadRejectedMessagewas not declared in scope. The M1-CFG-01 hot-reload helperrejectSimKeynames a debug-only message constant (declared inconfig.hunder#ifndef NDEBUG), but the helper itself was not guarded — so the Release build (the only Release build in CI, the detcheck job's pair B) failed to compile.Fix: guard
rejectSimKeywith#ifndef NDEBUG. The Releasepoll/createpaths return early and never reach the helper; compiling it out keeps both trees warning-free (unguarded it is a hard error; declared-but-unused it would trip-Wunused-functionunder-Werror).2. macOS arm64 — flaky
SystemTiming.OverBudgetSystemWarnsAtTheDocumentedMultiplierThe test assumed the 6.5 ms busy-wait burn stays under the 15 ms critical threshold (3× the 5 ms budget) — "the margin holds even under preemption". A shared-runner deschedule stretched the run past 3×, so the documented
budget_criticalERROR fired alongside the warn and the exact-entry-count assertion failed (2 entries, expected 1). macOS Intel passed the same run by luck; the failure is preemption-driven, not arch-specific.Key fact: preemption can only stretch a measured run, never shorten it. So the test now branches on the measured time:
Counters, rate-limit summaries, and entry counts are asserted per branch; every possible measured time maps to one consistent, documented state, so the test is immune to the preemption that failed it. The 1×/3× multiplier contract, warn-before-critical order, and LOG-004 rate limiting are all still asserted (the sibling
CriticallyOverBudgetSystemErrorsAfterTheWarnpins the same-tick order unconditionally).Same latent flake family, fixed in the same change:
EventsFollowTheErrorGrammar— its warn-only system's event sequence depended on whether preemption stretched it past 3×. Both systems now carry the 2 ms budget, so both event classes fire on every tick deterministically; the NFR-13.3 grammar is checked on the same two event classes, and the LOG-004 summaries are asserted per class.HealthyTicksLogNothingAndTrackStats/HealthyTicksAllocateNothing— 1 ms budgets on microsecond noop ticks: a >1 ms preemption fires a warn and breaks the success-path silence assertion. Budgets raised to 100 ms — the shared-runner noise floor this repo already treats as negligible (the archetype churn's preemption-immunity rationale).lastMsupper bound moves from 1.0 to the 100.0 budget; the tracked-state assertions (runs, counters, window) are unchanged.RollingWindowDropsOldestSampleskeeps its 7 ms/50 ms/5 ms parameters: its core assertions (count/totalRecorded rollover) are already preemption-immune, and separating a 7 ms burn from preemption-stretched fast ticks is impossible at any finite threshold — noted as a residual, much lower-probability flake risk rather than re-engineered.Validation
fixed_point_16_16andfloat_pinned_32.laige-sim_testsfull suite (88 ctest entries) green in the Debug tree.system_timingentry green in the clang++, ASan, and TSan trees (all warning-clean under-Wall -Werror).