1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
/* benchmark_inflate.cc -- benchmark inflate() without crc32/adler32
* Copyright (C) 2024-2025 Hans Kristian Rosbach
* 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 "test/compressible_data_p.h"
}
#define MAX_SIZE (1024 * 1024)
#define NUM_TESTS 6
class inflate_bench: public benchmark::Fixture {
private:
uint8_t *inbuff;
uint8_t *outbuff;
uint8_t *compressed_buff[NUM_TESTS];
z_uintmax_t compressed_sizes[NUM_TESTS];
uint32_t sizes[NUM_TESTS] = {1, 64, 1024, 16384, 128*1024, 1024*1024};
public:
void SetUp(::benchmark::State& state) {
int err;
outbuff = (uint8_t *)malloc(MAX_SIZE + 16);
if (outbuff == NULL) {
state.SkipWithError("malloc failed");
return;
}
// Initialize input buffer with highly compressible data, interspersed
// with small amounts of random data and 3-byte matches.
inbuff = gen_compressible_data(MAX_SIZE);
if (inbuff == NULL) {
free(outbuff);
outbuff = NULL;
state.SkipWithError("gen_compressible_data() failed");
return;
}
// Initialize Deflate state
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, Z_BEST_COMPRESSION, Z_DEFLATED, -15, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
if (err != Z_OK) {
state.SkipWithError("deflateInit2 did not return Z_OK");
return;
}
// Compress data into different buffers
for (int i = 0; i < NUM_TESTS; ++i) {
compressed_buff[i] = (uint8_t *)malloc(sizes[i] + 64);
if (compressed_buff[i] == NULL) {
state.SkipWithError("malloc failed");
return;
}
strm.avail_in = sizes[i]; // Size of the input buffer
strm.next_in = (z_const uint8_t *)inbuff; // Pointer to the input buffer
strm.next_out = compressed_buff[i]; // Pointer to the output buffer
strm.avail_out = sizes[i] + 64; // Maximum size of the output buffer
err = PREFIX(deflate)(&strm, Z_FINISH); // Perform compression
if (err != Z_STREAM_END ) {
state.SkipWithError("deflate did not return Z_STREAM_END");
PREFIX(deflateEnd)(&strm);
return;
}
compressed_sizes[i] = strm.total_out; // Total compressed size
err = PREFIX(deflateReset)(&strm); // Reset Deflate state
if (err != Z_OK) {
state.SkipWithError("deflateReset did not return Z_OK");
return;
}
}
err = PREFIX(deflateEnd)(&strm); // Clean up the deflate stream
if (err != Z_OK) {
state.SkipWithError("deflateEnd did not return Z_OK");
return;
}
}
void Bench(benchmark::State& state) {
int err;
int index = 0;
while (sizes[index] != (uint32_t)state.range(0)) ++index;
// Initialize the inflate stream
PREFIX3(stream) strm;
strm.zalloc = NULL;
strm.zfree = NULL;
strm.opaque = NULL;
strm.next_in = NULL;
strm.avail_in = 0;
err = PREFIX(inflateInit2)(&strm, -15); // Initialize the inflate state, no crc/adler
if (err != Z_OK) {
state.SkipWithError("inflateInit did not return Z_OK");
return;
}
for (auto _ : state) {
// Perform reset, avoids benchmarking inflateInit and inflateEnd
err = PREFIX(inflateReset)(&strm);
if (err != Z_OK) {
state.SkipWithError("inflateReset did not return Z_OK");
return;
}
strm.avail_in = (uint32_t)compressed_sizes[index]; // Size of the input
strm.next_in = compressed_buff[index]; // Pointer to the compressed data
strm.avail_out = MAX_SIZE; // Max size for output
strm.next_out = outbuff; // Output buffer
// Perform decompression
err = PREFIX(inflate)(&strm, Z_FINISH);
if (err != Z_STREAM_END) {
state.SkipWithError("inflate did not return Z_STREAM_END");
PREFIX(inflateEnd)(&strm);
return;
}
}
// Finalize the inflation process
err = PREFIX(inflateEnd)(&strm);
if (err != Z_OK) {
state.SkipWithError("inflateEnd did not return Z_OK");
return;
}
}
void TearDown(const ::benchmark::State&) {
free(inbuff);
free(outbuff);
for (int i = 0; i < NUM_TESTS; ++i) {
free(compressed_buff[i]);
}
}
};
#define BENCHMARK_INFLATE(name) \
BENCHMARK_DEFINE_F(inflate_bench, name)(benchmark::State& state) { \
Bench(state); \
} \
BENCHMARK_REGISTER_F(inflate_bench, name)->Arg(1)->Arg(64)->Arg(1024)->Arg(16<<10)->Arg(128<<10)->Arg(1024<<10);
BENCHMARK_INFLATE(inflate_nocrc);
|