]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/test/bench/parser/bench_parser.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / beast / test / bench / parser / bench_parser.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 "nodejs_parser.hpp"
11
12 #include "test/beast/http/message_fuzz.hpp"
13
14 #include <boost/beast/http.hpp>
15 #include <boost/beast/core/buffer_traits.hpp>
16 #include <boost/beast/core/buffers_suffix.hpp>
17 #include <boost/beast/core/buffers_to_string.hpp>
18 #include <boost/beast/core/ostream.hpp>
19 #include <boost/beast/core/flat_buffer.hpp>
20 #include <boost/beast/core/multi_buffer.hpp>
21 #include <boost/beast/_experimental/unit_test/suite.hpp>
22 #include <chrono>
23 #include <iostream>
24 #include <vector>
25
26 namespace boost {
27 namespace beast {
28 namespace http {
29
30 class parser_test : public beast::unit_test::suite
31 {
32 public:
33 static std::size_t constexpr N = 2000;
34
35 //using corpus = std::vector<multi_buffer>;
36 using corpus = std::vector<flat_buffer>;
37
38 corpus creq_;
39 corpus cres_;
40 std::size_t size_ = 0;
41
42 corpus
43 build_corpus(std::size_t n, std::true_type)
44 {
45 corpus v;
46 v.resize(n);
47 message_fuzz mg;
48 for(std::size_t i = 0; i < n; ++i)
49 {
50 mg.request(v[i]);
51 size_ += v[i].size();
52 BEAST_EXPECT(v[i].size() > 0);
53 }
54 return v;
55 }
56
57 corpus
58 build_corpus(std::size_t n, std::false_type)
59 {
60 corpus v;
61 v.resize(n);
62 message_fuzz mg;
63 for(std::size_t i = 0; i < n; ++i)
64 {
65 mg.response(v[i]);
66 size_ += v[i].size();
67 BEAST_EXPECT(v[i].size() > 0);
68 }
69 return v;
70 }
71
72 template<class ConstBufferSequence,
73 bool isRequest>
74 static
75 std::size_t
76 feed(ConstBufferSequence const& buffers,
77 basic_parser<isRequest>& parser,
78 error_code& ec)
79 {
80 beast::buffers_suffix<
81 ConstBufferSequence> cb{buffers};
82 std::size_t used = 0;
83 for(;;)
84 {
85 auto const n =
86 parser.put(cb, ec);
87 if(ec)
88 return 0;
89 if(n == 0)
90 break;
91 cb.consume(n);
92 used += n;
93 if(parser.is_done())
94 break;
95 if(buffer_bytes(cb) == 0)
96 break;
97 }
98 return used;
99 }
100
101 template<class Parser>
102 void
103 testParser1(std::size_t repeat, corpus const& v)
104 {
105 while(repeat--)
106 for(auto const& b : v)
107 {
108 Parser p;
109 error_code ec;
110 p.write(b.data(), ec);
111 if(! BEAST_EXPECTS(! ec, ec.message()))
112 log << buffers_to_string(b.data()) << std::endl;
113 }
114 }
115
116 template<class Parser>
117 void
118 testParser2(std::size_t repeat, corpus const& v)
119 {
120 while(repeat--)
121 for(auto const& b : v)
122 {
123 Parser p;
124 p.header_limit((std::numeric_limits<std::uint32_t>::max)());
125 error_code ec;
126 feed(b.data(), p, ec);
127 if(! BEAST_EXPECTS(! ec, ec.message()))
128 log << buffers_to_string(b.data()) << std::endl;
129 }
130 }
131
132 template<class Function>
133 void
134 timedTest(std::size_t repeat, std::string const& name, Function&& f)
135 {
136 using namespace std::chrono;
137 using clock_type = std::chrono::high_resolution_clock;
138 log << name << std::endl;
139 for(std::size_t trial = 1; trial <= repeat; ++trial)
140 {
141 auto const t0 = clock_type::now();
142 f();
143 auto const elapsed = clock_type::now() - t0;
144 log <<
145 "Trial " << trial << ": " <<
146 duration_cast<milliseconds>(elapsed).count() << " ms" << std::endl;
147 }
148 }
149
150 template<bool isRequest>
151 struct null_parser :
152 basic_parser<isRequest>
153 {
154 void
155 on_request_impl(
156 verb, string_view, string_view,
157 int, error_code&) override
158 {
159 }
160
161 void
162 on_response_impl(
163 int, string_view, int,
164 error_code&) override
165 {
166 }
167
168 void
169 on_field_impl(
170 field, string_view, string_view,
171 error_code&) override
172 {
173 }
174
175 void
176 on_header_impl(error_code&) override
177 {
178 }
179
180 void
181 on_body_init_impl(
182 boost::optional<std::uint64_t> const&,
183 error_code&) override
184 {
185 }
186
187 std::size_t
188 on_body_impl(
189 string_view,
190 error_code&) override
191 {
192 return 0;
193 }
194
195 void
196 on_chunk_header_impl(
197 std::uint64_t,
198 string_view,
199 error_code&) override
200 {
201 }
202
203 std::size_t
204 on_chunk_body_impl(
205 std::uint64_t,
206 string_view,
207 error_code&) override
208 {
209 return 0;
210 }
211
212 void
213 on_finish_impl(error_code&) override
214 {
215 }
216 };
217
218 template<bool isRequest, class Body, class Fields>
219 struct bench_parser : basic_parser<isRequest>
220 {
221 using mutable_buffers_type =
222 net::mutable_buffer;
223
224 void
225 on_request_impl(verb, string_view,
226 string_view, int, error_code&) override
227 {
228 }
229
230 void
231 on_response_impl(int,
232 string_view, int, error_code&) override
233 {
234 }
235
236 void
237 on_field_impl(field,
238 string_view, string_view, error_code&) override
239 {
240 }
241
242 void
243 on_header_impl(error_code&) override
244 {
245 }
246
247 void
248 on_body_init_impl(
249 boost::optional<std::uint64_t> const&,
250 error_code&) override
251 {
252 }
253
254 std::size_t
255 on_body_impl(
256 string_view s, error_code&) override
257 {
258 return s.size();
259 }
260
261 void
262 on_chunk_header_impl(std::uint64_t,
263 string_view, error_code&) override
264 {
265 }
266
267 std::size_t
268 on_chunk_body_impl(std::uint64_t,
269 string_view s, error_code&) override
270 {
271 return s.size();
272 }
273
274 void
275 on_finish_impl(error_code&) override
276 {
277 }
278 };
279
280 void
281 testSpeed()
282 {
283 static std::size_t constexpr Trials = 5;
284 static std::size_t constexpr Repeat = 500;
285
286 creq_ = build_corpus(N/2, std::true_type{});
287 cres_ = build_corpus(N/2, std::false_type{});
288
289 log << "sizeof(request parser) == " <<
290 sizeof(null_parser<true>) << '\n';
291
292 log << "sizeof(response parser) == " <<
293 sizeof(null_parser<false>)<< '\n';
294
295 testcase << "Parser speed test, " <<
296 ((Repeat * size_ + 512) / 1024) << "KB in " <<
297 (Repeat * (creq_.size() + cres_.size())) << " messages";
298
299 #if 0
300 timedTest(Trials, "http::parser",
301 [&]
302 {
303 testParser2<request_parser<dynamic_body>>(Repeat, creq_);
304 testParser2<response_parser<dynamic_body>>(Repeat, cres_);
305 });
306 #endif
307 #if 1
308 timedTest(Trials, "http::basic_parser",
309 [&]
310 {
311 testParser2<bench_parser<
312 true, dynamic_body, fields> >(
313 Repeat, creq_);
314 testParser2<bench_parser<
315 false, dynamic_body, fields>>(
316 Repeat, cres_);
317 });
318 #if 1
319 timedTest(Trials, "nodejs_parser",
320 [&]
321 {
322 testParser1<nodejs_parser<
323 true, dynamic_body, fields>>(
324 Repeat, creq_);
325 testParser1<nodejs_parser<
326 false, dynamic_body, fields>>(
327 Repeat, cres_);
328 });
329 #endif
330 #endif
331 pass();
332 }
333
334 void run() override
335 {
336 pass();
337 testSpeed();
338 }
339 };
340
341 BEAST_DEFINE_TESTSUITE(beast,benchmarks,parser);
342
343 } // http
344 } // beast
345 } // boost
346