Measurements
Generated by mise run bench (scripts/bench.ts) on 2026-09-28. Raw data: bench/results/.
Machine: Apple M4 Max, 16 cores, 48 GB, darwin 25.6.0. Runtimes: Bun 1.4.1, Node v26.10.0.
Runtime numbers come from the built package (dist/), each measure in a fresh process. Medians unless noted.
Startup (cold, fresh process)#
Importing the entry point; for the sandbox this includes instantiating QuickJS (WebAssembly).
| bun median (p95) | node median (p95) | |
|---|---|---|
| sandboxed | 14.9 ms (15.3 ms) | 13.6 ms (15.3 ms) |
| trusted | 1.55 ms (1.59 ms) | 2.55 ms (2.77 ms) |
Compiling charts#
Parsing (happy-dom's DOMParser in these runtimes; browsers use their own) and compiling + validating. Compiling is the library's cost.
| chart | states | transitions | parse (bun) | compile (bun) | parse (node) | compile (node) |
|---|---|---|---|---|---|---|
| gatekeeper | 17 | 14 | 258 µs | 67 µs | 352 µs | 89 µs |
| fulfillment | 59 | 72 | 703 µs | 193 µs | 979 µs | 244 µs |
| support-desk | 333 | 954 | 6.52 ms | 1.66 ms | 11.9 ms | 2.50 ms |
| generated-1000 | 1001 | 2064 | 8.51 ms | 2.89 ms | 14.7 ms | 6.02 ms |
| generated-5000 | 5001 | 10384 | 46.9 ms | 22.6 ms | 87.4 ms | 41.2 ms |
Sessions: creation and memory#
Creating and starting 500 gatekeeper sessions (one machine) and 20 support-desk systems (a root that invokes 14 child machines on start), after one warm-up session. Memory is the growth per session after a full GC: RSS, JS heap, and the QuickJS WebAssembly memory (which grows in large steps, so it often reads 0 for small counts).
| model | chart | create+start (bun) | RSS / heap per session (bun) | create+start (node) | RSS / heap per session (node) |
|---|---|---|---|---|---|
| sandboxed | gatekeeper | 270 µs | 171.8 KB / 139.4 KB + 65.5 KB wasm | 311 µs | 105.9 KB / 7.9 KB + 65.5 KB wasm |
| sandboxed | support-desk | 4.95 ms | 3196.8 KB / 2099.4 KB + 886.4 KB wasm | 5.73 ms | 2513.6 KB / 277.7 KB + 886.4 KB wasm |
| trusted | gatekeeper | 47 µs | 110.2 KB / 74.0 KB | 179 µs | 217.4 KB / 170.4 KB |
| trusted | support-desk | 1.15 ms | 2890.4 KB / 1318.7 KB | 3.42 ms | 4360.0 KB / 2721.7 KB |
Throughput#
External events: 20k send()s processed by a two-state machine that assigns a counter per transition. Microsteps: one macrostep of 20k eventless transitions with a guard and an assignment each. Median of 5 runs.
| model | events/s (bun) | microsteps/s (bun) | events/s (node) | microsteps/s (node) |
|---|---|---|---|---|
| sandboxed | 93k | 101k | 56k | 85k |
| trusted | 172k | 189k | 76k | 132k |
Leak check#
1k cycles of create → start → send → dispose (a 40-state chart), after 100 warm-up cycles; memory after a full GC at four checkpoints. Growth per cycle between the first and last checkpoint (≈ 0 means no leak; RSS includes allocator noise).
| model | heap / RSS / wasm per cycle (bun) | heap MB at checkpoints (bun) | heap / RSS / wasm per cycle (node) | heap MB at checkpoints (node) |
|---|---|---|---|---|
| sandboxed | 357 B / 7384 B / 0 B | 43.28 → 43.46 → 43.54 → 43.54 | 139 B / 218 B / 0 B | 21.74 → 21.79 → 21.80 → 21.84 |
| trusted | 270 B / 5090 B / 0 B | 9.82 → 10.01 → 9.98 → 10.01 | 107 B / 896 B / 0 B | 20.14 → 20.17 → 20.17 → 20.22 |
Browser#
Chrome 154.0.0.0, viewport 1500×950, trusted sessions. Times run until the content is in the DOM (checked once per animation frame, so anything under ~17 ms means "within a frame"). Median of 3.
<scxml-explorer>#
| chart | states | first render | tree rows in DOM | tree scroll: rows, median / p95 frame | long tasks while scrolling |
|---|---|---|---|---|---|
| gatekeeper | 17 | 12.3 ms | 11 | 17 rows, 16.8 ms / 16.8 ms | 0 |
| fulfillment | 58 | 13.9 ms | 10 | 51 rows, 17.0 ms / 17.4 ms | 0 |
| support-desk | 332 | 18.0 ms | 31 | 314 rows, 16.7 ms / 17.3 ms | 0 |
| generated-1000 | 1001 | 4.10 ms | 31 | 1001 rows, 16.7 ms / 17.6 ms | 0 |
| generated-5000 | 5001 | 10.3 ms | 31 | 5001 rows, 16.7 ms / 17.3 ms | 0 |
<scxml-view>#
session = a host-provided, running session. source = SCXML text with the trusted attribute: parse, compile, load the engine, lay out and draw.
| chart | state boxes drawn | render (session) | render (source) |
|---|---|---|---|
| gatekeeper | 17 | 13.2 ms | 15.2 ms |
| fulfillment | 59 | 13.6 ms | 14.8 ms |
| support-desk | 76 | 17.0 ms | 38.3 ms |
| generated-1000 | 137 | 44.5 ms | 57.7 ms |
Charts over the view's max-states (150) are folded: large compound states become single boxes.