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