perf: P11 - a for over a concrete list is a counted loop #58

Closed
opened 2026-10-05 21:07:15 +00:00 by orion · 9 comments
Collaborator

Context

F5 level 2; list-iterate is 44x a pointer walk. Waits until there are two back ends to answer to.

Source

Acceptance criteria

  • The round as PERFORMANCE.md section 5 specifies it
  • The named benchmark or snapshot recorded before and after

Dependencies

None known.

Moved from the planning lists of the docs; the design record stays the specification.

Steps (epic, no ready label on this issue)

  • #415 Step 1: specify the round in PERFORMANCE.md ("What P11 builds": where the pass sits, which lists qualify, semantics, measurement)
  • #470 Step 2: the pass, its tests and the before/after measurement
## Context F5 level 2; `list-iterate` is 44x a pointer walk. Waits until there are two back ends to answer to. ## Source - [PERFORMANCE.md round P11](https://git.torb.dev/torbscript/language/src/commit/393ef2608e4a60b8ff76d8b6b408951b822d887d/docs/PERFORMANCE.md#L1221) ## Acceptance criteria - [x] The round as PERFORMANCE.md section 5 specifies it - [x] The named benchmark or snapshot recorded before and after ## Dependencies None known. _Moved from the planning lists of the docs; the design record stays the specification._ ## Steps (epic, no `ready` label on this issue) - [x] #415 Step 1: specify the round in PERFORMANCE.md ("What P11 builds": where the pass sits, which lists qualify, semantics, measurement) - [x] #470 Step 2: the pass, its tests and the before/after measurement
orion added this to the Kernel of natives milestone 2026-10-05 21:07:15 +00:00
Author
Collaborator

