Skip to content

[M1-ECS-07] ECS stress + memory accounting test - #23

Merged
offdev merged 2 commits into
masterfrom
m1-ecs-07-ecs-stress
Sep 14, 2026
Merged

offdev merged 2 commits into
masterfrom
m1-ecs-07-ecs-stress

Conversation

@offdev

@offdev offdev commented Sep 14, 2026

Copy link
Copy Markdown
Owner

Implements roadmap step M1-ECS-07 · ECS stress + memory accounting test (scope only; no other changes).

What

New EcsStress suite in laige-sim_tests (CTest entry ecs_stress, added to the TSan property list):

  • 10k entities at the 100% scene budget (capacity 10000), 6 component types (4/8/8/16/8/4 B — distinct column strides), 10k frames of add/remove churn.
  • Each frame: beginFrame() drives G-R3/G-R4, then 64 seeded Tag adds + 64 Tag removes (cyclic Fisher-Yates permutation, TestPrng substream 1008; 128 ops/frame — the default 256 G-R4 budget is never exceeded), then one each<Pos, Tag> iteration (Read, Read) with visit count + 64-bit FNV-1a checksum.
  • A 700-frame warm-up (one full 625-frame cohort period + margin) brings every archetype's columns to their high water before the window, so the window's zero reservation/growth delta is the "pool high-water stable" claim (measured high water: 9 archetypes, 24,592 reserved rows, 549,024 bytes).

Verified properties (the step's Scope)

Property Check
No leaks ctest -R ecs_stress green on build-asan (37.7 s, no ASan/UBSan report)
Pool high-water stable zero totalReservations/totalArchetypeGrowth delta across the 10k-frame window
Iteration within documented cost (query.h) window-wide ns/visit throughput floor: 600 ns; measured 58.7 ns (g++ 16.2.1, -O0 Debug) / 72.3 ns (clang++ 22.1.8)
Zero-allocation window test-only operator-new counter (== 0); sanitizer trees: leak-free run + delta
Memory accounting (PRD §8.1 base memory) 110,000 entity bytes + 549,024 reserved row bytes; machine-greppable ecs-stress window/iteration/memory lines on every ctest run

The window/memory lines are byte-identical across g++ and clang++ (pure integer workload, ARCH-010) and across repeated runs. No new guardrail warns in the window (churnWarns delta 0; the entity-budget warns fire once at setup and never re-cross).

Baseline

Second baseline file: docs/benchmarks/baselines/m1-ecs-stress.md — full AGENTS §12 metadata, verbatim runs (canonical, ASan, cross-compiler), cross-tree results. Not a budgets.json workload, so no measured field is updated. Baselines index + benchmarks README updated to match.

Local verification

  • ctest -R ecs_stress green on build (Debug g++, 14.7 s), build-asan (required Verify), build-release, build-clang, build-tsan, build-shared
  • Full suite 40/40 on build, build-asan, build-clang; laige-sim_tests + ecs_stress green on the other trees
  • Zero new warnings under NFR-8.10 on all trees
  • No public API added (laige-api.json unchanged, 452 symbols — api-real-tree green); no include-graph change

Note

This PR also adds the retroactive M1-ECS-06 row to the roadmap change log (and the matching board counts, M1 5→7 / total 27→29): M1-ECS-06 merged (675fb94, #22) without updating roadmap/README.md. Same pattern as the M0 retro rows.

Roadmap step M1-ECS-07 (roadmap/M1-heartbeat.md), scope only.

Stress test (new EcsStress suite, CTest entry ecs_stress):
10k entities at the 100% scene budget, 6 registered component types,
10k frames of add/remove churn. Each frame: beginFrame() drives the
G-R3/G-R4 guardrails, 64 seeded Tag adds + 64 Tag removes (cyclic
permutation, default 256 churn budget never exceeded), then one
each<Pos, Tag> iteration (Read, Read) with visit count + 64-bit
FNV-1a checksum. A 700-frame warm-up (one full 625-frame cohort
period + margin) lets every archetype's columns reach their high
water before the measured window.

Verified properties (the step's Scope):
- no leaks: green ctest -R ecs_stress in the ASan tree (leak check),
  40/40 on build-asan
- pool high-water stable: zero totalReservations/totalArchetypeGrowth
  delta across the 10k-frame window (high water: 9 archetypes,
  24592 reserved rows, 549024 bytes)
- iteration within the documented cost (query.h): window-wide
  ns-per-visit throughput floor (600 ns; measured 58.7 ns g++ /
  72.3 ns clang++ on the -O0 Debug trees)
- zero-allocation window (test-only operator-new counter,
  non-sanitizer trees; sanitizer trees: leak-free run + delta)
- guardrails silent in the window (churnWarns delta 0; the 100%
  entity-budget warn fired once at setup and never re-crosses)

Memory accounting (PRD 8.1 base memory, accounted bytes): 110000
entity bookkeeping bytes + 549024 reserved row bytes at the 100%-full
scene; machine-greppable ecs-stress {window,iteration,memory} lines on
every ctest run. Baseline recorded in
docs/benchmarks/baselines/m1-ecs-stress.md (AGENTS 12 fields; not a
budgets.json workload - no measured field updated).

Determinism spot check: the window/memory lines are byte-identical
across g++ 16.2.1 and clang++ 22.1.8 (pure integer workload).

Local verify: ctest -R ecs_stress green on build (Debug g++),
build-asan (required Verify; 37.7s leak-free), build-release,
build-clang, build-tsan, build-shared; full laige-sim suite 40/40 on
build/build-asan/build-clang; zero new warnings under NFR-8.10.

Progress board: M1 5 -> 7 (M1-ECS-06 row lands in the same PR; it
merged without updating the board or change log).
Add the M1-ECS-07 change log row (commit 2995ec7) and the
retroactive M1-ECS-06 row (675fb94 / PR #22 — merged without
updating the board or change log; board counts now reflect the
checked boxes: M1 5 -> 7, total 27 -> 29). Fill the baseline
file's measured-commit field (2995ec7).
@offdev
offdev merged commit d27a087 into master Sep 14, 2026
10 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