Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compare our and stock zlib compression levels in README #291

Merged
merged 1 commit into from
Feb 4, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions libz-rs-sys/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ This crate is a C API for [zlib-rs](https://docs.rs/zlib-rs/latest/zlib_rs/). Th
From a rust perspective, this API is not very ergonomic. Use the [`flate2`](https://crates.io/crates/flate2) crate for a more
ergonomic rust interface to zlib.

# Features
## Features

**`custom-prefix`**

Expand All @@ -29,13 +29,13 @@ Pick the default allocator implementation that is used if no `zalloc` and `zfree
- `c-allocator`: use `malloc`/`free` for the implementation of `zalloc` and `zfree`
- `rust-allocator`: the rust global allocator for the implementation of `zalloc` and `zfree`

The `rust-allocator` is the default when this crate is used as a rust dependency, and slightly more efficient because alignment is handled by the allocator. When building a dynamic library, it may make sense to use `c-allocator` instead.
The `rust-allocator` is the default when this crate is used as a rust dependency, and slightly more efficient because alignment is handled by the allocator. When building a dynamic library, it may make sense to use `c-allocator` instead.

**`std`**

Assume that `std` is available. When this feature is turned off, this crate is compatible with `#![no_std]`.

# Example
## Example

This example compresses ("deflates") the string `"Hello, World!"` and then decompresses
("inflates") it again.
Expand Down Expand Up @@ -88,3 +88,39 @@ let inflated = &output[..strm.total_out as usize];
assert_eq!(inflated, input.as_bytes())
```

## Compression Levels

The zlib library supports compression levels 0 up to and including 9. The level indicates a tradeoff between time spent on the compression versus the compression ratio, the factor by which the input is reduced in size:

- level 0: no compression at all
- level 1: fastest compression
- level 6: default (a good tradeoff between speed and compression ratio)
- level 9: best compression

Beyond this intuition, the exact behavior of the compression levels is not specified. The implementation of `zlib-rs` follows the implementation of [`zlig-ng`](https://github.com/zlib-ng/zlib-ng), and deviates from the one in stock zlib.

In particular, our compression level 1 is extremely fast, but also just does not compress that well. On the `silesia-small.tar` input file, we see these output sizes:

| implementation | compression level | output size (mb) |
| --- | --- | --- |
| - | 0 | `15.74` |
| stock | 1 | ` 7.05` |
| rs | 1 | ` 8.52` |
| rs | 2 | ` 6.90` |
| rs | 4 | ` 6.55` |

But, `zlib-rs` is much faster than stock zlib. In our benchmarks, it is only at level 4 that we spend roughly as much time as stock zlib on level 1:

| implementation | compression level | wall time (ms) |
| --- | --- | --- |
| stock | 1 | 185 |
| rs | 2 | 139 |
| rs | 4 | 181 |

In our example, the main options are:

- level 1: worse compression, but much faster
- level 2: equivalent compression, but significantly faster
- level 4: better compression, at the same speed

In summary, when you upgrade from stock zlib, we recommend that you benchmark on your data and target platform, and pick the right compression level for your use case.