Skip to content

perf: bulk memcpy for primitive vector encoding on LE platforms - #715

Merged
lwshang merged 3 commits into
masterfrom
sat-perf-bulk-encode
Mar 15, 2026
Merged

perf: bulk memcpy for primitive vector encoding on LE platforms#715
lwshang merged 3 commits into
masterfrom
sat-perf-bulk-encode

Conversation

@sasa-tomic

@sasa-tomic sasa-tomic commented Mar 13, 2026

Copy link
Copy Markdown
Contributor

Summary

On little-endian targets (including wasm32), Vec<i16/u32/f64/etc.> encoding now writes the backing memory directly instead of iterating element-by-element through the Serializer trait.

  • Added try_write_raw_elements default method to Compound trait
  • ValueSerializer::Compound implements it with direct byte write
  • [T]::idl_serialize detects fixed-width primitives via TypeId on #[cfg(target_endian = "little")]
  • Vec<T> and [T; N] delegate to the optimized slice path
  • Excludes usize/isize (platform-dependent size)

Benchmark (canbench, wasm32)

Metric Before After Change
vec_int16 Encoding 123.7M inst 8.4M inst 14.7x faster (-93.2%)
vec_int16 Total 817.9M inst 704.7M inst -13.8%

No regressions on any of the 9 benchmarks.

Compatibility

Wire format is unchanged — produces byte-identical output. Round-trip compatibility test added.

Relates to #710

@sasa-tomic
sasa-tomic requested a review from a team as a code owner March 13, 2026 14:04
@github-actions

github-actions Bot commented Mar 13, 2026

Copy link
Copy Markdown
Name Max Mem (Kb) Encode Decode
blob 4_224 4_207_487 2_122_465 ($\textcolor{red}{0.00\%}$)
btreemap 73_856 531_975_943 ($\textcolor{red}{0.00\%}$) 13_058_092_273 ($\textcolor{red}{0.57\%}$)
nns 192 2_021_253 5_670_864 ($\textcolor{red}{0.12\%}$)
nns_list_proposal 1_216 7_018_096 ($\textcolor{red}{0.12\%}$) 64_361_414 ($\textcolor{red}{0.08\%}$)
option_list 64 715_981 ($\textcolor{green}{-0.00\%}$) 21_800_274 ($\textcolor{green}{-0.40\%}$)
text 6_336 4_204_384 7_877_792 ($\textcolor{red}{0.00\%}$)
variant_list 64 710_969 ($\textcolor{green}{-0.00\%}$) 20_596_350 ($\textcolor{red}{0.33\%}$)
vec_int16 12_480 ($\textcolor{green}{-25.29\%}$) 8_404_689 ($\textcolor{green}{-93.21\%}$) 635_462_524 ($\textcolor{red}{0.33\%}$)
  • Parser cost: 16_174_059
  • Extra args: 2_872_191
Click to see raw report
---------------------------------------------------

Benchmark: blob
  total:
    instructions: 6.33 M (0.00%) (change within noise threshold)
    heap_increase: 66 pages (no change)
    stable_memory_increase: 0 pages (no change)

  1. Encoding (scope):
    calls: 1 (no change)
    instructions: 4.21 M (no change)
    heap_increase: 66 pages (no change)
    stable_memory_increase: 0 pages (no change)

  2. Decoding (scope):
    calls: 1 (no change)
    instructions: 2.12 M (0.00%) (change within noise threshold)
    heap_increase: 0 pages (no change)
    stable_memory_increase: 0 pages (no change)

---------------------------------------------------

Benchmark: btreemap
  total:
    instructions: 13.59 B (0.54%) (change within noise threshold)
    heap_increase: 1154 pages (no change)
    stable_memory_increase: 0 pages (no change)

  1. Encoding (scope):
    calls: 1 (no change)
    instructions: 531.98 M (0.00%) (change within noise threshold)
    heap_increase: 159 pages (no change)
    stable_memory_increase: 0 pages (no change)

  2. Decoding (scope):
    calls: 1 (no change)
    instructions: 13.06 B (0.57%) (change within noise threshold)
    heap_increase: 995 pages (no change)
    stable_memory_increase: 0 pages (no change)

---------------------------------------------------

Benchmark: extra_args
  total:
    instructions: 2.87 M (no change)
    heap_increase: 0 pages (no change)
    stable_memory_increase: 0 pages (no change)

---------------------------------------------------

Benchmark: nns
  total:
    instructions: 24.70 M (0.03%) (change within noise threshold)
    heap_increase: 3 pages (no change)
    stable_memory_increase: 0 pages (no change)

  0. Parsing (scope):
    calls: 1 (no change)
    instructions: 16.17 M (no change)
    heap_increase: 3 pages (no change)
    stable_memory_increase: 0 pages (no change)

  1. Encoding (scope):
    calls: 1 (no change)
    instructions: 2.02 M (no change)
    heap_increase: 0 pages (no change)
    stable_memory_increase: 0 pages (no change)

  2. Decoding (scope):
    calls: 1 (no change)
    instructions: 5.67 M (0.12%) (change within noise threshold)
    heap_increase: 0 pages (no change)
    stable_memory_increase: 0 pages (no change)

---------------------------------------------------

Benchmark: nns_list_proposal
  total:
    instructions: 71.38 M (0.08%) (change within noise threshold)
    heap_increase: 19 pages (no change)
    stable_memory_increase: 0 pages (no change)

  1. Encoding (scope):
    calls: 1 (no change)
    instructions: 7.02 M (0.12%) (change within noise threshold)
    heap_increase: 5 pages (no change)
    stable_memory_increase: 0 pages (no change)

  2. Decoding (scope):
    calls: 1 (no change)
    instructions: 64.36 M (0.08%) (change within noise threshold)
    heap_increase: 14 pages (no change)
    stable_memory_increase: 0 pages (no change)

