dart: the laggard round — chunked lanes, windowed reads, the #165 bulk-bytes path; 363% -> 221% of generated C++ - #238
Merged
Merged
Conversation
Adjacent constant-width pure-expression fields pack into one staged word with literal relative shifts (the family lever, #198/#208/#237), capped at Dart's native 64-bit lane where the js number domain held it to 32. Wide 33..64-bit fields merge once instead of twice — their wire bits are contiguous, so the bytes are identical by the concatenation argument. Leg (quick, arm64 M2): write 1.894 -> 2.380 M msg/s (1.26x), round_trip 0.974 -> 1.088 (1.12x). Golden gate + 64-variant re-encode green; dart conformance suites green with asserts on. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
String/bytes bodies and bare [N]uint8 arrays stop paying one merge per byte: static runs of 8 or fewer bytes queue as chunk pieces (joining neighboring fields in one merge), longer and dynamic runs take 4 bytes per merge with a byte tail. No alignment requirement: LSB-first merging of the concatenation equals merging the bytes in sequence at any bit position, so the fix reaches the unaligned loadout too. Micro (AOT, M2): 4-byte grouping 2.33x, per-byte baseline 1.00x. Leg (quick): write 2.380 -> 2.499 M msg/s (+5.0%), round_trip 1.088 -> 1.104 (+1.4%) — bulk is only 3.65% of bench_mixed's wire by construction; the lever is for the real packets the issue names. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t per field The reader kept reloading its 64-bit window at every field. A load now folds the byte-interior shift in and guarantees 57 valid bits (in the tail arm, every bounds-proven remaining bit), so consecutive constant-width fields extract at literal relative shifts from one window through a compile-time ledger. Wide 33..57-bit fields extract in one masked read — their groups are contiguous on the wire. Short bare byte arrays unroll into the same windows (#165's read twin). The ledger invalidates at every dynamic bitsRead move and scope boundary. Micro (AOT, M2): chunked window 1.35x over per-field reload. Leg (quick): round_trip 1.104 -> 1.367 M msg/s (+23.8%), write flat; derived read 2.01 -> 3.03 M msg/s. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A counted array of static-width elements unrolls k = lane/elemBits elements per iteration (64-bit chunk lane on the write side, 57-bit window on the read side), with a remainder loop. The chunk accumulator and window ledger span the unrolled elements, so short elements merge together and extract from one load — bench_mixed's 80-element stat array drops from one merge and one window load per element to one per three. Hoisted element refs get unique names (e0, e0g1, e0g2) so the unroll shares one scope; correctness rides the same ledger/flush machinery as straight-line code. Bounded first by a hand-patched generated leg (+10% round_trip on the read side alone). Leg (quick): write 2.493 -> 2.856 M msg/s (+14.6%), round_trip 1.367 -> 1.592 (+16.5%). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wire goldens untouched — testdata/wire byte pins hold in every leg; the re-pin is the SOURCE form only (SPEC §3.1's deliberate-change path). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
before 1,900,191/972,818 (reproducing the standing ledger row within 0.6%), after 2,857,586/1,591,336; spreads 0.07-2.28%; one sitting, corpus 6b213fbfa1a03a99. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
gafferongames
marked this pull request as ready for review
September 1, 2026 04:12
Contributor
Author
|
Adversarially reviewed: the three proof obligations audited and attacked (the 57-bit read-window bound is tight — worst generated extraction is exactly 57, zero violations across 815 window extractions in four corpora; the tail arm is bounds-covered exactly; the 64-shift edge is defined-zero in Dart at precisely the full-word case), plus an independent instance-space differential on the opposite axis from the round's own buffer fuzz (dart:mirrors mutation, subnormals and NaN/Inf through compressed floats, both assert modes, cross read-back — zero divergence over nine units × seven seeds). Numbers recompute exactly from the committed pair. Verdict: MERGE. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Laggard round for generated Dart (#165, the last open laggard round). The issue's named lead — the bulk-bytes path — lands, and the profile named three larger levers beside it.
Headline (
--only dart --quick, both halves in one sitting minutes apart,bench_mixed, familygen, AOT,checks=contract, corpus6b213fbfa1a03a99, max rates per §2.2, spreads 0.07–2.28%):Against the arm64 sitting-2 certification reference at the same
corpus_id(cpp round_trip max 3,512,100 — the LOCKed reference, untouched by this round): 361% → 220.7% of generated C++ on the canonical round_trip blend — the ledger's standing 363% reproduced within 0.6% by this pair's own before leg. Derived read moved 1.99 → 3.60 M msg/s. The measurement CSVs live outsidebench/results/(scratch, per the round's rules); the numbers above are their rows verbatim.1. MEASURE FIRST — where the time actually was
Dart's
--observeprofiler is interactive, so the round profiled the AOT executable with macOSsample(file output, no UI) plus AOT micro-harnesses per the family method:writeBenchMixeditself — the per-field merge with its data-dependent flush branch; ~13% in one ~72-byte out-of-line stub reached from the driver loop (the generic tear-off dispatch of the data-driven contract — harness parity, every leg's driver calls through a function value; named, not touched).getUint64plus a tail branch — at EVERY field.The micro that ranked the forms (interleaved arms, AOT, M2, stats-loop shape): chunked write merge 1.21x over per-field; chunked window read 1.35x over per-field reload; bulk 4-byte grouping 2.33x over per-byte;
Uint64Liststore vsByteData.setUint64+0.8% (see refusals).2. THE LEVERS, each landed as one commit with its paired numbers
[N]uint8arrays stop paying a merge per byte; ≤8-byte static runs queue as chunk pieces (joining neighbor fields in one merge), longer/dynamic runs take 4 bytes per merge with a byte tail. No alignment requirement — LSB-first merging of the concatenation equals merging the bytes in sequence at any bit position, so it reaches the unalignedloadouttooRefused by measurement (results, per the method)
Uint64Listword stores instead ofByteData.setUint64: micro 3,888 → 3,918 K ops/s (+0.8%) — noise-level; the generated API keeps itsByteDatasurface. Refused.3. Discipline
make testgreen;testdata/wireuntouched (the one re-pin commit touches SOURCE goldens only — SPEC §3.1's deliberate-change path); the bench leg's §1.5 golden + 64-variant decode→re-encode gates pass atcorpus_id 6b213fbfa1a03a99.bitsRead/cursor move; a piece referencing a block-scoped temp flushes inside its scope; grouped-loop bodies begin with an invalidated ledger so every iteration executes the same straight-line code.go vetclean, modernize clean,dart analyze+dart format --set-exit-if-changedclean on all generated dart trees, shape-gate clean (19 exemptions, all on ledger), generated tree current.bench/LOCKuntouched: nothing underinternal/codegen/{c,cpp}orgenerated/{c,cpp,c-ludicrous}moved. The dart emitter's tests (fixed-default, reserved-name pins) stay green.Named follow-on (land-and-expand, not this round)
getUint32loads feeding the byte stores) — bounded small on this corpus; priced when a bulk-heavy real schema needs it.Closes #165.
🤖 Generated with Claude Code