2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
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>
19 #include "zlib-1.2.11/zlib.h"
25 class inflate_stream_test : public beast::unit_test::suite
28 // Lots of repeats, limited char range
31 corpus1(std::size_t n)
33 static std::string const alphabet{
34 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
39 std::uniform_int_distribution<std::size_t> d0{
40 0, alphabet.size() - 1};
41 std::uniform_int_distribution<std::size_t> d1{
45 auto const rep = d1(g);
46 auto const ch = alphabet[d0(g)];
47 s.insert(s.end(), rep, ch);
56 corpus2(std::size_t n)
61 std::uniform_int_distribution<std::uint32_t> d0{0, 255};
63 s.push_back(static_cast<char>(d0(g)));
69 compress(string_view const& in)
73 memset(&zs, 0, sizeof(zs));
74 result = deflateInit2(
76 Z_DEFAULT_COMPRESSION,
82 throw std::logic_error("deflateInit2 failed");
83 zs.next_in = (Bytef*)in.data();
84 zs.avail_in = static_cast<uInt>(in.size());
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);
94 throw std::logic_error("deflate failed");
95 out.resize(zs.total_out);
101 doInflateBeast(string_view const& in)
107 zs.avail_in = in.size();
108 out.resize(in.size());
109 zs.next_out = &out[0];
110 zs.avail_out = out.size();
114 is.write(zs, Flush::sync, ec);
116 throw std::logic_error("inflate_stream failed");
119 out.resize(2 * zs.total_out);
120 zs.next_out = &out[zs.total_out];
121 zs.avail_out = out.size() - zs.total_out;
123 out.resize(zs.total_out);
128 doInflateZLib(string_view const& in)
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(in.size());
138 zs.next_out = (Bytef*)&out[0];
139 zs.avail_out = static_cast<uInt>(out.size());
142 result = inflate(&zs, Z_SYNC_FLUSH);
143 if( result == Z_NEED_DICT ||
144 result == Z_DATA_ERROR ||
145 result == Z_MEM_ERROR)
147 throw std::logic_error("inflate failed");
151 if(result == Z_STREAM_END)
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);
158 out.resize(zs.total_out);
168 std::size_t constexpr trials = 3;
169 std::uint64_t constexpr scale = 16;
170 auto const c1 = corpus1(size);
171 auto const c2 = corpus2(size * scale);
172 auto const in1 = compress(c1);
173 auto const in2 = compress(c2);
175 std::left << std::setw(10) << (std::to_string(size) + "B") <<
176 std::right << std::setw(12) << "Beast" << " " <<
177 std::right << std::setw(12) << "ZLib" <<
179 for(std::size_t i = 0; i < trials; ++i)
182 log << std::left << std::setw(10) << "corpus1";
184 for(std::size_t j = 0; j < repeat; ++j)
185 out = doInflateBeast(in1);
186 BEAST_EXPECT(out == c1);
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(in1);
192 BEAST_EXPECT(out == c1);
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) << "%";
200 for(std::size_t i = 0; i < trials; ++i)
203 log << std::left << std::setw(10) << "corpus2";
205 for(std::size_t j = 0; j < repeat; ++j)
206 out = doInflateBeast(in2);
207 BEAST_EXPECT(out == c2);
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(in2);
213 BEAST_EXPECT(out == c2);
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) << "%";
227 doCorpus( 1 * 1024 * 1024, 64);
228 doCorpus( 4 * 1024 * 1024, 16);
229 doCorpus( 16 * 1024 * 1024, 8);
240 BEAST_DEFINE_TESTSUITE(beast,zlib,inflate_stream);