Skip to content

Reduce Flate decoding cost: reserve output capacity, use zlib-rs - #655

Merged
Velli20 merged 2 commits into
mainfrom
flate-decode-capacity
Oct 31, 2026
Merged

Velli20 merged 2 commits into
mainfrom
flate-decode-capacity

Conversation

@Velli20

@Velli20 Velli20 commented Oct 31, 2026

Copy link
Copy Markdown
Owner

Closes #621.

Changes

  • Capacity reservation. decode_flate now reserves 4× the encoded length up front instead of growing from an empty Vec. The reservation is capped at 16 MiB, so a small stream that expands enormously can't use it to grab memory. When a low-ratio stream leaves more than half of the reservation unused, the output is shrunk, because decoded data is kept as Bytes.
  • zlib-rs backend. flate2 1.1.10 now uses default-features = false, features = ["zlib-rs"]. zlib-rs is pure Rust, built from source, with no prebuilt binaries or C build. pdf-filter is flate2's only runtime user (the parser and object-collection crates use it only in tests), and miniz_oxide is no longer in pdf-filter's dependency tree.
  • New benchmark. crates/pdf-filter/benches/flate_decode.rs decodes synthetic content (2 MiB of operator text), image (3 MiB RGB gradient) and font-like (512 KiB, low ratio) streams through pdf_filter::filter::decode.

Benchmarks

Shipped release profile (opt-level "z", fat LTO), 5 interleaved rounds, --measurement-time 5, mean of criterion's point estimates.

flate_decode:

stream original + reservation + reservation + zlib-rs
content 1.011 ms 0.987 ms 0.219 ms (4.6×)
font 0.169 ms 0.165 ms 0.050 ms (3.4×)
image 3.580 ms 3.559 ms 2.061 ms (1.7×)

A rebuilt copy of the original measured 0.983 / 0.170 / 3.570 ms, so the reservation alone (with miniz_oxide) is within the noise. With zlib-rs, removing the reservation measured 0.228 / 0.048 / 2.119 ms, so the reservation helps image-sized streams by about 2%. ×2 and ×8 multipliers were not better than ×4.

document_open:

document original zlib-rs only zlib-rs + reservation
Gradients.pdf 16.85 ms 15.90 ms 15.64 ms
PlaygroundMDN.pdf 3.217 ms 3.023 ms 2.916 ms
RadialGradientFills.pdf 3.556 ms 3.189 ms 3.149 ms
W3Schools.pdf 2.895 ms 2.718 ms 2.668 ms
dd5cf1a7….pdf 30.68 ms 28.74 ms 28.66 ms
is.pdf 130.2 ms 128.6 ms 129.7 ms
test6.pdf 0.236 ms 0.225 ms 0.218 ms
webgl.pdf 24.51 ms 23.55 ms 23.07 ms

The release web-canvas wasm grows by 20 KB (23,767,525 → 23,787,586 bytes, +0.08%).

Verification

  • cargo test with 859 passing, and cargo clippy --all-targets -- -D warnings. Both were run on the workspace excluding pdf-graphics-skia and pdf-conformance, whose Skia build script downloads prebuilt binaries, which the local sandbox blocks. CI covers those crates.
  • cargo fmt --check, cargo build --workspace (same exclusions), and cargo xtask web-canvas --profile release.

🤖 Generated with Claude Code

Velli20 and others added 2 commits October 31, 2026 16:44
decode_flate grew its output from an empty Vec, so large streams were
reallocated and copied as they decoded. Reserve four times the encoded
length, capped at 16 MiB so a small stream that expands enormously
cannot reserve memory before it produces it, and give back a reservation
a low-ratio stream left mostly unused.

Add a flate_decode benchmark over content-, image- and font-like streams.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Switch flate2 from miniz_oxide to its pure-Rust zlib-rs backend, built
from source like the rest of the dependency tree. Under the shipped
release profile it decodes the flate_decode benchmark streams 1.7x to
4.6x faster and opens the example documents 6-12% faster.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Velli20
Velli20 merged commit 7815c95 into main Oct 31, 2026
10 checks passed
@Velli20
Velli20 deleted the flate-decode-capacity branch October 31, 2026 16:58
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.

Reduce reallocations in Flate decoding (and evaluate the zlib-rs backend)

1 participant