# lzbench: many compressors, one compiler, one executable

> lzbench is an in-memory benchmarking tool that compiles dozens of open source compressors into a single binary and runs them over the same input buffer, so the numbers are comparable in a way that separate downloads are not. Its most instructive feature is the per-codec notes column, which documents exactly which platforms and toolchains each compressor can be built for.

**inikep/lzbench** — lzbench is an in-memory benchmark of open-source compressors

- Repository: https://github.com/inikep/lzbench
- Stars: 1,101 · Forks: 222
- Language: C
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/inikep-lzbench

## The fairness comes from the build, not from the benchmark

lzbench is described as an in-memory benchmarking tool for open-source compressors, and it integrates all compressors into a single executable.

The method is stated plainly in the introduction. Initially, an input file is loaded into memory, after which each compressor is used to compress and decompress the file, ensuring the decompressed output matches the original.

That last clause is the one that matters most. A benchmark that reports only compression ratios can flatter a broken codec, because a compressor that throws away data is spectacular at compressing. Verifying that the decompressed output matches the original on every iteration turns the tool from a ratio calculator into a correctness check as well.

The stated advantage of the method is the one that makes the whole approach worth the effort: it provides the advantage of compiling all compressors with the same compiler and optimizations. If you benchmark zstd built by your distribution against lz4 built by a vendor against brotli built from a release tarball, you are measuring three toolchains as much as three algorithms. lzbench removes that variable by construction.

The cost of that fairness is the requirement that you have access to the source code of each compressor. The README is explicit about the consequence, and names the casualties: it means e.g. Slug and lzturbo are not included. A benchmark that could only test closed source codecs would be a different tool, and the trade is stated rather than hidden.

## The command line is a small query language

The usage is a single line of options followed by one or more input files, and the options compose in ways that are worth understanding before you run anything.

The examples in the README show the shape. Selecting a codec is a dash followed by the name, and levels are comma separated inside it: lzbench -ezstd filename selects all levels of zstd, and lzbench -ebrotli,2,5/zstd filename selects levels 2 and 5 of brotli and zstd, with the slash separating codecs. A time budget is a t with two numbers, where lzbench -t3,5 fname means 3 seconds of compression and 5 seconds of decompression loops, and the iteration count is an i, so lzbench -t0,0 -i3,5 fname asks for 3 compression and 5 decompression iterations instead of a time budget. The output format is an o with a format character and a sort column, and lzbench -o1c4 fname asks for markdown output sorted by the fourth column.

The directory mode is the most useful one for a real corpus. lzbench -ezlib -j -r dirname/ tests zlib on all files in a directory, recursively.

The two knobs, time budget and iteration count, exist because they answer different questions. A time budget measures throughput, which is what matters for a server compressing responses. An iteration count measures the ratio you get after a fixed number of passes, which is what matters when the codec has a training phase. Setting both to zero and asking for a fixed iteration count is how you compare ratios fairly rather than comparing whatever each codec reached in three seconds.

The complete list of options is in the manual, doc/lzbench.7.txt, in the doc directory, and the README says to refer to it for more detailed documentation.

## Building is one make command and a Makefile that explains itself

The build requirements are short. You need a C and C++ compiler that is GNUC-compatible, such as GCC, LLVM/Clang, or ICC, and the recommendation is GCC 7.1+ or Clang 6.0+. For Linux, macOS and MinGW on Windows, the build is:

```bash
make -j$(nproc)
```

The default linking for Linux is dynamic and static for Windows, and that can be changed with make BUILD_STATIC=0/1. The complete building instructions, with troubleshooting, are in BUILD.md.

The Makefile is unusually well documented, and reading it is the fastest way to understand the project's structure. The comments at the top show the switches: make BUILD_TYPE=debug for a debug build, make BUILD_ARCH=32-bit for 32-bit compilation, make CC=gcc-14 CXX=g++-14 for a non-default compiler, make MOREFLAGS="-march=native" or the USER_CFLAGS and USER_CXXFLAGS equivalents for an optimised but non-portable build, and make DONT_BUILD_LZHAM=1 to leave a codec out, with the names being the ones used in the mk/*.mk files. CUDA codecs are enabled with make ENABLE_CUDA=1, optionally with CUDA_BASE pointing at a CUDA installation.

That last point leads to the most interesting structural fact in the repository. Every codec is described by its own file in the mk directory, and the top level of the tree is organised by technique rather than by codec: bench, bwt, lz, lz+entropy, misc and mk. So adding a codec is a matter of writing a description file, and the build system is arranged so that the Makefile does not need to know about any of them individually.

Out-of-tree builds are supported too. The Makefile notes that make -f /path/to/lzbench/Makefile builds in the current directory, using vpath to find the sources.

## The Notes column is where the real information is

The supported compressors table has three columns, and the third one is the reason to read the README rather than skim it.

The Last update column is defined as the release date of the bundled version, so you always know which upstream release is under test. The Notes column records where lzbench carries local build fixes to a codec's sources, where a codec is excluded from a platform, and what a codec needs in order to build at all.

The entries are specific in a way that general documentation rarely is. The aocl-compression build is disabled by default and enabled with make DONT_BUILD_AOCL=0, it is Linux x86-64 only, and it provides AMD-optimized versions of lz4, lz4hc, lzma, bzip2, snappy, zlib and zstd with an aocl- prefix, and it requires GNU binutils, meaning nm and objcopy. The bsc codec is disabled on 32-bit ARM because multithreaded decompression faults with SIGBUS, with the issue number given. The density compressor requires the Rust toolchain and is skipped for 32-bit, cross-compiled and Windows builds. The lzham entry records that it has been public domain since 2020-09-15, that lzbench fixes the build for MinGW and newer compilers, and that it is disabled on macOS and 32-bit x86 because the 64 MB dictionary overflows the 32-bit address space.

