Skip to content

Dot performance dashboard

Warm, in-process timing of @knowvah/dot-engine vs the native dot oracle over the dot test corpus. Peer to PARITY.md — PARITY tracks correctness, PERF tracks speed. A report, not a gate. The fidelity target is ≤3× native.

Regenerate: npm run build:js && node test/corpus/bench.mjs && npm run bench:wasm && node test/corpus/perf-dashboard.mjs (the bench:wasm step is optional — it adds the dot-engine vs WASM section below).

Method

  • Port: the shipped bundle (dist/index.js) loaded once in a pool of resident, JIT-primed worker threads; pure renderSvg() is timed (best-of-N), so the measured region excludes all process/transpile/module-load startup — the warm steady state a long-lived consumer sees. Light graphs run at full pool; heavy graphs (native > 2s) are timed serially by default — measured cross-talk inflates a concurrent big render's single sample materially (≈66% on 2620). Set BENCH_HEAVY_POOL>1 for a faster, noisier scan.
  • Native: dot -Tsvg best-of-3 (min).
  • Budget: target ≤3× native. Per-render cap 4800000ms (SIGKILL → over-cap, i.e. a true synchronous hang).
  • Caveat: light graphs are timed under up-to-6-way load; for a precise single number re-run BENCH_POOL=1 BENCH_IDS=<id> node test/corpus/bench.mjs.

Summary

  • Rated inputs: 928 · within ≤3× native: 902 (97.2%)
  • ok (≤3×): 902 · slow (>3×): 26 · over-cap (hang): 2 · errored: 0 · oracle-error: 9
  • ratio (port/native): p50 0.02× · p90 0.70× · max 7.54×

Ratio distribution

bandcount
≤1× (port ≥ native, warm)851
1–2×31
2–3×20
3–4×17
4–6×8
6–10×1
>10×0
over-cap (≥4800000ms, possible hang)2

Over budget — slower than 3× native (worst first)

idnative msport ms (warm)ratio
210812849968377.54×
24713269191625.86×
graphs-b103121066765.52×
graphs-b1008646476175.51×
209526112164.66×
262125600011313554.42×
linux.x86-root_circo24510444.26×
tree-contrib-dirgraph-bsdarch12504.19×
graphs-b1048635348574.04×
nshare-root_circo247988
graphs-root2148393.92×
share-b2957822693.92×
linux.x86-root_twopi2489473.82×
nshare-root_twopi2479343.78×
tree-contrib-dirgraph-linux8303.75×
262037113823.73×
27432017483.72×
graphs-badvoro32011833.7×
2095_122309823023.69×
linux.i386-b2958220393.5×
tree-doc-neato-jho11383.45×
tree-graphs-undirected-ngk10_415513.43×
graphs-b2958519893.4×
16522703068946233.31×
windows-b2959719393.25×
tree-doc-dotguide-smlred21653.11×

Over-cap / possible hang

idnative mscap msnative×budgetstatus
tree-share-examples-world157209048000004716270exceeds budget (likely hang/runaway)
2475_1110334348000003310029exceeds budget (likely hang/runaway)

Raise BENCH_CAP_MS and re-run these ids to resolve an inconclusive status.

dot-engine vs WASM (@hpcc-js/wasm-graphviz)

A different axis from the table above: this compares the pure-TS port against the WASM build a browser would otherwise ship (@hpcc-js/wasm-graphviz@1.28.0) — both warm, in-process, best-of-3 (min). A report, not a gate: WASM is compiled C, so the port is expected to be a small constant factor slower; the port's wins are bundle size and no wasm fetch+instantiate, not raw layout compute. Source: wasm-perf.json. Regenerate: npm run bench:wasm.

  • Compared: 765 inputs · ratio (dot-engine / wasm): p50 3.63× · p90 4.53× · max 7.60× · mean 3.58×
  • Excluded: 12 heavy (native > 2000ms) · 4 large-source (> 1 MB) · 4 port-error · 7 wasm-error · 0 missing

Ratio distribution (dot-engine / wasm)

bandcount
dot-engine faster (<1×)1
1–2×31
2–4×509
4–6×214
6–10×10
>10×0

Slowest for the port vs WASM (worst first)

iddot-engine mswasm msratio
graphs-Heawood6.1130.8047.604×
26091.3120.1787.375×
share-Heawood5.3580.7627.033×
macosx-ordering_dot2.5860.3846.729×
graphs-rd_rules3.6130.5536.53×
graphs-grdfillcolor5.7420.8996.385×
macosx-nestedclust_dot1.3320.2116.324×
share-train115.1480.8266.232×
macosx-ordering_dot12.4130.3886.222×
graphs-sq_rules3.1120.5176.02×
graphs-pslib5.5710.9295.998×
graphs-ER2.5010.4215.94×
graphs-b7862.0780.365.775×
share-ER2.7090.475.763×
graphs-grdshapes6.1171.0795.667×
graphs-grdlinear5.7211.0185.62×
share-trapeziumlr8.1391.4625.566×
1212.4630.4445.544×
share-labelclust-nbl0.9820.1795.48×
14081.0920.25.455×

Excluded / not compared

  • Heavy (native > 2000ms): 12 inputs — warm best-of-N over multi-second layouts is impractical here; their vs-native behavior is in the main table above.
  • Large source (> 1 MB): 1864 (14.1 MB), 2064 (4.9 MB), 2475_1 (9.3 MB), 2593 (13.2 MB) — multi-MB disassembly/CFG dumps (~10k+ nodes) that are impractical for a warm best-of-N. These are hard for Graphviz generally, not port-specific: spot-checked, 2064 fails to render in native dot (>120s), the WASM build (>60s in layout()), and the port (>30s) alike; 1864 OOMs both the port (>1 GB) and the WASM build ("out of memory") while native times out. The port does not leak (with GC its per-render heap is flat ~17 MB) — this is a scale ceiling shared with upstream, not a defect.
  • Per-side error ids are listed in wasm-perf.json.