Ridiculously fast decompression at good ratios. misa77 is 1.5-3x faster than LZ4 for decompression on x86 and ARM (with better ratios!).
C++
172
13 commits
updated Aug 10, 2026
misa77 is an LZ-based codec that targets the write-once, read-many niche. In particular, it aims to satisfy the following criteria:
Slow compression is the obvious tradeoff that one makes to achieve the above.
misa77 has six compression effort levels as of v0.6.0. For most shapes of data, encode time increases and ratio decreases with increasing level, but decompression throughput is not similarly monotonic. In general, level 1 offers the fastest decode throughput. More information about effort levels can be found here.
There are two decompressor modes:
Note: As of now, level 4 doesn't have a safe decompressor. It will be added soon.
Detailed results are listed ahead, but here's a terse summary:
Let's first see some cross-platform results for the Silesia Corpus.
Note:
((compressed size)/(original)) * 100 (so lower is better).Details:
performance.| Compressor name | Compression | Decompress. | Ratio | Filename |
|---|---|---|---|---|
| misa77 0.6.0 --1 | 232 MB/s | 3846 MB/s | 46.74 | silesia.tar |
| misa77 0.6.0 -0 | 170 MB/s | 4593 MB/s | 44.60 | silesia.tar |
| misa77 0.6.0 -1 | 54.2 MB/s | 5376 MB/s | 42.64 | silesia.tar |
| misa77 0.6.0 -2 | 41.5 MB/s | 4689 MB/s | 40.33 | silesia.tar |
| misa77 0.6.0 -3 | 10.7 MB/s | 4635 MB/s | 37.76 | silesia.tar |
| misa77 0.6.0 -4 | 6.97 MB/s | 4366 MB/s | 35.51 | silesia.tar |
| lz4 1.10.0 | 371 MB/s | 2514 MB/s | 47.59 | silesia.tar |
| lz4hc 1.10.0 -9 | 22.0 MB/s | 2457 MB/s | 36.75 | silesia.tar |
| lz4hc 1.10.0 -12 | 7.31 MB/s | 2536 MB/s | 36.45 | silesia.tar |
| lzsse4fast 2019-04-18 | 187 MB/s | 2540 MB/s | 45.26 | silesia.tar |
| lzsse8fast 2019-04-18 | 183 MB/s | 2671 MB/s | 44.80 | silesia.tar |
| zxc 0.13.1 -3 | 114 MB/s | 2840 MB/s | 45.46 | silesia.tar |
| zxc 0.13.1 -4 | 80.6 MB/s | 2731 MB/s | 42.63 | silesia.tar |
| zxc 0.13.1 -5 | 48.2 MB/s | 2597 MB/s | 40.25 | silesia.tar |
| zxc 0.13.1 -7 | 4.26 MB/s | 1642 MB/s | 33.00 | silesia.tar |
| zstd 1.5.7 -1 | 297 MB/s | 903 MB/s | 34.54 | silesia.tar |
| lzav 5.16 -2 | 62.6 MB/s | 1675 MB/s | 34.85 | silesia.tar |
| snappy 1.2.2 | 375 MB/s | 858 MB/s | 47.89 | silesia.tar |
Details:
| Compressor name | Compression | Decompress. | Ratio | Filename |
|---|---|---|---|---|
| misa77 0.6.0 --1 | 541 MB/s | 9739 MB/s | 46.74 | silesia.tar |
| misa77 0.6.0 -0 | 385 MB/s | 11777 MB/s | 44.60 | silesia.tar |
| misa77 0.6.0 -1 | 135 MB/s | 12638 MB/s | 42.64 | silesia.tar |
| misa77 0.6.0 -2 | 103 MB/s | 10868 MB/s | 40.33 | silesia.tar |
| misa77 0.6.0 -3 | 19.5 MB/s | 10280 MB/s | 37.76 | silesia.tar |
| misa77 0.6.0 -4 | 13.5 MB/s | 9925 MB/s | 35.51 | silesia.tar |
| lz4 1.10.0 | 882 MB/s | 5195 MB/s | 47.59 | silesia.tar |
| lz4hc 1.10.0 -9 | 53.0 MB/s | 4899 MB/s | 36.74 | silesia.tar |
| lz4hc 1.10.0 -12 | 17.0 MB/s | 4887 MB/s | 36.45 | silesia.tar |
| zxc 0.13.1 -3 | 278 MB/s | 8022 MB/s | 45.77 | silesia.tar |
| zxc 0.13.1 -4 | 193 MB/s | 7642 MB/s | 43.20 | silesia.tar |
| zxc 0.13.1 -5 | 114 MB/s | 7162 MB/s | 40.30 | silesia.tar |
| zstd 1.5.7 -1 | 722 MB/s | 1615 MB/s | 34.54 | silesia.tar |
| lzav 5.16 -2 | 185 MB/s | 4243 MB/s | 34.85 | silesia.tar |
| snappy 1.2.2 | 967 MB/s | 3439 MB/s | 47.91 | silesia.tar |
As misa77's performance is quite "spiky" (depending on the shape of the data being compressed), a file-level breakdown for the silesia corpus yields some interesting insights into its performance.
Note:
At level 1, misa77 decodes faster than lz4 on all 12 files (some by huge margins).

