Batched SVG measured performance
Latest verification: 19 October CPU/memory regression. Earlier measurements are historical.
M2 reference: Apple M1 Pro, MacBookPro18,3, 16 GiB RAM, macOS 26.4 (25E5207k). Chromium version and actual results are recorded in the adjacent JSON artifacts. Budgets below were fixed before production implementation. Single-item baseline is built from e8ec9af61 plus the existing uncommitted M1 changes.
Fixtures: deterministic 1,000 / 10,000 / 100,000 observations, one series for groupedColumn/groupedBar; one X/Y pair for scatter. No nulls in timing fixtures; correctness fixtures cover nulls separately. A 960×440 host resizes to 800×440. Three runs per combination, production ESM, headless Chromium, serial execution. Create includes model cloning/validation, geometry, DOM, and two animation frames; resize waits 100ms for ResizeObserver and two frames (100ms excluded). These are blocking paint latencies, not a claim of 60fps. Nearest-rank p95 of three runs is the maximum. Data construction/module loading precede the timer. GC before/after uses CDP; retained JS heap delta includes model/index/scene. CDP native embedder heap and backing storage are also reported. Process RSS is not measured.
| Gate | 10k | 100k |
|---|---|---|
| Batched create and resize p95 | ≤750ms | ≤5000ms |
| Pointer/keyboard inspection p95 | ≤50ms | ≤100ms |
| Retained incremental JS heap | ≤128MiB | ≤512MiB |
Default single-item 1k create/resize median may grow by no more than 20% plus a 15ms noise allowance relative to the recorded baseline. Structural gate: batched mark nodes grow by paint groups/chunks, never one per observation. Native memory and long-session memory are limitations of this local benchmark, not implied passed gates. No GPU, WebGL, Firefox, Safari, CI or deployed performance claim.
Run the opt-in chart-batched-svg-benchmark.spec.ts with CHART_BENCHMARK pointing
to a JSON output path; set CHART_RENDERER_POLICY=batched-svg for batching.
CPU/memory optimization regression — 19 October 2026
Section titled “CPU/memory optimization regression — 19 October 2026”All nine batched cases and all three default single-item SVG cases complete and
pass the original M2 gates on the same final production graph as the
latest WebGL CPU/memory results.
The run used the original headless Chromium shell protocol, without Metal/8 GiB
heap launch overrides, from 11:54:46 to 11:55:30 UTC inside the coordinated hold
on other workspace builds/tests. It remains separate from the matched CPU/GPU
full-Chromium stress protocol. Hardware and emitted-JavaScript hash are retained
in raw batched results (packages/charts/docs/batched-svg-memory-optimized.json in the source repository) and
raw 1k default SVG results (packages/charts/docs/batched-svg-memory-default.json in the source repository).
| Family | Rows | Create p95 ms | Resize p95 ms | JS heap MiB | Pointer / keyboard p95 ms | Nodes / batch paths | Budget |
|---|---|---|---|---|---|---|---|
| groupedColumn | 1000 | 77.9 | 29.2 | 4.5 | 0.1 / 0.6 | 56 / 1 | PASS |
| groupedColumn | 10000 | 168.0 | 22.6 | 17.3 | 0.1 / 0.6 | 69 / 5 | PASS |
| groupedColumn | 100000 | 1148.2 | 364.7 | 145.7 | 0.1 / 0.6 | 109 / 49 | PASS |
| groupedBar | 1000 | 41.3 | 31.5 | 4.5 | 0.1 / 0.8 | 48 / 1 | PASS |
| groupedBar | 10000 | 152.5 | 31.2 | 17.5 | 0.1 / 0.5 | 52 / 5 | PASS |
| groupedBar | 100000 | 1333.5 | 571.8 | 149.2 | 0.2 / 0.5 | 96 / 49 | PASS |
| scatter | 1000 | 43.2 | 23.7 | 5.2 | 0.1 / 0.7 | 56 / 1 | PASS |
| scatter | 10000 | 175.6 | 25.3 | 23.9 | 0.1 / 0.6 | 60 / 5 | PASS |
| scatter | 100000 | 1910.1 | 515.4 | 214.0 | 0.1 / 0.5 | 104 / 49 | PASS |
1k default SVG comparison (median; limit = baseline × 1.2 + 15 ms):
| Family | Baseline create / resize ms | Current create / resize ms | Gate |
|---|---|---|---|
| groupedColumn | 80.8 / 4.1 | 45.2 / 14.3 | PASS |
| groupedBar | 92.1 / 6.4 | 43.6 / 17.1 | PASS |
| scatter | 113.7 / 3.8 | 42.9 / 17.5 | PASS |
The 1k default-SVG comparison passes its original median limit (baseline × 1.2 plus 15 ms). Its resize medians are higher than the original baseline, within that unchanged noise allowance; no resize improvement is claimed. The fixture includes two RAFs, without waiting for the full duration of any SVG entrance animation. It measures the recorded create/resize protocol, not completed animation latency. Functional transition tests separately verify committed geometry and exports. No observations or semantic inspection entries are dropped; 100k batched cases retain 49 batch paths rather than one mark node per datum.
node packages/charts/scripts/report-batched-svg.mjs packages/charts/docs/batched-svg-baseline.json packages/charts/docs/batched-svg-memory-optimized.json packages/charts/docs/batched-svg-memory-default.json --checkHistorical integrated verification — 18 October 2026
Section titled “Historical integrated verification — 18 October 2026”The final production graph, including optional GPU support and the private runtime snapshot optimization, passes all original M2 gates without changing the protocol, fixture or budgets. Runs started after package builds, workspace push hooks and compatibility jobs finished. Hardware and Chromium remain the same reference.
At 100k observations, groupedBar creation p95 is 2,171.5 ms and scatter 3,462.6 ms, versus current-build pre-optimization 5,155.1 / 7,862.4 ms. Scatter now has 1,537.4 ms headroom against its 5,000 ms creation gate. This remains a local measured result, not a guarantee on another host or dataset.
Raw final records: packages/charts/docs/batched-svg-integrated.json and
batched-svg-integrated-default-svg.json in the source repository. Both identify
source commit 462284b31 and the emitted-JavaScript SHA-256/hash protocol. Earlier
optimization and initial implementation artifacts below remain historical.
| Family | Rows | Create p95 ms | Resize p95 ms | JS heap MiB | Pointer / keyboard p95 ms | Nodes / batch paths | Budget |
|---|---|---|---|---|---|---|---|
| groupedBar | 1000 | 50.5 | 17.0 | 5.0 | 0.1 / 0.4 | 48 / 1 | PASS |
| groupedBar | 10000 | 242.9 | 21.5 | 23.9 | 0.1 / 0.5 | 52 / 5 | PASS |
| groupedBar | 100000 | 2171.5 | 783.8 | 215.0 | 0.2 / 0.5 | 96 / 49 | PASS |
| groupedColumn | 1000 | 50.5 | 15.8 | 5.0 | 0.1 / 0.6 | 38 / 1 | PASS |
| groupedColumn | 10000 | 220.3 | 156.9 | 23.6 | 0.1 / 0.5 | 42 / 5 | PASS |
| groupedColumn | 100000 | 2041.7 | 574.6 | 211.5 | 0.2 / 0.5 | 86 / 49 | PASS |
| scatter | 1000 | 56.0 | 20.2 | 5.8 | 0.1 / 0.6 | 56 / 1 | PASS |
| scatter | 10000 | 332.6 | 15.3 | 31.5 | 0.1 / 0.5 | 60 / 5 | PASS |
| scatter | 100000 | 3462.6 | 783.1 | 289.8 | 0.1 / 0.5 | 104 / 49 | PASS |
1k default SVG comparison (median; limit = baseline × 1.2 + 15 ms):
| Family | Baseline create / resize ms | Current create / resize ms | Gate |
|---|---|---|---|
| groupedBar | 92.1 / 6.4 | 39.2 / 13.7 | PASS |
| groupedColumn | 80.8 / 4.1 | 38.1 / 11.2 | PASS |
| scatter | 113.7 / 3.8 | 47.1 / 10.9 | PASS |
Recompute every gate, including the default-SVG medians:
node packages/charts/scripts/report-batched-svg.mjs packages/charts/docs/batched-svg-baseline.json packages/charts/docs/batched-svg-integrated.json packages/charts/docs/batched-svg-integrated-default-svg.json --checkFinal compatibility: Charts 3,033 / 180 files; Pivot 4,069 / 326 files; 33 functional cases across Chromium, Firefox and WebKit. Package builds, public types and imports pass. These browser-engine checks establish functional compatibility, not measured Firefox/WebKit performance. Remote CI and deployment are recorded separately.
M3 closure regression verification — 18 October 2026
Section titled “M3 closure regression verification — 18 October 2026”The shared parser/GPU resource changes retain every original M2 gate. All nine
batched cases and three 1k default SVG cases pass on the same production graph
as the GPU closure. Three unprofiled serial runs per case
are retained in raw batched results (packages/charts/docs/batched-svg-m3-closure.json in the source repository) and
raw default SVG results (packages/charts/docs/batched-svg-m3-closure-default-svg.json in the source repository). Hardware,
browser, data, default-renderer baseline and budgets are unchanged.
| Family | Rows | Create p95 ms | Resize p95 ms | JS heap MiB | Pointer / keyboard p95 ms | Nodes / batch paths | Budget |
|---|---|---|---|---|---|---|---|
| groupedBar | 1000 | 46.9 | 20.0 | 5.1 | 0.1 / 0.5 | 48 / 1 | PASS |
| groupedBar | 10000 | 206.3 | 12.4 | 24.4 | 0.1 / 0.5 | 52 / 5 | PASS |
| groupedBar | 100000 | 1823.3 | 615.4 | 218.4 | 0.2 / 0.6 | 96 / 49 | PASS |
| groupedColumn | 1000 | 57.6 | 21.8 | 5.1 | 0.1 / 0.7 | 38 / 1 | PASS |
| groupedColumn | 10000 | 185.6 | 148.8 | 24.1 | 0.1 / 0.5 | 42 / 5 | PASS |
| groupedColumn | 100000 | 1651.6 | 511.5 | 214.9 | 0.2 / 0.5 | 86 / 49 | PASS |
| scatter | 1000 | 50.6 | 18.5 | 6.0 | 0.1 / 0.7 | 56 / 1 | PASS |
| scatter | 10000 | 270.1 | 17.4 | 31.9 | 0.1 / 0.6 | 60 / 5 | PASS |
| scatter | 100000 | 2654.3 | 484.3 | 296.3 | 0.1 / 0.5 | 104 / 49 | PASS |
1k default SVG comparison (median; limit = baseline × 1.2 + 15 ms):
| Family | Baseline create / resize ms | Current create / resize ms | Gate |
|---|---|---|---|
| groupedBar | 92.1 / 6.4 | 35.8 / 12.2 | PASS |
| groupedColumn | 80.8 / 4.1 | 34.2 / 14.3 | PASS |
| scatter | 113.7 / 3.8 | 40.4 / 14.4 | PASS |