Context
Flamegraph on i9 of `decompress/level_-3_fast/decodecorpus-z000033/c_stream/matrix/pure_rust_direct` shows:
- 82% `__memmove_avx_unaligned_erms` (decoder match-copy + literal-push)
- 67% `do_user_addr_fault` + 60% `handle_mm_fault` + 55% `do_anonymous_page` (anonymous-page allocation)
- 34% `alloc_anon_folio`, 20% `vma_alloc_folio_noprof`
The page-fault stack dominates because each criterion iteration allocates a FRESH output Vec sized to the declared FCS, and the kernel lazily maps anonymous pages on first touch. The cost amortises poorly because criterion runs >100 iterations and each one re-pays.
This is a bench-harness artifact, not a decoder property — the dashboard shows `-54.68%` vs donor on this fixture mostly because of this, not because of actual decoder slowness.
Proposal
In `zstd/benches/compare_ffi.rs`, the closure given to `b.iter` should:
- Allocate the output Vec once outside the iter (in the surrounding `bench_function_with_input`).
- Pre-touch every page by writing 0 (e.g. `std::ptr::write_bytes(buf.as_mut_ptr(), 0, fcs)` or `buf.fill(0)`) BEFORE `b.iter`.
- Inside the iter, reuse the same buffer (caller passes `&mut buf[..fcs]` to the decoder).
For the `pure_rust_direct` path that uses `decode_to_slice_trusted`, the slice already lives outside; just ensure pre-touch happens.
Acceptance criteria
Part of #247.
Context
Flamegraph on i9 of `decompress/level_-3_fast/decodecorpus-z000033/c_stream/matrix/pure_rust_direct` shows:
The page-fault stack dominates because each criterion iteration allocates a FRESH output Vec sized to the declared FCS, and the kernel lazily maps anonymous pages on first touch. The cost amortises poorly because criterion runs >100 iterations and each one re-pays.
This is a bench-harness artifact, not a decoder property — the dashboard shows `-54.68%` vs donor on this fixture mostly because of this, not because of actual decoder slowness.
Proposal
In `zstd/benches/compare_ffi.rs`, the closure given to `b.iter` should:
For the `pure_rust_direct` path that uses `decode_to_slice_trusted`, the slice already lives outside; just ensure pre-touch happens.
Acceptance criteria
Part of #247.