Skip to content

perf: switch flate2 to the zlib-rs backend (2.3x faster gzip) - #138

Open
BenjaminDEMAILLE wants to merge 1 commit into
seqeralabs:mainfrom
BenjaminDEMAILLE:perf/flate2-zlib-ng
Open

perf: switch flate2 to the zlib-rs backend (2.3x faster gzip)#138
BenjaminDEMAILLE wants to merge 1 commit into
seqeralabs:mainfrom
BenjaminDEMAILLE:perf/flate2-zlib-ng

Conversation

@BenjaminDEMAILLE

@BenjaminDEMAILLE BenjaminDEMAILLE commented Aug 13, 2026

Copy link
Copy Markdown

What

Switches flate2 from its default miniz_oxide backend to zlib-rs, a pure-Rust rewrite of zlib. Dependency change only, no source changes.

Measurement

Decompressing Homo_sapiens.GRCh38.113.gtf.gz (61 MB compressed, 1.74 GB / 4,114,455 lines uncompressed) through io::open_reader(), aarch64 macOS, hyperfine -w 1 -r 5:

backend time vs current
miniz_oxide (current default) 777.4 ms ± 7.8 ms
zlib-ng (C) 441.4 ms ± 2.4 ms 1.76x
zlib-rs (this PR) 334.9 ms ± 1.4 ms 2.32x

End to end, parse_gtf() on that gzipped GTF: 2.997 s ± 0.015 s → 2.820 s ± 0.024 s. The gzip path is a fixed cost on every run that uses a .gz annotation, which is the common case for Ensembl/GENCODE downloads.

Why zlib-rs and not zlib-ng

I benchmarked both. zlib-ng is the more commonly cited option but it is C: it needs cmake at build time and adds a native artifact to all 8 release targets and the Docker images. zlib-rs is faster here and pure Rust, so nothing changes for cross-compilation or the release matrix.

libz-ng-sys would also have been safe symbol-wise (it builds in non-compat zng_ mode, so no clash with the zlib that rust-htslib links), but there was no reason to take the C dependency once zlib-rs measured faster.

Notes

  • rust-htslib keeps using its own zlib for BGZF. This only affects the annotation-file reader in src/io.rs.
  • Bumped the flate2 requirement to 1.1 since that is where the zlib-rs backend landed. MSRV is unaffected (project is on 1.87).
  • cargo test --release passes (200 + 12 + 18 + 2). Parsing the same annotation plain vs gzipped gives identical results (78,932 genes / 387,944 transcripts / 2,164,410 exons).

🤖 Generated with Claude Code

Part of #143.

flate2's default backend is miniz_oxide. zlib-rs is a pure-Rust rewrite of
zlib (Trifecta Tech) and is substantially faster at inflate, which is what
RustQC does with .gz annotation files.

Decompressing Homo_sapiens.GRCh38.113.gtf.gz (61 MB -> 1.74 GB,
4,114,455 lines), aarch64 macOS, hyperfine -w 1 -r 5:

  miniz_oxide (current): 777.4 ms ± 7.8 ms
  zlib-ng (C):           441.4 ms ± 2.4 ms
  zlib-rs (this PR):     334.9 ms ± 1.4 ms

zlib-rs is 2.32x faster than the current backend and 1.32x faster than the
C zlib-ng backend. End to end, parse_gtf() on that gzipped GTF goes from
2.997 s ± 0.015 s to 2.820 s ± 0.024 s.

zlib-rs was preferred over zlib-ng because it needs no C toolchain and no
cmake, so it does not complicate the 8-target release matrix or the Docker
builds. It is a pure-Rust dependency swap: no source changes.

Parsing the same annotation plain and gzipped produces identical results
(78,932 genes / 387,944 transcripts / 2,164,410 exons).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant