perf(ir): count a for over a flat list #475
Loading…
Reference in a new issue
No description provided.
Delete branch "loop/470-counted-for-pass"
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?
Closes #470
What it does
for value in numbersover aListIterator,TrieListIteratororBufferIteratorbecomes a length read once, a counter and an uncheckedElementread, on both back ends (compiler/src/ir/counted.trb, one wiring linecountFlatListLoops loweringinfinishLowering, afterdropUncountedMakeUniqueand beforedropProvableChecks). The pass takes a loop only whole: the head is the directnextcall of one of the three std cursors (found throughstandardFunctionsOf, never by field shape of a user type), itstagand theSwitch; theOptionis read only there and by the oneReadof itsSome; the cursor is built once in a block that jumps straight to the head. Every other loop (RingList,Array, maps, sets,String.chars(), a userIterate, a loop with nolengthinstance for the list) keeps its cursor,Optionand dispatch.Wiring note: the pass runs after
dropUncountedMakeUnique, because thevar fn nextof a trait-typed cursor is lowered with aMakeUniquein front of the call until that pass removes it.Tests
compiler/tests/counted.test.trb(IR snapshot, lowers a probe against the real std): the loop over aList<Int>has nonextcall, has aless, a[... unchecked]read andadd.i64.unchecked; aRingListloop and a userIterateloop keep theirnext. The" unchecked]"assert is the read annotation of criterion 3;add.i64.uncheckeddoes not contain it, so it is not implied and stays.tests/conformance/counted-for-{break,continue,tuple-pattern,strings,empty,write-to-list}with.allocations; they pass natively and in both VM lanes (tier B green).51d38d87c7(the perf commit; this head only adds the docs commit): all green (commit messages, bootstrap, tier A, tier B, gates, same-C, playground).Cursor shape re-check after #413 (criterion 2)
#413 is on
main. The cursors are unchanged and decision 2's match stands:TrieListIterator(std/collections/src/list.trb:588),ListIterator(:610) andBufferIterator(std/core/src/buffer.trb:249) each are{ items: <list type>, var index: Int = 0 }withnext=get, thenindex = index + 1;compiler/src/ir/instantiate.trbstill registersArrayList,TrieListandBufferasRuntime(ListStorage). The "Related work in review" paragraph of section 5.1 is rewritten accordingly (second commit).Measurement (criterion 5)
Forge CI run 1745, job
tier B (linux-x64),tools/collection-cost.sh(this PR extends it tobenchmarks/run.sh --allocationsand a VM line): one job builds the compiler of the merge base44a359160dand of the branch51d38d87c7, same machine, fastest of 9 runs, µs, as printed.Verdict per criterion 5:
list-iterate1.47x vslist-index6.43x of the same run (bound: at most 10% above, 7.07x); 55 823 µs against 378 156 µs onmain= 0.15 of its time ("did not help" starts at two thirds).mainboth programs allocate 22, and the branch allocates the same 22 forlist-iterate, equal tolist-index, row by row for all seven programs. I read the criterion as "no change, equal tolist-index" and say so rather than claim 24.torb run --vmoflist-iterate: 20 828 ms on base, 62 526 ms on the branch (3.0x slower);list-indexunchanged (23 215 vs 23 513 ms). Cause not found by reading (the new read isListItemAddress, one kernel call likelist-index'sElementAddress). Tracked in #482, which also takes a second sample (this head's CI run prints another). The fix belongs to the bytecode emitter or the VM, not to the pass. Reviewer: this is the one criterion I report as not met; decision on merging before #482 is yours.Docs (criterion 6)
Second commit
docs(performance): record round P11(docs/PERFORMANCE.md only): header status, section 2 row, finding 5 "What was left", section 5's P11 row (done), the 5.1 intro, "Related work" (cursor re-check), and a "Result" paragraph at the end of decision 5 with the tables above.skills/carries no text of docs/PERFORMANCE.md (no P11 text inskills/, no carry directive), sotorb docs skill docs skillsis a no-op; the tier A gatedocs skill --checkconfirms on this head.Nits
counted.test.trbassert: kept, see Tests..allocationsof the fivecounted-for-*programs stay at the 1000 ceiling: CI prints the real counts only for a failing budget (tools/gates.shdeletes the output of a green gate), and a probe branch costs a full CI cycle for a budget notice.counted-for-write-to-listis the measured 6. Tightening is a follow-up in the next PR that touches these files.Seed
None. No syntax, native, driver flag or name the seed looks up (decision 6).
After merge
Nothing to release or deploy.
forpass over a flat list (step 2 of #58) #470forpass over a flat list (step 2 of #58) #470forpass over a flat list (step 2 of #58) #470forpass over a flat list (step 2 of #58) #470forpass over a flat list (step 2 of #58) #470forpass over a flat list (step 2 of #58) #470528fedf62f60ebb4a47cCI is green on
a221d30(tier A/B, bootstrap, same-C gate), and the pass itself reads correctly: whole-loop match, cursor identified throughstandardFunctionsOfnames, increment placed before the body socontinueis safe, the write-to-list case holds. What is missing is the rest of #470, and the PR body still says "Work in progress".benchmarks/run.sh --allocationstable formainand for the branch is recorded in the PR body, so "list-iteratewithin 10% of thelist-indexratio, allocations exactly 24" is unproven. Run one forge CI job each, paste both tables as printed, and state done / "did not help" per the criterion. The VM run oflist-iteratemust be shown not to be slower.docs(performance): record round P11is missing (criterion 6): before/after tables, section 5's P11 row (still "specified, not built"), finding 5 "what is left", the section 5.1 status line, and theskills/regeneration (torb docs skill docs skills).fix(...): compile errors,chore(ir): ... format width,test(ir), ...). Squash it intoperf(ir): count a for over a flat listplus the docs commit before merge; the history is rebase-merged and stays as is.Non-blocking:
counted.test.trb:assert text.contains("unchecked")is implied by theadd.i64.uncheckedline above it.counted-for-write-to-list.allocationsis 6 while the other five use 1000; if 1000 is a placeholder rather than the measured budget, tighten each to the value the run prints.On re-review I will check only these points and the lines changed since.
a221d30851cf227088c1cf227088c151d38d87c7Re-review on
51d38d8: CI is green and the branch is now one commit (earlier finding 4 is resolved). The other four blockers are unchanged: the diff touches no docs file and the PR body is still the earlier "Work in progress" text.benchmarks/run.sh --allocationstable formainand for the branch is in the PR body. Run one forge CI job each, paste both tables as printed, and state done / "did not help" per the criterion (list-iteratewithin 10% of thelist-indexratio, allocations exactly 24; the VM run must not be slower).docs(performance): record round P11is missing (criterion 6): before/after tables, section 5's P11 row, finding 5 "what is left", the section 5.1 status line, and theskills/regeneration (torb docs skill docs skills).Non-blocking (from the earlier review, still open):
counted.test.trb:assert text.contains("unchecked")is implied by theadd.i64.uncheckedline above it.counted-for-write-to-list.allocationsis 6 while the other five use 1000; if 1000 is a placeholder, tighten each to the value the run prints.On the next review I will check only these points and the lines changed since.
Re-review on
19e27a6(round 3): CI is green on this head (tier A/B, bootstrap, gates, same-C, playground, pdisc). The perf commit is unchanged since51d38d8; the head adds only the docs commit.Earlier blockers: measurement (base vs branch tables, done/not-met per criterion) is in the body; the
docs(performance): record round P11commit exists (PERFORMANCE.md only,skills/check green in tier A); the cursor-shape re-check after #413 is stated with the std lines and section 5.1 is updated; the body describes the finished change; history is two Conventional Commits.Checklist: tests (IR snapshot + six conformance programs with budgets) ok; correctness (whole-loop match, std cursors found via
standardFunctionsOf, increment before body socontinueis safe, write-to-list sees the old length) ok; scope = #470 ok; no secrets/deps/boundary change; no data impact; docs ok; "After merge": nothing.The one unmet criterion is disclosed in the body:
torb run --vmoflist-iteratemeasured 20 828 ms on base vs 62 526 ms on the branch, while native improves from 10.61x to 1.47x. It is tracked in #482 with a root-cause plan in the bytecode emitter/VM, not the pass. I decide on merit: it is a measured, isolated, disclosed regression of one lane with a follow-up issue, and the native gain is large. Merging with #482 as the open item; please keep it prioritised.Non-blocking:
counted.test.trb: the" unchecked]"assert is justified in the body, fine.counted-for-*.allocationsbudgets (1000) in the next PR touching these files, as you noted.