Skip to content

trs runcore: zero-copy sidecar strings + window-image move — the boot-alloc rung - #150

Open
nanavati wants to merge 1 commit into
trs/30-benchvlfrom
trs/31-bootalloc
Open

trs runcore: zero-copy sidecar strings + window-image move — the boot-alloc rung#150
nanavati wants to merge 1 commit into
trs/30-benchvlfrom
trs/31-bootalloc

Conversation

@nanavati

Copy link
Copy Markdown
Collaborator

Why

The -m 1 boot/loop split showed the last two Verilator deficits are RunCore boot mass, not per-cycle code: CFL's boot was 66% of its run (6.1ms of 9.2), BRAM0Test's 56% — while both steady loops alone already beat Verilator's entire runs. The boot profile put the compute share in allocations: parse_sidecar built a String per entry of the full design string table (CFL: thousands of rule names — the dominant push/malloc source, with heap-consolidation churn), and the boot then cloned the whole post-window arena image.

What

  • Zero-copy string/path tables: they parse to (offset, len) ranges into the sidecar bytes — take_range UTF-8-validates each entry once and allocates nothing; the buffer moves into RunCore and table_str slices it unchecked under that parse-time invariant (documented). The two runcore_prim_cb name lookups slice field-precisely (a &self accessor would conflict with the live &mut rc.prims borrow). Dyn strings, warn names, prim seeds, and load rows keep owned storage — tiny counts, and runcore_restore is untouched.
  • Window-image move: Boot's post-window arena image is take()n instead of cloned — the clone re-touched every arena page (alloc + memcpy) and nothing reads it afterward.

Sidecar format unchanged (no version bump — this is a boot-side parse change only).

Measured

Same-session: CFL boot 6.1 → 4.8ms (full 9.2 → 8.3), BRAM0Test full 9.7 → 8.8, outputs byte-identical. Boot compute after the change is 4.1M Ir (a third of it the one-time UTF-8 validation) — the remaining boot is process/dlopen/page-fault overhead, not instructions.

Same-moment stamp (fresh host, min-of-N interleaved, all legs byte-verified — vl_bytes all green under the harness's trailer/prefix/golden rules):

design trs verilator note
CFL 6.04 5.33 gap −1.7 → −0.71ms
BRAM0Test 6.62 4.62 gap −2.8 → −2.0ms
Mesa 35.92 54.40 −4.8ms (same big string table at boot) — 1.51x win
FloatTest 39.42 44.30 win widens to 11%
Dividers / TrafficBRAM / Sudoku / DFT64v1 / DFT64v5 / Long 2.07 / 23.18 / 132.7 / 8.93 / 9.13 / 1060 3.10 / 29.64 / 370.8 / 12.15 / 15.47 / 16218 wins hold

Scoreboard: 8W/2L across 10 timed Verilator legs, 11/11 vs Bluesim, both remaining deficits ≤2.0ms.

Witnesses

  • Regress battery 22/22, classic and TRS_RUNCORE=1.
  • Dual full-corpus seals: 1003 PASS / 0 DIFF twice (witnessed TRS_RUNCORE_CHECK=1 TRS_SELFCHECK=1, and driver-armed TRS_RUNCORE=1 — the driver-armed sweep exercises the new parser on all 998 aot designs), zero mismatch, zero panics.

Generated by Claude Code

The -m 1 boot/loop split showed the last two Verilator deficits are
RunCore BOOT mass, not per-cycle code: CFL's boot was 66% of its run
(6.1ms of 9.2), BRAM0Test's 56% — while both steady loops alone
already beat Verilator's entire runs.  The boot profile put the
compute share in allocations: parse_sidecar built a String per entry
of the full design string table (CFL: thousands of rule names — the
dominant push/malloc source, with heap-consolidation churn), and the
boot then CLONED the whole post-window arena image.

- The string and path tables parse to (offset, len) RANGES into the
  sidecar bytes: take_range UTF-8-validates each entry once and
  allocates nothing; the buffer moves into RunCore and table_str
  slices it unchecked under that parse-time invariant.  The two
  runcore_prim_cb name lookups slice field-precisely (a &self accessor
  would conflict with the live &mut rc.prims borrow).  Dyn strings,
  warn names, prim seeds, and load rows keep owned storage (tiny
  counts; runcore_restore is untouched).
- The window arena image is take()n out of Boot instead of cloned —
  the clone re-touched every arena page (alloc + memcpy) and nothing
  reads Boot's window afterward.

Same-session effect: CFL boot 6.1 -> 4.8ms (full 9.2 -> 8.3),
BRAM0Test full 9.7 -> 8.8, outputs byte-identical.  The remaining
boot is process/dlopen/page-fault overhead, not instructions (boot
compute after this change: 4.1M Ir, a third of it the one-time UTF-8
validation).

Battery 22/22 classic and TRS_RUNCORE=1; dual corpus seals 1003 PASS /
0 DIFF (witnessed + driver-armed — the driver-armed sweep exercises
the new parser on all 998 aot designs), zero mismatch, zero panics.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CerPH99xuDTaGhaBQ3wwqS
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.

2 participants