[loop:torbscript] intake: in scope (author orion, label loop), source PERFORMANCE.md round P11, not a duplicate. Touches the lowering in compiler/src (opus/high when implemented); measured in forge CI (list-iterate). The precondition "two back ends" is checked in refine. next: refine, waiting (ready buffer full: #4, #163, #164, #223 are ready) until 2026-10-10T04:00:00Z

[loop:torbscript] intake: in scope (author orion, label loop), source PERFORMANCE.md round P11, not a duplicate. Touches the lowering in `compiler/src` (opus/high when implemented); measured in forge CI (`list-iterate`). The precondition "two back ends" is checked in refine. next: refine, waiting (ready buffer full: #4, #163, #164, #223 are ready) until 2026-10-10T04:00:00Z
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261023 until 2026-10-23T06:51:00Z

[loop:torbscript] claim refine by session:loop-torbscript-20261023 until 2026-10-23T06:51:00Z
Author
Collaborator

[loop:torbscript] refine: epic, not ready - the round cannot be one PR yet, so I filed its first step as #415 (docs only, ready), next: step 1 = #415, step 2 (the pass) is filed when #415 has landed.

Findings.

  • Precondition "two back ends": met. The bytecode VM interprets the same IR as the C back end and the conformance suite holds both to one behaviour (same basis as #56 and #57).
  • Not a duplicate: keyword search over open and closed issues (P11, list-iterate, iterate, counted loop, Element step) finds only the sibling rounds #56 (P9) and #59 (P12), and #413 (ArrayList on Buffer, mentions for over a concrete ArrayList as COLLECTIONS gap 9 only as a point to decide).
  • The round table names ir/lower/statement.trb as the only file. That does not fit the code: lowerForIterate runs before devirtualizeProgram, and the benchmark's subject is written List<Int>, so the lowering cannot tell the flat ArrayList from a List whose at is not O(1) (ConsStack, BankersQueue), where a counted loop would become quadratic. The concrete type is known only after the devirtualization, which is where P7's ir/elements.trb works for the same reason.

Decided by the loop (no owner question; internal design and performance).

  • The counted loop is made by an IR pass between devirtualizeProgram and insertOwnership, beside rewriteElementPlaces; it recognises the cursor of the flat ArrayList iterator and replaces next's Option round trip by a counter and an Element read. Other cursors keep theirs.
  • Measurement is the pass's acceptance: benchmarks/list-iterate against benchmarks/list-index (39.09x vs 13.25x in section 4), allocations stay 24, recorded before and after in forge CI.
  • No seed impact expected (no syntax, no native, no looked-up name); step 1 confirms it.

Size. Step 1 (#415): one PR, one commit, docs only. Step 2: new pass file, pipeline wiring, IR snapshot test, conformance programs, budget, PERFORMANCE.md status; sized for one PR of two commits, step 1's record says where to cut if not. The epic checklist is in the issue body.

[loop:torbscript] refine: epic, not `ready` - the round cannot be one PR yet, so I filed its first step as #415 (docs only, `ready`), next: step 1 = #415, step 2 (the pass) is filed when #415 has landed. **Findings.** - Precondition "two back ends": met. The bytecode VM interprets the same IR as the C back end and the conformance suite holds both to one behaviour (same basis as #56 and #57). - Not a duplicate: keyword search over open and closed issues (P11, list-iterate, iterate, counted loop, Element step) finds only the sibling rounds #56 (P9) and #59 (P12), and #413 (ArrayList on Buffer, mentions `for` over a concrete ArrayList as COLLECTIONS gap 9 only as a point to decide). - The round table names `ir/lower/statement.trb` as the only file. That does not fit the code: `lowerForIterate` runs before `devirtualizeProgram`, and the benchmark's subject is written `List<Int>`, so the lowering cannot tell the flat `ArrayList` from a `List` whose `at` is not O(1) (`ConsStack`, `BankersQueue`), where a counted loop would become quadratic. The concrete type is known only after the devirtualization, which is where P7's `ir/elements.trb` works for the same reason. **Decided by the loop (no owner question; internal design and performance).** - The counted loop is made by an IR pass between `devirtualizeProgram` and `insertOwnership`, beside `rewriteElementPlaces`; it recognises the cursor of the flat `ArrayList` iterator and replaces `next`'s `Option` round trip by a counter and an `Element` read. Other cursors keep theirs. - Measurement is the pass's acceptance: `benchmarks/list-iterate` against `benchmarks/list-index` (39.09x vs 13.25x in section 4), allocations stay 24, recorded before and after in forge CI. - No seed impact expected (no syntax, no native, no looked-up name); step 1 confirms it. **Size.** Step 1 (#415): one PR, one commit, docs only. Step 2: new pass file, pipeline wiring, IR snapshot test, conformance programs, budget, PERFORMANCE.md status; sized for one PR of two commits, step 1's record says where to cut if not. The epic checklist is in the issue body.
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261024 until 2026-10-24T03:20Z

[loop:torbscript] claim refine by session:loop-torbscript-20261024 until 2026-10-24T03:20Z
Author
Collaborator

[loop:torbscript] release refine: already refined as an epic (step 1 is #415, step 2 is filed after #415 lands); claimed by mistake. next: waiting (epic steps, #415)

[loop:torbscript] release refine: already refined as an epic (step 1 is #415, step 2 is filed after #415 lands); claimed by mistake. next: waiting (epic steps, #415)
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261024 until 2026-10-24T11:15:00Z

[loop:torbscript] claim refine by session:loop-torbscript-20261024 until 2026-10-24T11:15:00Z
Author
Collaborator

[loop:torbscript] decided by the loop: step 2 is one issue, #470, two commits (pass + tests, then the docs record), cut by cursor (ListIterator alone first) if it grows; no split up front. Measurement criteria are taken verbatim from PERFORMANCE.md 5.1 decision 5 (done: list-iterate within 10% of list-index's ratio in the same run, 24 allocations; did not help: above two thirds of main's time). Rebase order with #468 (shares the for lowering): #468 first, then #470 re-reads the cursor shape; no blocker either way.

[loop:torbscript] refine: step 2 filed as #470 and marked ready, next: waiting (epic waits on its steps, #470 next). Tokens used: about 60k

[loop:torbscript] decided by the loop: step 2 is one issue, #470, two commits (pass + tests, then the docs record), cut by cursor (`ListIterator` alone first) if it grows; no split up front. Measurement criteria are taken verbatim from PERFORMANCE.md 5.1 decision 5 (done: `list-iterate` within 10% of `list-index`'s ratio in the same run, 24 allocations; did not help: above two thirds of `main`'s time). Rebase order with #468 (shares the `for` lowering): #468 first, then #470 re-reads the cursor shape; no blocker either way. [loop:torbscript] refine: step 2 filed as #470 and marked ready, next: waiting (epic waits on its steps, #470 next). Tokens used: about 60k
Author
Collaborator

[loop:torbscript] refine: step 2 filed as #470 and marked ready (decision in the comment above), next: waiting (epic waits on its steps, #470 next). Rebase order: #468 and #470 both touch the for lowering; whichever lands second rebases.

[loop:torbscript] refine: step 2 filed as #470 and marked ready (decision in the comment above), next: waiting (epic waits on its steps, #470 next). Rebase order: #468 and #470 both touch the `for` lowering; whichever lands second rebases.
orion closed this issue 2026-10-25 15:33:39 +00:00
Author
Collaborator

[loop:torbscript] close: both steps landed (#415 specification, #470 the counted for pass via PR 475, merge commit 22cf1658f2 on main, before/after in PERFORMANCE.md round P11 from the tier B run noted in #470), main CI green. Epic checklist ticked, closing. next: closed

[loop:torbscript] close: both steps landed (#415 specification, #470 the counted for pass via PR 475, merge commit 22cf1658f2f465d157ba3c294a3cc54cab19e5cb on main, before/after in PERFORMANCE.md round P11 from the tier B run noted in #470), main CI green. Epic checklist ticked, closing. next: closed
Sign in to join this conversation.
No labels
loop
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#58
No description provided.