Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / beast / test / bench / zlib / inflate_stream.cpp
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.11/zlib.h"
20
21 namespace boost {
22 namespace beast {
23 namespace zlib {
24
25 class inflate_stream_test : public beast::unit_test::suite
26 {
27 public:
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(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);
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(n);
60         std::mt19937 g;
61         std::uniform_int_distribution<std::uint32_t> d0{0, 255};
62         while(n--)
63             s.push_back(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(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::sync, ec);
115             if(ec)
116                 throw std::logic_error("inflate_stream failed");
117             if(zs.avail_out > 0)
118                 break;
119             out.resize(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(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(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(size);
171         auto const c2 = corpus2(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(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(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(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(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(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(  1 * 1024 * 1024, 64);
228         doCorpus(  4 * 1024 * 1024, 16);
229         doCorpus( 16 * 1024 * 1024,  8);
230     }
231
232     void
233     run() override
234     {
235         doBench();
236         pass();
237     }
238 };
239
240 BEAST_DEFINE_TESTSUITE(beast,zlib,inflate_stream);
241
242 } // zlib
243 } // beast
244 } // boost