Commit Graph
3 Commits
Author SHA1 Message Date
Chris Tate fd34d72e00 Keep each runtime benchmark workload in its own file
workloads.json listed every workload in one array, and its README table
listed them in one hand order, so changes that each added a workload
appended at the same place and conflicted. Each workload is now a JSON
file in benchmarks/runtime/workloads/ named after it, read through
benchmarks/runtime/workloads.mjs by the bench runner, the zero-cost
gate, the strace script and the dynamic-tier test, ordered by category
and then name. The loader still reads workloads.json in a checkout from
before this change, so the gate can compare against one. The README
table follows the same order.
2026-10-20 18:08:10 -05:00
Malte UblandClaude Opus 5.5 4aa5d6cbf8 Give dense arrays head room so shift, splice(0, n) and unshift runs cost amortized O(1)
shift() moved every remaining element down one slot, making queue drains
quadratic (100k elements: 0.85 s; 1M: no result in 30 s). Dense arrays of
8-byte slots with their own allocation now remove front elements by
advancing data/present and lowering cap; the vacated slots stay in the
allocation as head room. A flag in `spare` marks it and its size is
implied by the layout (present == data + cap + head), so every reader,
including inline element access in emitted code, is unchanged. Growth
moves the elements back to the start of the allocation (in place only
when that leaves half the moved count free, else geometrically), a
drained array starts over at the front, unshift reuses head room, and an
array unshift already had to move once reserves head room for half its
length. scr_arr_outline drops head room before compiled storage swaps.
Booleans, inline slots, sparse arrays and static arrays keep the old
behavior.

Scaling probes: shift/BFS/splice(0,1)/deque drains and unshift runs go
from exponent ~2.0 to ~1.0 (shift 1e5 847 ms -> 1.6 ms); runtime bench
geomean 1.0045 (neutral).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 12:13:53 -07:00
Malte Ubl 1c5dfda937 Add a scaling probe suite and strace tools for pathology hunting
benchmarks/scaling: 128 probes of common operations (arrays, strings,
Map/Set/records, JSON, closures, exceptions, regex, dates, promises,
timers, console, fs) run at 3-4 sizes under scriptc and Node with
identical-stdout checks; run.mjs flags superlinear growth and >3x Node,
--strace-only reports syscalls per operation, strace-workloads.mjs
straces the runtime benchmark suite. Results and the full probe table:
results/h40-pathology-hunt/REPORT.md.

Pathologies fixed on this branch (probe ms at 1e3/1e4/1e5/1e6, Linux):
  i in number[]        base 43/5291/timeout   -> 0.03/0.20/1.5/15   (Node 0.19/0.73/6.8/39)
  k in Record<string>  base 4.8/436/timeout   -> 0.15/1.5/20/319    (Node 0.96/8.9/100/1452)
  re.exec /g loop      base 1.1/70/7910/t.o.  -> 0.49/4.1/40/416    (Node 0.47/4.6/43/398)
  clearTimeout n live  base 1.3/10/1014/t.o.  -> 1.3/3.9/38/740     (Node 3.8/9.4/46/527)
  new RegExp repeat    base 3.9/38/368/3811   -> 0.13/1.1/11/106    (Node 0.49/2.9/23/174)
  console.error        2 writes/line          -> 1 write/line

Suite A/B, Linux x86_64 sandbox, candidate vs perf/stack/06 (--layouts=4
--runs=16), all workloads ok:

| workload | baseline ms | candidate ms | change | 95% CI | verdict | size | node ms | candidate/node |
| --- | ---: | ---: | ---: | --- | --- | ---: | ---: | ---: |
| json-records | 202.3 | 201.9 | -0.2% | -7.0% .. +3.8% | neutral | +0.0% | 458.29 | 0.44x |
| regex-logs | 166.8 | 166.4 | -0.2% | -1.6% .. +1.1% | neutral | +0.1% | 239.97 | 0.69x |
| ast-interp | 268.6 | 269.9 | +0.5% | -4.6% .. +3.8% | neutral | +0.0% | 242.7 | 1.11x |
| records-sort | 648.7 | 670.4 | +3.3% | -4.7% .. +10.0% | neutral | +0.0% | 222.69 | 3.01x |
| template-render | 69.6 | 70.7 | +1.7% | -0.2% .. +2.6% | neutral | +0.0% | 187.3 | 0.38x |
| functional-pipeline | 221.8 | 214.9 | -3.1% | -7.3% .. +0.7% | neutral | +0.0% | 249.06 | 0.86x |
| async-pipeline | 197.3 | 198.2 | +0.4% | -1.2% .. +3.0% | neutral | +0.2% | 89.25 | 2.22x |
| word-graph | 259.2 | 256.0 | -1.3% | -6.3% .. +3.0% | neutral | +0.0% | 469.48 | 0.55x |
| alloc-trees | 318.8 | 316.8 | -0.6% | -3.0% .. +1.2% | neutral | +0.0% | 127.68 | 2.48x |
| numeric-kernels | 46.4 | 46.5 | +0.1% | -1.6% .. +3.9% | neutral | +0.0% | 133.42 | 0.35x |
| validate-errors | 176.5 | 178.1 | +0.9% | -3.1% .. +4.7% | neutral | +0.0% | 702.45 | 0.25x |
| csv-numbers | 336.2 | 336.8 | +0.2% | -2.0% .. +1.2% | neutral | +0.0% | 500.14 | 0.67x |
| log-summary | 165.7 | 164.6 | -0.6% | -5.9% .. +1.9% | neutral | +0.0% | 290.81 | 0.57x |
| inventory-report | 321.9 | 320.1 | -0.6% | -6.7% .. +9.5% | neutral | +0.0% | 431.4 | 0.74x |

geomean change: +0.0%
geomean candidate/node: 0.768x (lower is better; goal: well below 1)

macOS lane not run (all measurement in the sandbox per task instructions).
2026-10-08 15:48:28 -05:00