summaryrefslogtreecommitdiff
path: root/neozip/test/benchmarks/benchmark_inflate.cc
blob: ac6ef7229f94c330a7dd94b14d5b74b5ea53a7db (plain)
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);