On the compressible files, misa77 sits on the decode-throughput/ratio Pareto frontier: it decodes fastest while ~matching or beating the ratio of the other fast-LZ codecs. (x-ray and sao are exceptions as most compressors have a ratio near 1, and their decode essentially devolves to a memcpy).
To spot misa77 in these graphs, just look for the circles near the top :)

Levels are ordered by compression effort. For most shapes of data, encode time increases and ratio decreases with increasing level, but decompression throughput is not similarly monotonic.
| Level | Description | Ratio | Encode vs L1 | Decode vs L1 | Encoder memory | Format |
|---|---|---|---|---|---|---|
| -1 | fastest compression (not recommended as slow to decode) | 46.74 | 4.0-4.3x | 72-77% | 1 MB | light |
| 0 | fast compression, lz4-class ratio | 44.60 | 2.9-3.1x | 85-93% | 1 MB | light |
| 1 | default, fastest decode | 42.64 | 1x | 100% | 3 MB | light |
| 2 | better ratio, still cheap to encode | 40.33 | 0.76-0.77x | 86-87% | 3 MB | light |
| 3 | best ratio in the light format | 37.76 | 0.14-0.20x | 81-86% | 29 MB | light |
| 4 | best ratio overall, prefer on inputs above ~1 MB | 35.51 | 0.10-0.13x | 79-81% | 176 MB | heavy |
Ratio is measured on silesia.tar in the Intel run.Encode/Decode vs L1 columns are relative to level 1, given as the range spanned by the Intel and M3 runs.Encoder memory is the compressor's own working state (disjoint from the caller's input and output buffers). Decompression needs no working memory at all.docs/format.md) and have a safe decoder. Level 4 emits the heavy format, which does not have one yet.For the library:
For the CLI:
misa CLI needs POSIX (Linux, macOS).Note: On x86-64, AVX2/SSE2 are selected at runtime. ARM has a NEON path.
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
This produces the misa CLI at build/misa. For a binary tuned to the exact machine you'll run it on, add -DMISA77_MARCH=native (I recommend this). To run the round-trip test:
ctest --test-dir build
The build produces a static library (CMake target misa77) with a small C++ API in misa77/misa77.h. The easiest integration is a git submodule (or CMake FetchContent) plus:
add_subdirectory(misa77)
target_link_libraries(your_app PRIVATE misa77)
Sample usage:
#include <misa77/misa77.h>
#include <vector>
// compress (pick a level with misa77::config(N) with N in [-1, 4], default is 1), returns 0 on failure
misa77::config cfg;
std::vector<uint8_t> compressed(misa77::compress_bound(input_size, cfg));
uint64_t csize = misa77::compress(input, input_size, compressed.data(), compressed.size(), cfg);
compressed.resize(csize);
// decompress, returns original_size on success
uint64_t original_size = misa77::decompressed_size(compressed.data());
std::vector<uint8_t> output(misa77::decompressed_buffer_bound(original_size));
// decompress uses the unsafe decompressor by default, pass dconfig(true) to use the safe decompressor
uint64_t written = misa77::decompress(compressed.data(), csize, output.data(), output.size(), misa77::dconfig(true));
Three things to keep in mind:
compress_bound / decompressed_buffer_bound, passing compress_bound the same config you compress with (the bound depends on the level's format).misa77::dconfig(true) to misa77::decompress if you want the decompressor to exit gracefully on invalid input.decompress with dconfig(true) returns 0 for them (the unsafe path decodes them fine).The experimental modes are declared in misa77/experimental.h, with usage documented in comments (these keep changing frequently so I don't wanna "formally" document them here just yet).
misa is a single, dependency-free binary with two file-based subcommands. It operates on single files only (there's no directory or pipe support, so tar first if you need those).
misa compress FILE # -> FILE.misa77
misa decompress FILE.misa77 # -> FILE
misa compress takes -l N / --level N to pick the compression level (default is 1). Everywhere, -o PATH sets the output path and -f overwrites without asking.
misa compress -l 0 enwik8 # enwik8 -> enwik8.misa77
misa decompress enwik8.misa77 -f # back to enwik8
The underlying stream formats (used by the library functions) and the container format for .misa77 files (produced by the CLI) can be found in docs/.
Note: misa77 has evolved out of a less polished endeavour to learn performance engineering, and its history can be found in this archived repository.
Inspiration has been taken from:
Lastly, the following models helped a lot with orchestrating experiments, scripting, tooling, and building the CLI. Without their assistance, development would have been far slower, and I would likely not have explored all the paths that I did end up exploring (some of which were productive and some of which weren't).
MIT (see LICENSE).
721 followers · starred Jul 2026
122 followers · starred Jul 2026
199 followers · starred Jul 2026
88 followers · starred Jul 2026
Ridiculously fast decompression at good ratios. misa77 is 1.5-3x faster than LZ4 for decompression on x86 and ARM (with better ratios!).
C++
172
13 commits
updated Aug 10, 2026
misa77 is an LZ-based codec that targets the write-once, read-many niche. In particular, it aims to satisfy the following criteria:
Slow compression is the obvious tradeoff that one makes to achieve the above.
misa77 has six compression effort levels as of v0.6.0. For most shapes of data, encode time increases and ratio decreases with increasing level, but decompression throughput is not similarly monotonic. In general, level 1 offers the fastest decode throughput. More information about effort levels can be found here.
There are two decompressor modes:
Note: As of now, level 4 doesn't have a safe decompressor. It will be added soon.
Detailed results are listed ahead, but here's a terse summary:
Let's first see some cross-platform results for the Silesia Corpus.
Note:
((compressed size)/(original)) * 100 (so lower is better).Details:
performance.| Compressor name | Compression | Decompress. | Ratio | Filename |
|---|---|---|---|---|
| misa77 0.6.0 --1 | 232 MB/s | 3846 MB/s | 46.74 | silesia.tar |
| misa77 0.6.0 -0 | 170 MB/s | 4593 MB/s | 44.60 | silesia.tar |
| misa77 0.6.0 -1 | 54.2 MB/s | 5376 MB/s | 42.64 | silesia.tar |
| misa77 0.6.0 -2 | 41.5 MB/s | 4689 MB/s | 40.33 | silesia.tar |
| misa77 0.6.0 -3 | 10.7 MB/s | 4635 MB/s | 37.76 | silesia.tar |
| misa77 0.6.0 -4 | 6.97 MB/s | 4366 MB/s | 35.51 | silesia.tar |
| lz4 1.10.0 | 371 MB/s | 2514 MB/s | 47.59 | silesia.tar |
| lz4hc 1.10.0 -9 | 22.0 MB/s | 2457 MB/s | 36.75 | silesia.tar |
| lz4hc 1.10.0 -12 | 7.31 MB/s | 2536 MB/s | 36.45 | silesia.tar |
| lzsse4fast 2019-04-18 | 187 MB/s | 2540 MB/s | 45.26 | silesia.tar |
| lzsse8fast 2019-04-18 | 183 MB/s | 2671 MB/s | 44.80 | silesia.tar |
| zxc 0.13.1 -3 | 114 MB/s | 2840 MB/s | 45.46 | silesia.tar |
| zxc 0.13.1 -4 | 80.6 MB/s | 2731 MB/s | 42.63 | silesia.tar |
| zxc 0.13.1 -5 | 48.2 MB/s | 2597 MB/s | 40.25 | silesia.tar |
| zxc 0.13.1 -7 | 4.26 MB/s | 1642 MB/s | 33.00 | silesia.tar |
| zstd 1.5.7 -1 | 297 MB/s | 903 MB/s | 34.54 | silesia.tar |
| lzav 5.16 -2 | 62.6 MB/s | 1675 MB/s | 34.85 | silesia.tar |
| snappy 1.2.2 | 375 MB/s | 858 MB/s | 47.89 | silesia.tar |
Details:
| Compressor name | Compression | Decompress. | Ratio | Filename |
|---|---|---|---|---|
| misa77 0.6.0 --1 | 541 MB/s | 9739 MB/s | 46.74 | silesia.tar |
| misa77 0.6.0 -0 | 385 MB/s | 11777 MB/s | 44.60 | silesia.tar |
| misa77 0.6.0 -1 | 135 MB/s | 12638 MB/s | 42.64 | silesia.tar |
| misa77 0.6.0 -2 | 103 MB/s | 10868 MB/s | 40.33 | silesia.tar |
| misa77 0.6.0 -3 | 19.5 MB/s | 10280 MB/s | 37.76 | silesia.tar |
| misa77 0.6.0 -4 | 13.5 MB/s | 9925 MB/s | 35.51 | silesia.tar |
| lz4 1.10.0 | 882 MB/s | 5195 MB/s | 47.59 | silesia.tar |
| lz4hc 1.10.0 -9 | 53.0 MB/s | 4899 MB/s | 36.74 | silesia.tar |
| lz4hc 1.10.0 -12 | 17.0 MB/s | 4887 MB/s | 36.45 | silesia.tar |
| zxc 0.13.1 -3 | 278 MB/s | 8022 MB/s | 45.77 | silesia.tar |
| zxc 0.13.1 -4 | 193 MB/s | 7642 MB/s | 43.20 | silesia.tar |
| zxc 0.13.1 -5 | 114 MB/s | 7162 MB/s | 40.30 | silesia.tar |
| zstd 1.5.7 -1 | 722 MB/s | 1615 MB/s | 34.54 | silesia.tar |
| lzav 5.16 -2 | 185 MB/s | 4243 MB/s | 34.85 | silesia.tar |
| snappy 1.2.2 | 967 MB/s | 3439 MB/s | 47.91 | silesia.tar |
As misa77's performance is quite "spiky" (depending on the shape of the data being compressed), a file-level breakdown for the silesia corpus yields some interesting insights into its performance.
Note:
At level 1, misa77 decodes faster than lz4 on all 12 files (some by huge margins).

On the compressible files, misa77 sits on the decode-throughput/ratio Pareto frontier: it decodes fastest while ~matching or beating the ratio of the other fast-LZ codecs. (x-ray and sao are exceptions as most compressors have a ratio near 1, and their decode essentially devolves to a memcpy).
To spot misa77 in these graphs, just look for the circles near the top :)

Levels are ordered by compression effort. For most shapes of data, encode time increases and ratio decreases with increasing level, but decompression throughput is not similarly monotonic.
| Level | Description | Ratio | Encode vs L1 | Decode vs L1 | Encoder memory | Format |
|---|---|---|---|---|---|---|
| -1 | fastest compression (not recommended as slow to decode) | 46.74 | 4.0-4.3x | 72-77% | 1 MB | light |
| 0 | fast compression, lz4-class ratio | 44.60 | 2.9-3.1x | 85-93% | 1 MB | light |
| 1 | default, fastest decode | 42.64 | 1x | 100% | 3 MB | light |
| 2 | better ratio, still cheap to encode | 40.33 | 0.76-0.77x | 86-87% | 3 MB | light |
| 3 | best ratio in the light format | 37.76 | 0.14-0.20x | 81-86% | 29 MB | light |
| 4 | best ratio overall, prefer on inputs above ~1 MB | 35.51 | 0.10-0.13x | 79-81% | 176 MB | heavy |
Ratio is measured on silesia.tar in the Intel run.Encode/Decode vs L1 columns are relative to level 1, given as the range spanned by the Intel and M3 runs.Encoder memory is the compressor's own working state (disjoint from the caller's input and output buffers). Decompression needs no working memory at all.docs/format.md) and have a safe decoder. Level 4 emits the heavy format, which does not have one yet.For the library:
For the CLI:
misa CLI needs POSIX (Linux, macOS).Note: On x86-64, AVX2/SSE2 are selected at runtime. ARM has a NEON path.
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
This produces the misa CLI at build/misa. For a binary tuned to the exact machine you'll run it on, add -DMISA77_MARCH=native (I recommend this). To run the round-trip test:
ctest --test-dir build
The build produces a static library (CMake target misa77) with a small C++ API in misa77/misa77.h. The easiest integration is a git submodule (or CMake FetchContent) plus:
add_subdirectory(misa77)
target_link_libraries(your_app PRIVATE misa77)
Sample usage:
#include <misa77/misa77.h>
#include <vector>
// compress (pick a level with misa77::config(N) with N in [-1, 4], default is 1), returns 0 on failure
misa77::config cfg;
std::vector<uint8_t> compressed(misa77::compress_bound(input_size, cfg));
uint64_t csize = misa77::compress(input, input_size, compressed.data(), compressed.size(), cfg);
compressed.resize(csize);
// decompress, returns original_size on success
uint64_t original_size = misa77::decompressed_size(compressed.data());
std::vector<uint8_t> output(misa77::decompressed_buffer_bound(original_size));
// decompress uses the unsafe decompressor by default, pass dconfig(true) to use the safe decompressor
uint64_t written = misa77::decompress(compressed.data(), csize, output.data(), output.size(), misa77::dconfig(true));
Three things to keep in mind:
compress_bound / decompressed_buffer_bound, passing compress_bound the same config you compress with (the bound depends on the level's format).misa77::dconfig(true) to misa77::decompress if you want the decompressor to exit gracefully on invalid input.decompress with dconfig(true) returns 0 for them (the unsafe path decodes them fine).The experimental modes are declared in misa77/experimental.h, with usage documented in comments (these keep changing frequently so I don't wanna "formally" document them here just yet).
misa is a single, dependency-free binary with two file-based subcommands. It operates on single files only (there's no directory or pipe support, so tar first if you need those).
misa compress FILE # -> FILE.misa77
misa decompress FILE.misa77 # -> FILE
misa compress takes -l N / --level N to pick the compression level (default is 1). Everywhere, -o PATH sets the output path and -f overwrites without asking.
misa compress -l 0 enwik8 # enwik8 -> enwik8.misa77
misa decompress enwik8.misa77 -f # back to enwik8
The underlying stream formats (used by the library functions) and the container format for .misa77 files (produced by the CLI) can be found in docs/.
Note: misa77 has evolved out of a less polished endeavour to learn performance engineering, and its history can be found in this archived repository.
Inspiration has been taken from:
Lastly, the following models helped a lot with orchestrating experiments, scripting, tooling, and building the CLI. Without their assistance, development would have been far slower, and I would likely not have explored all the paths that I did end up exploring (some of which were productive and some of which weren't).
MIT (see LICENSE).
721 followers · starred Jul 2026
122 followers · starred Jul 2026
199 followers · starred Jul 2026
88 followers · starred Jul 2026