Skip to content

Commit fd79dab

Browse files
committed
perf(inflate): widen [512,2048)-byte initial output estimate to 160x
fzip's two-block periodic encoder now packs 100 KiB into ~700-750 bytes (~140x), which fell just under the previous 96x initial-buffer estimate and forced a mid-decode realloc plus a full-buffer copy. Inputs this small are exactly the ones most likely to be highly compressible (runs, periodic, sparse), so bias the estimate higher for this size class; the buffer is trimmed to the exact length afterwards, and output is byte-identical. inflate decompress (native, isolated, 100K periodic seq): - raw deflate: 15.17 -> 12.91 us (-14.9%) back to ~flat vs the pre-periodic baseline (12.17 us); the residual is the bulk block's tiny dynamic-table build. - <512-byte and >=2048-byte inputs are untouched (zeros/random unaffected). - All 367 tests pass on wasm-gc, native, js. No public API change.
1 parent 915e191 commit fd79dab

2 files changed

Lines changed: 12 additions & 2 deletions

File tree

src/inflate.mbt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@ fn initial_inflate_size(sl : Int, max_output_size : Int) -> Int raise FzipError
2525
}
2626
let base = sl * 3
2727
if sl >= 512 && sl < 2048 {
28-
let expanded = sl * 96
28+
// Small inputs in this range are frequently highly compressible (runs,
29+
// periodic data, sparse buffers) and expand by well over 100x. fzip's
30+
// periodic encoder packs 100 KiB into ~700 bytes (~140x), so a smaller
31+
// multiplier would force a mid-decode realloc + buffer copy. Estimate
32+
// generously here (the buffer is trimmed to the exact length afterwards)
33+
// so these streams decode in a single allocation.
34+
let expanded = sl * 160
2935
if expanded > max_output_size {
3036
max_output_size
3137
} else {

src/inflate_wbtest.mbt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,13 @@ test "inflate/high_ratio_preallocation/100kb_sequential" {
102102

103103
///|
104104
test "inflate initial size heuristic" {
105+
// sl < 512 and sl >= 2048 use the proportional base estimate (sl * 3).
105106
assert_eq(initial_inflate_size(100, default_max_output_size), 300)
106-
assert_eq(initial_inflate_size(512, default_max_output_size), 49152)
107107
assert_eq(initial_inflate_size(2048, default_max_output_size), 6144)
108+
// [512, 2048) is biased high (sl * 160) because inputs this small are often
109+
// highly compressible (runs/periodic) and expand >100x; the generous estimate
110+
// lets them decode in a single allocation.
111+
assert_eq(initial_inflate_size(512, default_max_output_size), 81920)
108112
}
109113

110114
///|

0 commit comments

Comments
 (0)