That last one is the kind of note that saves a day. A compressor that is silently absent from a benchmark table looks like a compressor that lost. Here, the absence is documented and explained.

There are also entries for codecs that need other toolchains: mbrotli requires the Rust toolchain 1.89+, misa77 is little-endian 64-bit only and needs a C++20 compiler so GCC 10+ or Clang 12+, and skim requires the Zig compiler. The CUDA codecs, gpucompact and nvcomp, are built with make ENABLE_CUDA=1 and nvcomp is explicitly not in the default CI matrix.

## A benchmark that bundles forty codecs bundles forty licences

The licence story here is more complicated than a single file, and it is a direct consequence of what the tool is.

The lzbench project itself carries a LICENSE file, and GitHub's own classification for the repository comes out as a custom licence it could not map to a standard identifier, so that file is the text to read. But the more important point is that the licences of the bundled codecs are individual, and the table records them where they differ. The aocl-compression row lists BSD 3-Clause, MIT and NCSA. The pulsar row notes GPL-3. The lzham row records public domain since 2020-09-15.

That matters for anyone who takes this repository and redistributes it, and for anyone who builds it and ships the resulting binary. A GPL-3 codec in the tree is a different situation from a public domain one, and a benchmark that mixes them makes a single licence claim about the whole artefact impossible to make honestly.

This is the same reason the tool needs codec source access in the first place. The design choice that gives fair benchmarks, everything compiled with the same compiler, is also the design choice that turns the repository into an aggregator of other people's code with their own terms attached.

None of this is a reason to avoid the tool, and the project is plainly careful about it, since the Notes column exists partly to record where lzbench has patched a codec's sources. It is a reason to read the table rather than skim it, and to check what you are about to redistribute.

## Regular releases, a wide CI matrix, and a maintained changelog

The maintenance signals are consistent. The recent tags are v2.2 from 2025-10-28, v2.3 from 2026-06-15 and v2.4 from 2026-09-27, and the last push to the repository was on 2026-10-14, so the tool is being worked on right now rather than sitting on a finished release.

The list of changes is available in the CHANGELOG, and contributor information is in CONTRIBUTING.md, which is the arrangement you want from a project with this many external codebases vendored into it.

The continuous integration matrix is described in the README and it is broad. The Azure Pipelines badge covers gcc and clang tests, and compressors are built on every CI platform, which the README lists as Linux x86-64, x86-32, ARM64, ARM32 and PPC64LE, macOS arm64, and Windows MinGW, unless the Notes column says otherwise. That matrix is the direct explanation of the per-codec notes, since a codec that cannot build on ARM32 is excluded there and recorded here.

For a user, the practical effect is that the supported set of codecs varies by platform in a documented way, and the way to find out which ones you actually have is to read the table for your target and then run the tool.

The scope of the tool is worth restating at the end. lzbench measures compression libraries, not compression deployments. It does not model your storage system, your page cache or your network, and the numbers it gives are the numbers you get when the codec is warm in memory with a fixed input. That is the right tool for choosing a library and the wrong tool for predicting your application.

## Conclusion

lzbench fits a developer choosing a compression library for a real project and needing numbers they can trust, because every codec is compiled with the same compiler and the same optimisation flags and the round trip is verified on every iteration. It does not fit a comparison of codecs you cannot build from source, since Slug and lzturbo are excluded for that reason, and it does not fit a machine where the platform limits apply, such as a 32-bit ARM target or a build without the Rust toolchain. Before you trust a number, read the Notes column for that codec and check whether your build actually included it.

## FAQ

### What is lzbench and how does it benchmark compressors?

It is an in-memory benchmarking tool for open-source compressors that integrates many of them into a single executable. An input file is loaded into memory, then each compressor compresses and decompresses it and the output is checked against the original, with all compressors compiled by the same compiler and optimisation settings.

### How do I build lzbench?

You need a GNUC-compatible C and C++ compiler such as GCC, LLVM/Clang or ICC, with GCC 7.1+ or Clang 6.0+ recommended, then run make -j$(nproc) on Linux, macOS or MinGW. Linking is dynamic on Linux and static on Windows by default and can be changed with make BUILD_STATIC=0/1.

### How do I run a specific codec and level with lzbench?

Select the codec after a dash, with levels comma separated inside it, and separate codecs with a slash. The README gives lzbench -ezstd filename to select all levels of zstd and lzbench -ebrotli,2,5/zstd filename to select levels 2 and 5 of brotli and zstd.

### Why are some compressors missing from lzbench on my platform?

The Notes column in the supported compressors table records each exclusion. Examples: bsc is disabled on 32-bit ARM because multithreaded decompression faults, lzham is disabled on macOS and 32-bit x86 because its 64 MB dictionary overflows the address space, and density, mbrotli, pulsar and skim need the Rust or Zig toolchains, so they are skipped on 32-bit, cross-compiled and Windows builds.

### Can lzbench benchmark codecs that are not open source?

No. The method requires access to the source code of each compressor, which is why the README notes that Slug and lzturbo are not included. That requirement is what allows every codec to be compiled with the same compiler and optimisations.

## Sources

- [inikep/lzbench on GitHub](https://github.com/inikep/lzbench)
- [Issues](https://github.com/inikep/lzbench/issues)
- [README](https://github.com/inikep/lzbench/blob/master/README.md)
- [Releases](https://github.com/inikep/lzbench/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/inikep-lzbench
