]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
Add parameterized deflate benchmark
authorNathan Moinvaziri <nathan@nathanm.com>
Fri, 27 Feb 2026 00:10:11 +0000 (16:10 -0800)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Mon, 9 Mar 2026 22:56:37 +0000 (23:56 +0100)
Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
test/benchmarks/CMakeLists.txt
test/benchmarks/benchmark_deflate.cc [new file with mode: 0644]

index acd320d3c682719d94e28604ac6cd0bab47ab0e7..df6f5a7e69b26bebf30551e50e6d4867b6e564e4 100644 (file)
@@ -50,6 +50,7 @@ set(BENCH_INTERNAL_SRCS
     benchmark_compare256_rle.cc
     benchmark_crc32.cc
     benchmark_crc32_copy.cc
+    benchmark_deflate.cc
     benchmark_insert_string.cc
     benchmark_slidehash.cc
     )
diff --git a/test/benchmarks/benchmark_deflate.cc b/test/benchmarks/benchmark_deflate.cc
new file mode 100644 (file)
index 0000000..625ccd8
--- /dev/null
@@ -0,0 +1,147 @@
+/* benchmark_deflate.cc -- benchmark deflate() with various levels and raw mode
+ * Copyright (C) 2026 Nathan Moinvaziri
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <benchmark/benchmark.h>
+
+extern "C" {
+#  include "zbuild.h"
+#  include "zutil_p.h"
+#  if defined(ZLIB_COMPAT)
+#    include "zlib.h"
+#  else
+#    include "zlib-ng.h"
+#  endif
+#  include "compressible_data_p.h"
+}
+
+#define MAX_SIZE (1024 * 1024)
+
+/* Parameterized deflate benchmark: Args(size, level) */
+class deflate_bench: public benchmark::Fixture {
+private:
+    uint8_t *inbuff = nullptr;
+    uint8_t *outbuff = nullptr;
+    z_uintmax_t outbuff_size = 0;
+
+public:
+    void SetUp(::benchmark::State& state) {
+        outbuff_size = PREFIX(deflateBound)(NULL, MAX_SIZE);
+        outbuff = (uint8_t *)malloc(outbuff_size);
+        if (outbuff == NULL) {
+            state.SkipWithError("malloc failed");
+            return;
+        }
+
+        inbuff = gen_compressible_data(MAX_SIZE);
+        if (inbuff == NULL) {
+            free(outbuff);
+            outbuff = NULL;
+            state.SkipWithError("gen_compressible_data() failed");
+            return;
+        }
+    }
+
+    void Bench(benchmark::State& state, int window_bits, int strategy = Z_DEFAULT_STRATEGY) {
+        int err;
+        size_t size = (size_t)state.range(0);
+        int level = (int)state.range(1);
+
+        PREFIX3(stream) strm;
+        strm.zalloc = NULL;
+        strm.zfree = NULL;
+        strm.opaque = NULL;
+        strm.total_in = 0;
+        strm.total_out = 0;
+        strm.next_out = NULL;
+        strm.avail_out = 0;
+
+        err = PREFIX(deflateInit2)(&strm, level, Z_DEFLATED, window_bits, MAX_MEM_LEVEL, strategy);
+        if (err != Z_OK) {
+            state.SkipWithError("deflateInit2 did not return Z_OK");
+            return;
+        }
+
+        for (auto _ : state) {
+            err = PREFIX(deflateReset)(&strm);
+            if (err != Z_OK) {
+                state.SkipWithError("deflateReset did not return Z_OK");
+                PREFIX(deflateEnd)(&strm);
+                return;
+            }
+
+            strm.avail_in = (uint32_t)size;
+            strm.next_in = (z_const uint8_t *)inbuff;
+            strm.next_out = outbuff;
+            strm.avail_out = (uint32_t)outbuff_size;
+
+            err = PREFIX(deflate)(&strm, Z_FINISH);
+            if (err != Z_STREAM_END) {
+                state.SkipWithError("deflate did not return Z_STREAM_END");
+                PREFIX(deflateEnd)(&strm);
+                return;
+            }
+        }
+
+        err = PREFIX(deflateEnd)(&strm);
+        if (err != Z_OK) {
+            state.SkipWithError("deflateEnd did not return Z_OK");
+            return;
+        }
+    }
+
+    void TearDown(const ::benchmark::State&) {
+        free(inbuff);
+        free(outbuff);
+    }
+};
+
+#define BENCHMARK_DEFLATE_ARGS \
+    ->Args({1024, 1})->Args({1024, 3})->Args({1024, 6})->Args({1024, 9}) \
+    ->Args({16384, 1})->Args({16384, 3})->Args({16384, 6})->Args({16384, 9}) \
+    ->Args({131072, 1})->Args({131072, 3})->Args({131072, 6})->Args({131072, 9}) \
+    ->Args({1048576, 1})->Args({1048576, 3})->Args({1048576, 6})->Args({1048576, 9})
+
+/* Parameterized deflate with zlib wrapping (includes adler32 checksum) */
+BENCHMARK_DEFINE_F(deflate_bench, deflate_level)(benchmark::State& state) {
+    Bench(state, MAX_WBITS);
+}
+BENCHMARK_REGISTER_F(deflate_bench, deflate_level) BENCHMARK_DEFLATE_ARGS;
+
+/* Parameterized raw deflate without checksum */
+BENCHMARK_DEFINE_F(deflate_bench, deflate_nocrc)(benchmark::State& state) {
+    Bench(state, -MAX_WBITS);
+}
+BENCHMARK_REGISTER_F(deflate_bench, deflate_nocrc) BENCHMARK_DEFLATE_ARGS;
+
+/* Strategy benchmarks use fewer size/level combos to keep test count reasonable */
+#define BENCHMARK_DEFLATE_STRATEGY_ARGS \
+    ->Args({1024, 1})->Args({1024, 6})->Args({1024, 9}) \
+    ->Args({1048576, 1})->Args({1048576, 6})->Args({1048576, 9})
+
+/* Parameterized deflate with filtered strategy */
+BENCHMARK_DEFINE_F(deflate_bench, deflate_filtered)(benchmark::State& state) {
+    Bench(state, MAX_WBITS, Z_FILTERED);
+}
+BENCHMARK_REGISTER_F(deflate_bench, deflate_filtered) BENCHMARK_DEFLATE_STRATEGY_ARGS;
+
+/* Parameterized deflate with Huffman-only strategy */
+BENCHMARK_DEFINE_F(deflate_bench, deflate_huffman)(benchmark::State& state) {
+    Bench(state, MAX_WBITS, Z_HUFFMAN_ONLY);
+}
+BENCHMARK_REGISTER_F(deflate_bench, deflate_huffman) BENCHMARK_DEFLATE_STRATEGY_ARGS;
+
+/* Parameterized deflate with RLE strategy */
+BENCHMARK_DEFINE_F(deflate_bench, deflate_rle)(benchmark::State& state) {
+    Bench(state, MAX_WBITS, Z_RLE);
+}
+BENCHMARK_REGISTER_F(deflate_bench, deflate_rle) BENCHMARK_DEFLATE_STRATEGY_ARGS;
+
+/* Parameterized deflate with fixed Huffman codes */
+BENCHMARK_DEFINE_F(deflate_bench, deflate_fixed)(benchmark::State& state) {
+    Bench(state, MAX_WBITS, Z_FIXED);
+}
+BENCHMARK_REGISTER_F(deflate_bench, deflate_fixed) BENCHMARK_DEFLATE_STRATEGY_ARGS;