1//
2// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7// Official repository: https://github.com/boostorg/beast
8//
9
10#include <boost/beast/core/string.hpp>
11#include <boost/beast/zlib/inflate_stream.hpp>
12#include <boost/beast/test/throughput.hpp>
13#include <boost/beast/_experimental/unit_test/dstream.hpp>
14#include <boost/beast/_experimental/unit_test/suite.hpp>
15#include <iomanip>
16#include <random>
17#include <string>
18
19#include "zlib-1.2.12/zlib.h"
20
21namespace boost {
22namespace beast {
23namespace zlib {
24
25class inflate_stream_test : public beast::unit_test::suite
26{
27public:
28 // Lots of repeats, limited char range
29 static
30 std::string
31 corpus1(std::size_t n)
32 {
33 static std::string const alphabet{
34 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
35 };
36 std::string s;
37 s.reserve(res_arg: n + 5);
38 std::mt19937 g;
39 std::uniform_int_distribution<std::size_t> d0{
40 0, alphabet.size() - 1};
41 std::uniform_int_distribution<std::size_t> d1{
42 1, 5};
43 while(s.size() < n)
44 {
45 auto const rep = d1(g);
46 auto const ch = alphabet[d0(g)];
47 s.insert(s.end(), rep, ch);
48 }
49 s.resize(n: n);
50 return s;
51 }
52
53 // Random data
54 static
55 std::string
56 corpus2(std::size_t n)
57 {
58 std::string s;
59 s.reserve(res_arg: n);
60 std::mt19937 g;
61 std::uniform_int_distribution<std::uint32_t> d0{0, 255};
62 while(n--)
63 s.push_back(c: static_cast<char>(d0(g)));
64 return s;
65 }
66
67 static
68 std::string
69 compress(string_view const& in)
70 {
71 int result;
72 z_stream zs;
73 memset(&zs, 0, sizeof(zs));
74 result = deflateInit2(
75 &zs,
76 Z_DEFAULT_COMPRESSION,
77 Z_DEFLATED,
78 -15,
79 4,
80 Z_DEFAULT_STRATEGY);
81 if(result != Z_OK)
82 throw std::logic_error("deflateInit2 failed");
83 zs.next_in = (Bytef*)in.data();
84 zs.avail_in = static_cast<uInt>(in.size());
85 std::string out;
86 out.resize(deflateBound(&zs,
87 static_cast<uLong>(in.size())));
88 zs.next_in = (Bytef*)in.data();
89 zs.avail_in = static_cast<uInt>(in.size());
90 zs.next_out = (Bytef*)&out[0];
91 zs.avail_out = static_cast<uInt>(out.size());
92 result = deflate(&zs, Z_FULL_FLUSH);
93 if(result != Z_OK)
94 throw std::logic_error("deflate failed");
95 out.resize(zs.total_out);
96 deflateEnd(&zs);
97 return out;
98 }
99
100 std::string
101 doInflateBeast(string_view const& in)
102 {
103 z_params zs;
104 std::string out;
105 inflate_stream is;
106 zs.next_in = &in[0];
107 zs.avail_in = in.size();
108 out.resize(n: in.size());
109 zs.next_out = &out[0];
110 zs.avail_out = out.size();
111 for(;;)
112 {
113 error_code ec;
114 is.write(zs, flush: Flush::sync, ec);
115 if(ec)
116 throw std::logic_error("inflate_stream failed");
117 if(zs.avail_out > 0)
118 break;
119 out.resize(n: 2 * zs.total_out);
120 zs.next_out = &out[zs.total_out];
121 zs.avail_out = out.size() - zs.total_out;
122 }
123 out.resize(n: zs.total_out);
124 return out;
125 }
126
127 std::string
128 doInflateZLib(string_view const& in)
129 {
130 int result;
131 z_stream zs;
132 std::string out;
133 memset(&zs, 0, sizeof(zs));
134 result = inflateInit2(&zs, -15);
135 zs.next_in = (Bytef*)in.data();
136 zs.avail_in = static_cast<uInt>(in.size());
137 out.resize(n: in.size());
138 zs.next_out = (Bytef*)&out[0];
139 zs.avail_out = static_cast<uInt>(out.size());
140 for(;;)
141 {
142 result = inflate(&zs, Z_SYNC_FLUSH);
143 if( result == Z_NEED_DICT ||
144 result == Z_DATA_ERROR ||
145 result == Z_MEM_ERROR)
146 {
147 throw std::logic_error("inflate failed");
148 }
149 if(zs.avail_out > 0)
150 break;
151 if(result == Z_STREAM_END)
152 break;
153 out.resize(2 * zs.total_out);
154 zs.next_out = (Bytef*)&out[zs.total_out];
155 zs.avail_out = static_cast<uInt>(
156 out.size() - zs.total_out);
157 }
158 out.resize(zs.total_out);
159 inflateEnd(&zs);
160 return out;
161 }
162
163 void
164 doCorpus(
165 std::size_t size,
166 std::size_t repeat)
167 {
168 std::size_t constexpr trials = 3;
169 std::uint64_t constexpr scale = 16;
170 auto const c1 = corpus1(n: size);
171 auto const c2 = corpus2(n: size * scale);
172 auto const in1 = compress(c1);
173 auto const in2 = compress(c2);
174 log <<
175 std::left << std::setw(10) << (std::to_string(val: size) + "B") <<
176 std::right << std::setw(12) << "Beast" << " " <<
177 std::right << std::setw(12) << "ZLib" <<
178 std::endl;
179 for(std::size_t i = 0; i < trials; ++i)
180 {
181 test::timer t;
182 log << std::left << std::setw(10) << "corpus1";
183 std::string out;
184 for(std::size_t j = 0; j < repeat; ++j)
185 out = doInflateBeast(in: in1);
186 BEAST_EXPECT(out == c1);
187 auto const t1 =
188 test::throughput(t.elapsed(), size * repeat);
189 log << std::right << std::setw(12) << t1 << " B/s ";
190 for(std::size_t j = 0; j < repeat; ++j)
191 out = doInflateZLib(in: in1);
192 BEAST_EXPECT(out == c1);
193 auto const t2 =
194 test::throughput(t.elapsed(), size * repeat);
195 log << std::right << std::setw(12) << t2 << " B/s";
196 log << std::right << std::setw(12) <<
197 unsigned(double(t1)*100/t2-100) << "%";
198 log << std::endl;
199 }
200 for(std::size_t i = 0; i < trials; ++i)
201 {
202 test::timer t;
203 log << std::left << std::setw(10) << "corpus2";
204 std::string out;
205 for(std::size_t j = 0; j < repeat; ++j)
206 out = doInflateBeast(in: in2);
207 BEAST_EXPECT(out == c2);
208 auto const t1 =
209 test::throughput(t.elapsed(), size * scale * repeat);
210 log << std::right << std::setw(12) << t1 << " B/s ";
211 for(std::size_t j = 0; j < repeat; ++j)
212 out = doInflateZLib(in: in2);
213 BEAST_EXPECT(out == c2);
214 auto const t2 =
215 test::throughput(t.elapsed(), size * scale * repeat);
216 log << std::right << std::setw(12) << t2 << " B/s";
217 log << std::right << std::setw(12) <<
218 unsigned(double(t1)*100/t2-100) << "%";
219 log << std::endl;
220 }
221 log << std::endl;
222 }
223
224 void
225 doBench()
226 {
227 doCorpus( size: 1 * 1024 * 1024, repeat: 64);
228 doCorpus( size: 4 * 1024 * 1024, repeat: 16);
229 doCorpus( size: 16 * 1024 * 1024, repeat: 8);
230 }
231
232 void
233 run() override
234 {
235 doBench();
236 pass();
237 }
238};
239
240BEAST_DEFINE_TESTSUITE(beast,zlib,inflate_stream);
241
242} // zlib
243} // beast
244} // boost
245

source code of boost/libs/beast/test/bench/zlib/inflate_stream.cpp