[M0-CORE-08] Budget harness: Histogram/TimeIt/budgetCheck + budgets.json + laige-bench - #9
Merged
Merged
Conversation
…son + laige-bench laige::Histogram: fixed-capacity rolling window; O(1) allocation-free record(); exact min/mean/p50/p95/p99/max over the stored window with nearest-rank percentiles (rank = ceil(p*n/100), exact integer math); stats() is a cold-path O(n log n) pass with no allocation (pre-allocated scratch). laige::TimeIt: steady_clock ms scope timer, no allocation. loadBudgets: file I/O + bounded parse (ADR 0003) + strict budgets.json schema v1 validation (ARCH-007; unsupported version/fields, bad name/metric/unit charset, duplicate names, negative or non-finite numbers -> MalformedInput; unreadable file -> IoError). budgetCheck: total operation; empty histogram -> loud NO_SAMPLES; target > 0 -> measured <= target; target == 0 -> hard-zero budget (sim_heap_allocs), not "not set" (the not-yet-measured marker is the initial measured: 0). Report = stable 4-line AGENTS §12 text with before/after pair and caller context; formatStatsLine is the single source of the stats text. budgets.json (repo root): all 15 PRD §8.1 budgets as named entries; measured: 0 = not yet measured until their subsystems land (M1+). laige-bench: canonical command ./build/bin/laige-bench --suite=<name> (reserved for this step by docs/getting-started/building.md); M0 suite "synthetic" (deterministic, allocation-free 4096-step LCG + double stand-in workload); --runs/--warmup, --budget=<name> check with --budgets path resolution (arg -> LAIGE_BUDGETS_PATH env -> budgets.json), --report append; exit 0 pass / 1 usage or load failure / 2 budget check failure (CI-gateable). ctest: budget_harness entry (22 GTest cases) + laige_bench_smoke entry; LAIGE_BUDGETS_PATH wired for both (incl. the TSan tree, where CTest ENVIRONMENT is last-write-wins). API contract: docs/api/budget_harness.md. Bug fix (M0-CORE-07) found by the Verify run of this step: json.cpp parseObjectMembers was missing skipWhitespace before the member key - object documents with ", " between members (the hand-formatted repo-root budgets.json) were rejected. Regression test ConfigJsonValid.ObjectMemberWhitespace fails pre-fix. Verified locally: ctest 16/16, zero warnings, on GCC 16.2.1 (static, shared, ASan+UBSan fatal, TSan halt_on_error=1) and Clang 22.1.8 trees; include-lint clean (17 files). MSVC/AppleClang compile proof lands in CI.
M0-foundations.md: M0-CORE-08 checked, with Decision (2026-09-11), Verify (22 GTest cases + laige_bench_smoke; 16/16 ctest on GCC static, shared, ASan, TSan and Clang trees) and Size notes, including the record of the M0-CORE-07 parser bug fix found by this step's Verify run (missing skipWhitespace before the object member key). README.md: Progress Board M0 11 -> 17 (Total 17), and the change log gains this step's line (810c251) plus the five reconstructed lines for M0-CORE-03..07 (0fd41f3, 5c76991+7538053, 4a572af+ba4ffb2, a82de8e, 41938b0) rebuilt from their step records in M0-foundations.md — the board and change log had drifted (11 vs 16 checked boxes) since M0-CORE-03 landed.
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.
Scope (M0-CORE-08, per
roadmap/M0-foundations.md):laige::Histogram— fixed-capacity rolling window; O(1) allocation-freerecord(); exact min/mean/p50/p95/p99/max over the stored window via nearest-rank percentiles (rank = ceil(p·n/100), exact integer math); allocation-freestats().laige::TimeIt—steady_clockms scope timer.loadBudgets/budgetCheck— strictbudgets.jsonschema v1 (ARCH-007) over the M0-CORE-07 bounded JSON parser (no new dependencies); AGENTS §12 report: stable 4-line machine-greppable text with before/after pair and caller context;formatStatsLineis the single source of the stats text.budgets.json(repo root) — all 15 PRD §8.1 budgets as named entries;measured: 0= not yet measured until their subsystems land (M1+).laige-bench— the canonical command./build/bin/laige-bench --suite=<name>reserved bydocs/getting-started/building.mdfor this step; M0 suitesynthetic(deterministic, allocation-free stand-in workload);--budget=<name>check with exit code 2 on failure (CI-gateable per PRD §8.1).docs/api/budget_harness.md.Key design decisions:
target == 0is a hard-zero budget (e.g.sim_heap_allocs: zero steady-state heap allocations per frame), not "not set" — the not-yet-measured marker lives inmeasuredonly. An empty histogram is a loudNO_SAMPLESfailure (no silent pass — CORE-008). The 1 MiB bound is enforced before the read; unreadable file →IoError, every schema violation →MalformedInput(no new error codes).Bug fix (M0-CORE-07) found by this step's Verify run:
json.cppparseObjectMemberswas missingskipWhitespacebefore the member key — object documents with", "between members (the hand-formatted repo-rootbudgets.json) were rejected. Fixed with a regression test (ConfigJsonValid.ObjectMemberWhitespace, fails pre-fix); the documented grammar was already correct, the implementation did not match it.Verify (local, 2026-09-11):
ctest16/16, zero warnings under the NFR-8.10 policy, on five Linux trees — GCC 16.2.1 (buildstatic,build-shared,build-asanASan+UBSan fatal,build-tsanTSanhalt_on_error=1) + Clang 22.1.8 (build-clang).budget_harnessCTest entry = 22 GTest cases: known percentiles on 1..100, full-ring wrap dropping the oldest, empty → NaN, loud FAIL when a threshold is exceeded, hard-zero-target budget, 13-case schema-rejection corpus against the repobudgets.json,IoErroron missing file. The synthetic workload producing percentiles is exercised end-to-end by thelaige_bench_smokeentry.include-lintclean (17 files). The MSVC + AppleClang compile proof lands in this PR's CI run (default Linux lane).Also in this PR (roadmap bookkeeping, per the roadmap agent contract):
roadmap/M0-foundations.mdM0-CORE-08 checked with Decision/Verify/Size;roadmap/README.mdProgress Board M0 11 → 17 (Total 17) and the change log gains this step's line plus five reconstructed lines for M0-CORE-03…07 — the board and change log had drifted (11 vs 16 checked boxes) since M0-CORE-03 landed, so they are brought back in sync in the same PR that checks the next box.