bench_parser.cpp 8.1 KB

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