Hi,

I'd like to report some measurements rather than send a patch.

Two of gzip's hottest loops still work one byte at a time:
- longest_match() in deflate.c compares candidate matches byte by byte;
- NEEDBITS in inflate.c pulls input into the bit buffer one byte per
iteration.

Doing both a word at a time, as zlib and its forks do, gives the gains
below. I combined that with a 64-bit bit buffer on the output side
(send_bits/compress_block). The compressed output is byte-for-byte
identical to unpatched gzip at every level 1-9 and with --rsyncable.

Specifically:
- longest_match: the candidate filter tests the same two byte pairs as
16-bit loads. The rest is compared 8 bytes at a time via memcpy + le64toh +
stdc_trailing_zeros. Same lengths, no reads past offset 258.
- inflate: when at least 8 bytes are buffered, up to 7 bytes are refilled
at once. The existing give-back at the end of a block keeps the trailer
position unchanged.

Numbers are unpatched/patched CPU-time ratios (higher is better). Both
builds are from current master (b4ed8e7) with the same flags. Runs are
interleaved A/B with alternating order, and each figure is the median per
file.

Corpus:
- an ~800k-token LLM chat transcript as JSONL (2.4 MB), and the same file
x16 (39 MB);
- silesia.tar;
- a tar of /usr/lib binaries (46 MB);
- 25 MB of random data.

"All files" is total CPU summed over the five files.

macOS, Mac mini M4 Pro (real hardware), Apple clang 21 -O2, 16 runs:

-1 -6 -9 -d
LLM thread 1.16 1.16 1.15 1.07
LLM thread x16 1.18 1.17 1.16 1.11
silesia.tar 1.19 1.19 1.16 1.13
all files 1.17 1.18 1.15 1.13

A/A noise (stock vs. stock, 11 runs): within 1% per file.

Linux x86-64, Intel Sapphire Rapids, 8-vCPU KVM VM, Debian 13, gcc 14.2
-O2, pinned to one CPU, 12 runs:

-1 -6 -9 -d
LLM thread 1.15 1.15 1.12 1.12
LLM thread x16 1.18 1.16 1.12 1.16
silesia.tar 1.21 1.17 1.04 1.12
all files 1.19 1.16 1.04 1.14

A/A noise on this VM: about +/-4% per file. So the -9 binary-data gains on
x86 are close to noise. On text the gain is clear.

Testing:
- make check, plus ASan/UBSan and valgrind;
- about 15k differential fuzz cases against stock gzip, covering edge sizes
around WSIZE/INBUFSIZ/MAX_MATCH, multi-member, truncated and corrupt input
(same exit code and messages);
- big-endian s390x and ppc64, plus aarch64 and 32-bit ARM, under qemu-user.

To be upfront: I used an LLM to make these changes. I reviewed the code,
ran the tests and did the benchmarks myself. Given the GNU/gnulib policy on
LLM-generated code, I'm not attaching the patch. If you think this is worth
having, I'm happy to write a clean implementation myself from the
description above. I'm ready to sign an FSF copyright assignment. I can
also share the benchmark scripts and corpus setup.

Thanks,
Silvio Ney

Reply via email to