perf: an allocation budget per conformance program as a gate #60
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Make the allocation count of each conformance program a gate so a regression is noticed.
Source
Acceptance criteria
Dependencies
None known.
Moved from the planning lists of the docs; the design record stays the specification.
[loop:torbscript] intake: in scope (author orion, label loop), source PERFORMANCE.md section 6, not a duplicate, no collision with a design record. A tier B or conformance gate with a recorded budget per program; measurable, so the loop decides the budget rule from the numbers in refine. next: refine, waiting (ready buffer full: #4, #163, #164, #223 are ready) until 2026-10-10T04:00:00Z
[loop:torbscript] claim refine by session:loop-torbscript-20261010 until 2026-10-10T02:45Z (the "ready buffer full" marker is stale: only seed-blocked items are ready)
[loop:torbscript] refine: ready, an exact per-program allocation budget, one PR in two commits, no seed impact.
Goal.
tests/conformance/already runs each program withTORB_REPORT_LEAKS=1and assertslive blocks at exit: 0(tools/conformance.sh, the leak run). Add a second number to that same report, the total blocks the program allocated, and hold each program to a recorded budget, so a regression from per element to per loop allocation fails tier B instead of being found later. Implementsdocs/PERFORMANCE.mdsection 6, "An allocation budget per conformance program"; the design record stays that section.Acceptance criteria.
runtime/memory.c: every block made bytorb_allocate(and sotorb_allocate_zeroed),torb_raw_allocate(and sotorb_raw_allocate_zeroed) and the immortal path is counted once into a new per-heap counter (torb_heap.allocated_blocksplusmachine_allocated_blocks, next to the live and immortal ones inruntime/include/torb_pool.h).torb_raw_count_immortalandtorb_raw_count_mortalre-class a block and do not count.torb_fold_workerinruntime/task.cfolds the counter into worker 0 and atorb_pool_sum_*pair sums it, so a program with workers loses nothing; a newtorb_allocated_block_count()sits besidetorb_live_block_count().torb_report_leaksprints a third lineallocated blocks at exit: N, in the VM branch (machine_allocated_blocks) and the native one. The two existing lines and the greps on them are unchanged.runtime/tests/memory_test.c: a test that the counter rises by exactly the number of allocations, is not lowered by a free, and counts an immortal block once.tools/conformance.sh(native leg): programs that get the leak run today (no.stderr, no.leaks, notbinary-only/) are also held to<program>.allocations. The file holds one integer, orunbudgeted: <reason>(as.leaksholds its reason, and for the same kind of reason). The count is read from a run withTORB_WORKERS=1; a program with a.workersfile gets that one extra run, since its leak run uses its own worker count. The program fails when the count is above its budget, printing program, budget, count and the difference. A count below the budget passes and is listed in a closing note with the command to lower it. A program with a leak run and no.allocationsfile fails and prints its count (this also makes every new program carry a budget).sh tools/conformance.sh --update-budgets [--filter x]writes.allocationsfrom a run. It reads the count three times and writes nothing for a program whose three differ, naming it, so it isunbudgetedby hand.--updateleaves budgets alone: raising one is a separate, visible act, and the commit message says why.--vm,TORB_VM_DEBUGGED=1) print nothing new and read no budget. Whether the VM allocates like the native binary is not measured yet; that is a follow-up once the budgets exist..allocationsfile (a number, orunbudgeted:with a reason, expected for timing-driven programs such asprocess-pipes,confined-child,task-sleep,entropy,wall-clock,io-eight-filesand the like if their count varies); the final tip of the branch is green in forge tier B.tests/conformance/README.md(the table of what is compared gets the.allocationsrow, the "Zero live blocks" section the third line, and how to update);compiler/CONTRIBUTING.mdline "Numbers are recorded, not enforced: allocation counts, ..." is corrected, since the conformance allocation count now does fail a gate (the benchmark ratios and the size of the C stay recorded);docs/PERFORMANCE.mdsection 6 paragraph states what was built and the rule below, and the status line is updated. Docs changes regenerateskills/(docs skill); the worker does it with the existingbuild/release/torbif present, else the first CI run names the diff.Decided by the loop (budget rule).
.expected, because a loop and its parallel PRs add programs at the same time and a single list file would conflict on every merge. Reviewers see a budget change as a one-line diff in the PR.docs/PERFORMANCE.mdalready reads this column as "exact" (sections 4 and 6; for examplelist-iterate24 blocks,pipeline85,map-count50 110). A percentage tolerance would let a per-loop block creep in unseen on the small programs where it matters (24 blocks), and an exact number makes the one-block change of a std or lowering round show up in review. The only exceptions are programs whose count varies between runs; they takeunbudgeted:with a reason.tier B (linux-x64)job (sh tools/gates.sh b). It is not a tier A gate (it needs a built binary and the C compiler). The runner enforces budgets on Linux x86_64 and only reports (prints the count, compares nothing) elsewhere, viauname, withTORB_ALLOCATION_BUDGET=enforce|reportto override:.forgejo/actions/portableand the GitHub mirror run the sametools/conformance.shon windows-x64, macos-arm64 and linux-arm64, and the counted raw blocks of the OS layer (console.cwide buffers,file.cpath conversions,process.c) are not the same on every platform. Counting the raw blocks at all is deliberate: the map's entry table and bucket array (map.c) are raw blocks and are exactly what a per-element regression of a map would allocate..allocationsfiles, its tier B run fails every program withno budget, allocated N, the implementer writes the files from that log (a script that asserts each name matches), and the second run with the files must be green. That second run is also the stability check, and a program that differs between the two runs becomesunbudgeted:. (Nothing runs the suite in the worker's own exec: orion/infra#947.)Seed impact: none. No syntax change, no new native (the counter is C-internal and no TorbScript
nativeis added), no driver flag, no std name looked up by string. The runtime change is read by the bootstrap's own binary and by the conformance runner of the same checkout; the seed'sprogram.cis untouched. Do not touchseed/.Size: one PR, two Conventional Commits.
feat(runtime): count the blocks a program allocates-runtime/memory.c,runtime/include/torb_pool.h,runtime/include/torb.h,runtime/task.c,runtime/tests/memory_test.c, the leak-report comment inruntime/process.c; closes the gap for workers (torb_fold_worker).test(conformance): hold each program to an allocation budget-tools/conformance.sh, the.allocationsfiles,tests/conformance/README.md,compiler/CONTRIBUTING.md,docs/PERFORMANCE.md,skills/. Implementer: opus/high for the runtime (the contract's rule forruntime/); the second commit is tooling plus data. The ~280 data files are one mechanical change of one commit, not a reason to split.Overlap with open PRs (no blocker, order only).
tools/conformance.sh(header comment, the timings file selection near the end),tools/gates.sh,compiler/CONTRIBUTING.md(tier B paragraph a few lines above the "Numbers are recorded" sentence and the timings paragraph),docs/design/DEBUGGER.md,compiler/src/ir/lower/scope.trb. This issue's second commit touches the same two files in different hunks; implement on top of #291 if it has landed, otherwise expect a trivial rebase inconformance.sh's header and inCONTRIBUTING.md. The debugged leg is a--vmleg, so it reads no budget.perf(ir), dead witness members) editscompiler/src/backend/{bytecode/emit,c/body,c/emit}.trb,compiler/src/ir/{called-members,ir,kept,lower/lower,print,sites,verify}.trb, testsemit-c,lower-generics,lower,witness-dead,docs/BACKEND.mdanddocs/PERFORMANCE.md(status line, F12 and the P10 row). No file in common exceptdocs/PERFORMANCE.md: section 6 here against sections 5 and F12 there, so a clean rebase is likely. #284 removes emitted table entries, not blocks, so it should not move a budget; if it does, the first budget run of whichever lands second shows it.[loop:torbscript] claim implement by session:loop-torbscript-20261010 until 2026-10-10T06:50Z (ready, refine comment above)
[loop:torbscript] claim implement by session:loop-torbscript-20261010 until 2026-10-10T14:02Z (re-claim: the previous worker died in the gateway gap between 02:10Z and 08:00Z without a write-back)
[loop:torbscript] claim implement by session:loop-torbscript-20261010 until 2026-10-10T17:00Z (renewed: resume 3 worker is running on PR 297)
[loop:torbscript] done: PR #297 merged by argus (
b0f6808). Issue closed by the merge; no after-merge steps (no release or deploy). Budgets: 216 exact, 21unbudgeted:.