Latest Results
perf(bindings): 8–10% smaller addons, 11–12% less decode time, 29.4 MB less compression-table memory (#12740)
**Description:**
<!-- native-decoding:start -->
[This
implementation](https://github.com/jdalton/swc/compare/c8d37f173207e7f8d7e2bc029a10d9babe95ed44...0a101c7041509ce3290f2cb8dba659c4c1ae03d1)
makes the measured Darwin ARM64 addon files **8.27% smaller for SWC
(0.74 MB saved)** and **9.92% smaller for Rspack (1.29 MB saved)**, with
**11.70% and 10.59% less verified decoding time**. Peak
decoding-benchmark memory falls **3.46% and 9.76%**, respectively.
The compression lookup table also uses **4.2 MB instead of 33.6 MB: 29.4
MB less allocation** against the large-table control described below.
### Historical combined measurement: before feature gating
**Historical measurements:** these results predate filesystem-feature
gating and do not validate the current gated implementation. A fresh
volume without compression feature bits now uses zlib. A
current-revision benchmark on both baseline and explicitly zstd-enabled
volumes remains outstanding.
On the same Linux ARM64/Btrfs setup, this PR’s optimized native payload
plus #12739’s zstd replacement produced **a 12.3% smaller complete
carrier, 23.5% faster first native `require()`, 65.0% faster follow-up
cold `require()`, and 1.7% less Btrfs allocated space** versus the
baseline with neither change. The two standalone percentages are not
added; these figures are a direct measurement of both changes together.

| Metric | Baseline | Both changes | Improvement |
| --- | ---: | ---: | ---: |
| Complete carrier | 10.7 MB | 9.4 MB | 12.3% smaller |
| Btrfs allocated space after replacement | 14.2 MB | 14.0 MB | 1.7%
less |
| First carrier `require()` | 284.6 ms | 217.7 ms | 23.5% faster |
| Follow-up cold `require()` | 61.8 ms | 21.6 ms | 65.0% faster |
The run used eight alternating trials per build and three follow-up
loads per trial. Each first load verified that the carrier was replaced
with the original addon. Full method and raw measurements: [combined
benchmark
artifacts](https://github.com/jdalton/swc/tree/3b2fe574d7a86f88129f96566fb8bcbb93e19ee0/benchmark-artifacts/combined-native-btrfs).
This is one Linux ARM64 VM; file page cache was evicted, but other
VM/host caches were uncontrolled.
<!-- combined-native-btrfs-result -->

<details>
<summary>Measured results and benchmark method</summary>
The baseline uses original level-16 compression and streaming decoding.
The final implementation uses tuned level-22 compression, bounded bulk
decoding, and batched writes. A complete `.node` file includes both the
compressed addon and its loader. MB uses decimal units.
| Metric | SWC 1.16.2: baseline → final | Rspack 1.7.0: baseline → final
|
| --- | ---: | ---: |
| Complete `.node` file | 8.989 → 8.246 MB (−8.27%) | 12.985 → 11.697 MB
(−9.92%) |
| Verified decoding elapsed time | 50.876 → 44.926 ms (−11.70%) | 76.506
→ 68.401 ms (−10.59%) |
| Peak benchmark process memory | 46.0 → 44.4 MB (−3.46%) | 72.2 → 65.2
MB (−9.76%) |
The final implementation was faster in all five paired process
comparisons for both inputs. The smaller table plus batched writes also
beat the Hash21 bulk-decoding control by 7.06% for SWC and 7.99% for
Rspack, again in all five pairs.
Each variant/input ran in five fresh processes with balanced ordering,
two warmups, and twelve measured rounds per process. Reported runtime
values are medians of process medians. Timed work includes
decompression, full-content BLAKE3 verification, and staging-file
writes. Independent SHA-512 checks outside timing verified all 420
outputs in the final three-variant confirmation. Peak memory includes
process setup and independent verification.
Measurements used a plugged-in Apple M1 Max on Darwin ARM64, with
benchmark jobs serialized and file indexers temporarily suspended. Other
system work remained active; host snapshots are included. Scope is built
addon-file size and staging-file decoding. Full addon startup, npm
transfer size, and other-platform performance remain unmeasured.
</details>
<!-- native-decoding:end -->
<!-- native-packing:start -->
<details>
<summary>Compression memory savings and build-time CPU
tradeoff</summary>
The lookup table helps the compressor find repeated data. Its allocation
falls from **33.6 MB to 4.2 MB**, saving **29.4 MB (87.5%)**, when
comparing the `HashLog(23)` large-table control with `HashLog(20)`. This
is table allocation, not total process memory; Hash23 is not zstd's
default.

A separate three-pair comparison of Hash21 against Hash20 measured **4.2
MB less peak packing-benchmark memory on both inputs**:
| Packing benchmark | Hash21 control → Hash20 final |
| --- | ---: |
| SWC peak process memory | 358.0 → 353.8 MB |
| Rspack peak process memory | 674.5 → 670.3 MB |
| SWC process CPU time | 8.56 → 9.33 s (+9.00%) |
| Rspack process CPU time | 15.35 → 16.12 s (+5.02%) |
These fresh-process measurements include compression and exact
round-trip verification, with the compressor retained. They are distinct
from production-packer RSS and runtime memory. The smaller table trades
more build-time CPU for lower allocation; no compression-speed
improvement is claimed.
Final compressed payloads are 7.698436 MB for SWC and 11.133901 MB for
Rspack. The production packer reproduced the measured frames exactly.
Complete-file measurements above include loader overhead and padding.
</details>
<!-- native-packing:end -->
<details>
<summary>Implementation, correctness, and reproduction</summary>
- Inputs of at least 8 MiB use level 22, long-distance matching,
`HashLog(20)`, and `SearchLog(8)`. Smaller inputs retain level 16;
compression windows remain capped at 64 MiB.
- Images up to 64 MiB whose frame history covers the full output reuse
the decoded buffer as history. Other frames retain streaming. Writes are
grouped directly from that buffer, preserving hashing chunks and adding
no extra buffer or copying.
- Payload format, full-content integrity, window/length/target checks,
cache security, and atomic publication are preserved. No decmpfs
dependency is added.
- **40 crate tests passed; three platform-specific tests were skipped.**
Formatting and focused Clippy passed. Fixtures cover single-segment,
explicit-window, and legacy frames; both hash modes and corruption;
output-write failures; and the 64 MiB boundary.
- Both complete `.node` files built successfully and contained the exact
verified payloads. The combined table/write change adds no complete-file
size beyond the bulk decoder. The bulk decoder adds 0.0165 MB to the SWC
`.node` file compared with the same payload and streaming decoder; the
overall size reductions above already include that cost.
- Validation covers the native-addon crate and built Darwin ARM64
`.node` files. Full-workspace and cross-platform checks remain
outstanding. The required release changeset is included.
[Raw results, input and binary hashes, source, host snapshots,
validation logs, chart scripts, and reproduction
instructions](https://github.com/jdalton/swc/tree/3a1861698ef6fb777cbe5e8bf0ff4d8cd5c9cdc2/benchmark-artifacts/decoding/final-0a101c704-20261109).
The optional local benchmark guard suspends only explicitly selected
`fff-mcp` indexers and restores them after the batch or on timeout.
</details>
**Related issue:**
[#12741](https://github.com/swc-project/swc/issues/12741).
<details>
<summary>Memory scope and compression CPU tradeoff</summary>
Measured peak decoding-benchmark process memory falls from **46.0 to
44.4 MB for SWC** and **72.2 to 65.2 MB for Rspack**. The separate
**29.4 MB saving** is compression lookup-table allocation against the
explicitly configured large-table control, not total process RAM or a
comparison against zstd defaults.
The smaller table uses **5–9% more packing CPU time** in the paired
measurements. This is a deliberate build-time cost for lower memory;
runtime decoding remains faster. No packing-speed improvement is
claimed.
</details>
<details>
<summary>Current revision and review follow-up</summary>
Rebased onto upstream `main` at `96e93547e` and consolidated into one
commit. Historical benchmark links above retain the exact measured
revisions; the refresh has not been re-benchmarked.
Both Codex documentation findings are addressed: the release guide and
crate format guide describe the level-22 threshold and level-16
fallback, and the memory contract distinguishes the bounded bulk-output
buffer from streaming and total process memory.
Validation: 40 native crate tests passed, with three platform-specific
tests ignored. Focused Clippy and formatting passed. Full-workspace
Clippy and the Node development build could not complete within
available local disk space; Node integration tests were therefore not
run.
CodSpeed’s CPU simulation report warns that syscall costs are omitted.
The filesystem and decoding results above use separate wall-clock
measurements and are not inferred from that CPU simulation report.
</details> Latest Branches
+2%
jdalton:perf/native-btrfs-codec-fallback +2%
jdalton:perf/native-payload-long-matches +2%
© 2026 CodSpeed Technology