Skip to content

[M1-BENCH-01] laige-bench sim-tick suite: 10k-entity tick budget on both SimMath backends - #52

Merged
offdev merged 5 commits into
masterfrom
m1-bench-01-sim-tick
Sep 25, 2026
Merged

offdev merged 5 commits into
masterfrom
m1-bench-01-sim-tick

Conversation

@offdev

@offdev offdev commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Implements M1-BENCH-01 (roadmap/M1-heartbeat.md).

What

The PRD §8.1 "Simulation tick" workload as a laige-bench suite (--suite=sim-tick):

  • Workload — 10 000 entities at the 100% scene budget, 2 000 dynamic bodies (Position2D<B> + a BenchVel<B> component, both marked deterministic-safe), 8 000 bare entities; deterministic seed 0x1F055EED, index-derived initial state (no RNG in the measured path).
  • Systems — BenchMove (1 ms budget, pos += vel via the active backend's SimMath::add) and BenchHash (2 ms budget, the per-tick World::stateHash).
  • Driver — the engine's GameLoop at 60 Hz on an exact synthetic clock (one due tick/frame); one measured sample = one completed tick; 1 000 warm-up + 3 000 measured ticks.
  • Backends — both SimMath backends (--math=fixed_point_16_16 / float_pinned_32), both must pass (ADR 0002).
  • Zero-alloc — in debug non-sanitizer builds, every measured tick additionally passes the engine's own G-R1 per-tick zero-allocation assertion (M1-ALLOC-01); an allocating tick aborts the run.

Tool changes

  • --math=<fixed_point_16_16|float_pinned_32> — SimMath backend selection for the sim-tick suite (default fpx16).
  • Repeatable --budget=<name> — one run checks every named budget against the same histogram (the M1 gate: avg AND p99 in one run); duplicate name = usage error; any FAIL exits 2.
  • Compiler-id fix: Clang is now identified before GCC (Clang 22 defines __GNUC__ and its __VERSION__ is "Clang 22.1.8" — the old order mislabeled clang builds as "GCC Clang 22.1.8").

CI gate

New ctest entries laige_bench_sim_tick_fpx16 / laige_bench_sim_tick_fp32 (canonical 3000/1000 shape, both budgets, repo-root budgets.json via LAIGE_BUDGETS_PATH) run in every non-instrumented P0 job's full ctest — this is the PRD §14 CI perf lane for the sim tick. Excluded from the ASan/TSan trees: instrumentation inflates the tick's absolute cost (~2.7× under ASan+UBSan), so a sanitizer measurement would measure the instrumentation, not the sim (the m1-profiler-cost precedent). A budget FAIL exits 2 and fails the CI job.

Results (canonical Debug, g++ 16.2.1, AMD Ryzen 9 7950X3D / CachyOS)

Backend mean (ms) p99 (ms) Target
fixed_point_16_16 0.59283 0.618314 ≤ 3.0 / ≤ 5.0
float_pinned_32 0.589047 0.605951 ≤ 3.0 / ≤ 5.0

Both backends PASS (5.1× / 8.1× inside the budgets). The run's final_hash fingerprint is bit-identical across all four non-instrumented local trees and both compilers (g++ 16.2.1 / Clang 22.1.8), at both backends (fpx16 0x8aa6b855aa807b31, fp32 0x34ff9f20dac09426).

budgets.json gains its first recorded measured values (worse of the two backends): sim_tick_avg 0.59283, sim_tick_p99 0.618314.

Baseline + docs

  • Fourth baseline: docs/benchmarks/baselines/m1-sim-tick.md — full AGENTS §12 metadata, verbatim budget-checked runs, the ctest gate, cross-tree/cross-compiler table, interpretation. Records that M1 measures the ECS-only slice of the §8.1 workload (kinematic movement + state hash; physics lands in M3, presentation in M4).
  • docs/benchmarks/README.md + docs/benchmarks/baselines/README.md — stale "every entry still measured: 0" text replaced; the missing m1-profiler-cost baseline entry added.
  • docs/api/budget_harness.md — the new CLI form, the sim-tick suite, the measured-field note, both suites' determinism.

Local verification

Full ctest green on all six local trees: 94/94 build/build-clang/build-shared, 93/93 build-release, 92/92 build-asan/build-tsan (gate entries correctly absent there); ASan run leak-free, TSan halt_on_error=1 race-free (one legitimate G-R5 budget_overrun warn on BenchHash under the 4× TSan slowdown — correct engine observation); zero new warnings under NFR-8.10; include-lint + determinism-lint OK; no new public API (laige-api.json unchanged).

…oth SimMath backends

The PRD 8.1 simulation-tick workload as a laige-bench suite: 10k entities
(2k dynamic bodies with Position2D + velocity, 8k bare), 60 Hz through
the GameLoop on an exact synthetic clock, BenchMove + BenchHash (per-tick
state hash) systems, 3000 measured ticks after 1000 warm-up, checked
against sim_tick_avg (<=3.0 ms) and sim_tick_p99 (<=5.0 ms) on BOTH
SimMath backends (ADR 0002). In debug non-sanitizer builds every measured
tick additionally passes the engine's own G-R1 per-tick zero-allocation
assertion (M1-ALLOC-01).

Tool: new --math=<fixed_point_16_16|float_pinned_32> option, repeatable
--budget (one run gates every named budget against the same histogram),
suite setup/teardown hooks, compiler-id fix (Clang before GCC — Clang 22's
__VERSION__ is 'Clang 22.1.8' and the old order mislabeled clang builds).

CI gate: laige_bench_sim_tick_{fpx16,fp32} ctest entries in every
non-instrumented P0 job's full ctest (excluded from ASan/TSan trees —
instrumentation inflates the tick cost, the m1-profiler-cost precedent);
a budget FAIL exits 2 and fails the job (PRD 8.1 regression gate).