---------------------------------------------------

Benchmark: option_list
  total:
    instructions: 22.52 M (-0.39%) (change within noise threshold)
    heap_increase: 1 pages (no change)
    stable_memory_increase: 0 pages (no change)

  1. Encoding (scope):
    calls: 1 (no change)
    instructions: 715.98 K (-0.00%) (change within noise threshold)
    heap_increase: 0 pages (no change)
    stable_memory_increase: 0 pages (no change)

  2. Decoding (scope):
    calls: 1 (no change)
    instructions: 21.80 M (-0.40%) (change within noise threshold)
    heap_increase: 1 pages (no change)
    stable_memory_increase: 0 pages (no change)

---------------------------------------------------

Benchmark: text
  total:
    instructions: 12.08 M (0.00%) (change within noise threshold)
    heap_increase: 99 pages (no change)
    stable_memory_increase: 0 pages (no change)

  1. Encoding (scope):
    calls: 1 (no change)
    instructions: 4.20 M (no change)
    heap_increase: 66 pages (no change)
    stable_memory_increase: 0 pages (no change)

  2. Decoding (scope):
    calls: 1 (no change)
    instructions: 7.88 M (0.00%) (change within noise threshold)
    heap_increase: 33 pages (no change)
    stable_memory_increase: 0 pages (no change)

---------------------------------------------------

Benchmark: variant_list
  total:
    instructions: 21.31 M (0.32%) (change within noise threshold)
    heap_increase: 1 pages (no change)
    stable_memory_increase: 0 pages (no change)

  1. Encoding (scope):
    calls: 1 (no change)
    instructions: 710.97 K (-0.00%) (change within noise threshold)
    heap_increase: 0 pages (no change)
    stable_memory_increase: 0 pages (no change)

  2. Decoding (scope):
    calls: 1 (no change)
    instructions: 20.60 M (0.33%) (change within noise threshold)
    heap_increase: 1 pages (no change)
    stable_memory_increase: 0 pages (no change)

---------------------------------------------------

Benchmark: vec_int16
  total:
    instructions: 643.87 M (improved by 14.95%)
    heap_increase: 195 pages (improved by 25.29%)
    stable_memory_increase: 0 pages (no change)

  1. Encoding (scope):
    calls: 1 (no change)
    instructions: 8.40 M (improved by 93.21%)
    heap_increase: 130 pages (improved by 50.19%)
    stable_memory_increase: 0 pages (no change)

  2. Decoding (scope):
    calls: 1 (no change)
    instructions: 635.46 M (0.33%) (change within noise threshold)
    heap_increase: 65 pages (regressed from 0)
    stable_memory_increase: 0 pages (no change)

---------------------------------------------------

Summary:
  instructions:
    status:   Improvements detected 🟢
    counts:   [total 9 | regressed 0 | improved 1 | new 0 | unchanged 8]
    change:   [max +73.40M | p75 +57.17K | median +33 | p25 0 | min -113.19M]
    change %: [max +0.54% | p75 +0.08% | median 0.00% | p25 0.00% | min -14.95%]

  heap_increase:
    status:   Improvements detected 🟢
    counts:   [total 9 | regressed 0 | improved 1 | new 0 | unchanged 8]
    change:   [max 0 | p75 0 | median 0 | p25 0 | min -66]
    change %: [max 0.00% | p75 0.00% | median 0.00% | p25 0.00% | min -25.29%]

  stable_memory_increase:
    status:   No significant changes 👍
    counts:   [total 9 | regressed 0 | improved 0 | new 0 | unchanged 9]
    change:   [max 0 | p75 0 | median 0 | p25 0 | min 0]
    change %: [max 0.00% | p75 0.00% | median 0.00% | p25 0.00% | min 0.00%]

---------------------------------------------------

Only significant changes:
| status | name                   | calls |     ins |  ins Δ% |  HI |   HI Δ% | SMI |  SMI Δ% |
|--------|------------------------|-------|---------|---------|-----|---------|-----|---------|
|   +    | vec_int16::2. Decoding |     1 | 635.46M |  +0.33% |  65 |   +inf% |   0 |   0.00% |
|   -    | vec_int16              |       | 643.87M | -14.95% | 195 | -25.29% |   0 |   0.00% |
|   -    | vec_int16::1. Encoding |     1 |   8.40M | -93.21% | 130 | -50.19% |   0 |   0.00% |

ins = instructions, HI = heap_increase, SMI = stable_memory_increase, Δ% = percent change

---------------------------------------------------
Successfully persisted results to canbench_results.yml

On little-endian targets (including wasm32), Vec<i16/u32/f64/etc.>
encoding now writes the backing memory directly instead of iterating
element-by-element through the Serializer trait.

Benchmark: vec_int16 encoding 123M → 8.4M instructions (14.7x faster).

Wire format is unchanged — produces byte-identical output.

Made-with: Cursor
@lwshang
lwshang force-pushed the sat-perf-bulk-encode branch from 33bbf0a to 1952d76 Compare March 15, 2026 17:37
@lwshang
lwshang changed the base branch from sat-perf-improvements to master March 15, 2026 17:45
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lwshang
lwshang merged commit eaf7e6c into master Mar 15, 2026
11 checks passed
@lwshang
lwshang deleted the sat-perf-bulk-encode branch March 15, 2026 17:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants