Skip to content

bench/boundary: a compound-element-type lane (#261) - #262

Merged
lannbot merged 1 commit into
mainfrom
bench/compound-element-lane
Sep 3, 2026
Merged

bench/boundary: a compound-element-type lane (#261)#262
lannbot merged 1 commit into
mainfrom
bench/compound-element-lane

Conversation

@lannbot

@lannbot lannbot commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Refs #261 (checklist item: "add a compound-element-type lane to bench/boundary").

Every payload shape in the instrument was a flat scalar — list<u8>, u32, stream<u8> — exactly the set #63/#67 moved onto bulk copy paths. Nothing in bench/boundary exercised the per-element interpreted lift/lower loop that compound types actually walk, so #261's ~5 µs/element finding had no regression instrument and no way to be reproduced in-repo. This lands the instrument before the optimization it will measure, so the "before" numbers are honest.

Shapes

export measures
lift-ops: async func(n: u32) -> list<op> compound-element lift (cabi/load.ts per-element path)
lower-ops: async func(ops: list<op>) -> u64 compound-element lower (cabi/store.ts per-element path)

op is a 16-case variant over records, with string, option<u16>, list<u8> and a nested variant across the payloads — the width and payload mix mirror the consumer schema #261 reports (17 cases). The width is load-bearing, not decoration: maxCaseAlignment (cabi/layout.ts:80, called from loadVariant) and the embedder facade's variant case resolution (embedder/values.ts:212) are both O(case count) per element. An earlier revision of this lane used a 4-case variant and measured ~3.5x below the reported figure — the instrument, not the box.

Both directions because load.ts and store.ts are separate code with the same defect, and a lift-only lane would leave half of it uninstrumented.

Methodology

Reported as ns/element — the unit that makes these comparable to #261's numbers. The guest caches its Vec<Op> per n in a thread_local!; the warmup builds it and timed calls clone it, so format!-per-element is out of the timed region. The clone residue was measured in isolation (temporary export, cloning without crossing the boundary) at ~15 ns/element, under 0.5% of the figures below — so the lane is measuring the boundary. lower-ops's host array is built once outside the timed loop.

Pre-optimization baseline

compound-element lanes (ns/element; n=10000; jco lane skipped):
shape         polyengine-node-callback      polyengine-node-jspi  polyengine-deno-callback
lift-ops                       3,804.4                   3,909.3                   3,184.6
lower-ops                      3,482.3                   3,646.8                   3,285.3

Within ~1.6x of #261's reported ~5 µs/element on its box — the residual reads as box/config drift, not a methodology defect.

Scope

bench/boundary/** only. No published surface, no version bump, no contract change. just check passes; just version-guard-local passes.

Every payload shape in the instrument was a flat scalar — `list<u8>`,
`u32`, `stream<u8>` — which is exactly the set #63/#67 moved onto bulk
copy paths. Nothing here exercised the per-element interpreted
lift/lower loop that compound types (records, variants, options,
strings) actually walk, so #261's ~5 µs/element finding had no
regression instrument and no in-repo way to reproduce it.

Adds `lift-ops` / `lower-ops` over a 16-case variant-over-records whose
width and payload mix mirror the consumer schema #261 reports: records
carrying `string`, `option<u16>`, `list<u8>`, and a nested variant. The
width is load-bearing — `maxCaseAlignment` (cabi/layout.ts) and the
embedder facade's variant case resolution (embedder/values.ts) are both
O(case count) per element, so a narrow variant under-measures the cost
it exists to catch. Both directions, because load.ts's and store.ts's
per-element paths are separate code with the same defect.

Reported as ns/element. The guest caches its `Vec<Op>` per `n` and the
timed calls clone it (residue measured at ~15 ns/element); the
`lower-ops` host array is built outside the timed region.

Pre-optimization baseline recorded: ~3.2-3.9 µs/element across the three
polyengine lanes, within ~1.6x of #261's reported figure on its box.
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