Results (canonical Debug g++ 16.2.1, AMD Ryzen 9 7950X3D):
  fpx16_16  mean=0.59283 ms  p99=0.618314 ms
  fp32_pinned mean=0.589047 ms p99=0.605951 ms
Both backends PASS (5.1x / 8.1x inside the budgets). The run's final_hash
is bit-identical across all non-instrumented local trees and both
compilers, at both backends.

budgets.json measured (worse of the two backends, first recorded values):
  sim_tick_avg 0.59283 ms / sim_tick_p99 0.618314 ms.

Fourth baseline: docs/benchmarks/baselines/m1-sim-tick.md (full AGENTS
12 metadata, verbatim runs, cross-tree/cross-compiler table). Docs
updated: benchmarks READMEs, budget_harness.md.
M1-BENCH-01 is complete (sim-tick suite, both SimMath backends, first
recorded budgets.json measured values, fourth baseline) and CI-verified
(PR lane run 36152843429: linux-gcc/clang full ctest green including the
two sim_tick budget gate entries, detcheck both-backend baselines,
sanitizer lanes, lints, API manifest).

Progress Board: M1 25/25 complete (the board Total row also corrected
41 -> 47, which had gone stale across the last M1 steps). The gate's
Recorded evidence block (the three CI links) lands in this PR's
follow-up commit once the full P0-matrix run (ci:macos + ci:windows
labels) is green.
The initial-state formula stacked the 2 000 dynamic bodies in a single
grid column: x = (i / 2000) % 50 - 25 is 0 for every i < 2000, so the
bodies never spread over the documented 50x50 grid (one body per cell
of the first 2000 cells). Fixed to x = (i / 50) % 50 - 25 (column-major
over the grid span), matching the documented workload.

Re-measured on every tree after the fix (the initial state changed, so
the final_hash fingerprints changed — determinism across trees and
compilers re-verified, bit-identical again):
  canonical Debug g++ 16.2.1: fpx16_16 mean 0.598405 / p99 0.606001,
  fp32_pinned mean 0.591438 / p99 0.615179 (both budgets PASS, 5.0x /
  8.1x inside target); Release 0.0801/0.0844; Clang 0.9133/0.9360;
  shared 0.6237/0.6393; ASan leak-free 1.6397; TSan race-free 2.4497.
Numbers moved <2% (the iteration cost is archetype-bound, not
position-value-bound); the budget result is unchanged.

budgets.json measured updated to the post-fix values (worse of the two
backends): sim_tick_avg 0.598405, sim_tick_p99 0.615179. The baseline
doc and the M1-BENCH-01 changelog line carry the corrected values, and
the baseline's Interpretation records the fix (same PR, before merge).
@offdev offdev removed the ci:macos label Sep 25, 2026
…S evidence)

The PR-lane label protocol runs one P0 OS family per run: no labels =
linux-gcc/clang/asan/tsan, ci:windows (no ci:macos) = windows-msvc,
ci:macos = macos-arm64/intel. The M1-EXIT-01 gate requires replay
bit-exactness evidence on every P0 OS job for this PR's code; the
Linux lane ran on 36152843429 (c2287c1), the macOS pair on
36155154836 (this commit's parent), this empty commit selects the
Windows lane.
@offdev offdev removed the ci:windows label Sep 25, 2026
The three gate items, with their CI evidence links:
(1) sim-tick budget green on both SimMath backends — the baseline
report + PR-lane runs 36152843429 (linux-gcc/clang full ctest 94/94
with the two budget-gate entries) and 36155154836 (macOS arm64/Intel
full ctest, same entries green on AppleClang); the CI reference
machine (ubuntu-24.04) is the gate.
(2) replay bit-exact on CI across all P0 OS jobs and both backends —
the determinism matrix + merge-lane run 36037080146 (all 7 P0 jobs +
detcheck on master) and this PR's label-gated P0 matrix: Linux run
36152843429, macOS arm64/Intel run 36155154836, windows-msvc run
36156322585 — every job green, including hello_baseline_fpx/fp32 in
each OS job's ctest and the detcheck job (both backends).
(3) zero-alloc assertion green on the 10k workload — the zero_alloc
ctest entry green in every P0 job's full ctest in the runs above, and
the M1-BENCH-01 measurement itself zero-alloc-asserted per tick (G-R1).
Deferred P1 items: none — every M1 step is P0.
Progress Board: M1 25/25 complete (total 47/193), set in the prior
commit; the M1-BENCH-01 changelog line's stale 1.6/0.59 ms ASan
mention corrected to the post-fix 1.64/0.60 ms in the same change.
@offdev
offdev merged commit 1db980c into master Sep 25, 2026
11 checks passed
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.

1 participant