bench_buffers.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 <boost/beast/core/buffers_range.hpp>
  10. #include <boost/beast/core/flat_buffer.hpp>
  11. #include <boost/beast/core/multi_buffer.hpp>
  12. #include <boost/beast/core/read_size.hpp>
  13. #include <boost/beast/core/string.hpp>
  14. #include <boost/beast/_experimental/unit_test/suite.hpp>
  15. #include <boost/asio/streambuf.hpp>
  16. #include <algorithm>
  17. #include <chrono>
  18. #include <cstdlib>
  19. #include <iomanip>
  20. #include <utility>
  21. #include <vector>
  22. namespace boost {
  23. namespace beast {
  24. class buffers_test : public beast::unit_test::suite
  25. {
  26. public:
  27. using size_type = std::uint64_t;
  28. class timer
  29. {
  30. using clock_type =
  31. std::chrono::system_clock;
  32. clock_type::time_point when_;
  33. public:
  34. using duration =
  35. clock_type::duration;
  36. timer()
  37. : when_(clock_type::now())
  38. {
  39. }
  40. duration
  41. elapsed() const
  42. {
  43. return clock_type::now() - when_;
  44. }
  45. };
  46. inline
  47. size_type
  48. throughput(std::chrono::duration<
  49. double> const& elapsed, size_type items)
  50. {
  51. using namespace std::chrono;
  52. return static_cast<size_type>(
  53. 1 / (elapsed/items).count());
  54. }
  55. template<class MutableBufferSequence>
  56. static
  57. std::size_t
  58. fill(MutableBufferSequence const& buffers)
  59. {
  60. std::size_t n = 0;
  61. for(auto b : beast::buffers_range_ref(buffers))
  62. {
  63. std::fill(
  64. static_cast<char*>(b.data()),
  65. static_cast<char*>(b.data()) +
  66. b.size(), '\0');
  67. n += b.size();
  68. }
  69. return n;
  70. }
  71. template<class DynamicBuffer>
  72. size_type
  73. do_prepares(std::size_t repeat,
  74. std::size_t count, std::size_t size)
  75. {
  76. timer t;
  77. size_type total = 0;
  78. for(auto i = repeat; i--;)
  79. {
  80. DynamicBuffer b;
  81. for(auto j = count; j--;)
  82. {
  83. auto const n = fill(b.prepare(size));
  84. b.commit(n);
  85. total += n;
  86. }
  87. }
  88. return throughput(t.elapsed(), total);
  89. }
  90. template<class DynamicBuffer>
  91. size_type
  92. do_hints(std::size_t repeat,
  93. std::size_t count, std::size_t size)
  94. {
  95. timer t;
  96. size_type total = 0;
  97. for(auto i = repeat; i--;)
  98. {
  99. DynamicBuffer b;
  100. for(auto j = count; j--;)
  101. {
  102. for(auto remain = size; remain;)
  103. {
  104. auto const n = fill(b.prepare(
  105. read_size(b, remain)));
  106. b.commit(n);
  107. remain -= n;
  108. total += n;
  109. }
  110. }
  111. }
  112. return throughput(t.elapsed(), total);
  113. }
  114. template<class DynamicBuffer>
  115. size_type
  116. do_random(std::size_t repeat,
  117. std::size_t count, std::size_t size)
  118. {
  119. timer t;
  120. size_type total = 0;
  121. for(auto i = repeat; i--;)
  122. {
  123. DynamicBuffer b;
  124. for(auto j = count; j--;)
  125. {
  126. auto const n = fill(b.prepare(
  127. 1 + (rand()%(2*size))));
  128. b.commit(n);
  129. total += n;
  130. }
  131. }
  132. return throughput(t.elapsed(), total);
  133. }
  134. static
  135. inline
  136. void
  137. do_trials_1(bool)
  138. {
  139. }
  140. template<class F0, class... FN>
  141. void
  142. do_trials_1(bool print, F0&& f, FN... fn)
  143. {
  144. timer t;
  145. using namespace std::chrono;
  146. static size_type constexpr den = 1024 * 1024;
  147. if(print)
  148. {
  149. log << std::right << std::setw(10) <<
  150. ((f() + (den / 2)) / den) << " MB/s";
  151. log.flush();
  152. }
  153. else
  154. {
  155. f();
  156. }
  157. do_trials_1(print, fn...);
  158. }
  159. template<class F0, class... FN>
  160. void
  161. do_trials(string_view name,
  162. std::size_t trials, F0&& f0, FN... fn)
  163. {
  164. using namespace std::chrono;
  165. // warm-up
  166. do_trials_1(false, f0, fn...);
  167. do_trials_1(false, f0, fn...);
  168. while(trials--)
  169. {
  170. timer t;
  171. log << std::left << std::setw(24) << name << ":";
  172. log.flush();
  173. do_trials_1(true, f0, fn...);
  174. log << " " <<
  175. duration_cast<milliseconds>(t.elapsed()).count() << "ms";
  176. log << std::endl;
  177. }
  178. }
  179. void
  180. run() override
  181. {
  182. static std::size_t constexpr trials = 1;
  183. static std::size_t constexpr repeat = 250;
  184. std::vector<std::pair<std::size_t, std::size_t>> params;
  185. params.emplace_back(1024, 1024);
  186. params.emplace_back(512, 4096);
  187. params.emplace_back(256, 32768);
  188. log << std::endl;
  189. for(auto const& param : params)
  190. {
  191. auto const count = param.first;
  192. auto const size = param.second;
  193. auto const s = std::string("count=") + std::to_string(count) +
  194. ", size=" + std::to_string(size);
  195. log << std::left << std::setw(24) << s << " " <<
  196. std::right << std::setw(15) << "prepare" <<
  197. std::right << std::setw(15) << "with hint" <<
  198. std::right << std::setw(15) << "random" <<
  199. std::endl;
  200. do_trials("multi_buffer", trials,
  201. [&](){ return do_prepares<multi_buffer>(repeat, count, size); }
  202. ,[&](){ return do_hints <multi_buffer>(repeat, count, size); }
  203. ,[&](){ return do_random <multi_buffer>(repeat, count, size); }
  204. );
  205. do_trials("flat_buffer", trials,
  206. [&](){ return do_prepares<flat_buffer>(repeat, count, size); }
  207. ,[&](){ return do_hints <flat_buffer>(repeat, count, size); }
  208. ,[&](){ return do_random <flat_buffer>(repeat, count, size); }
  209. );
  210. do_trials("net::streambuf", trials,
  211. [&](){ return do_prepares<net::streambuf>(repeat, count, size); }
  212. ,[&](){ return do_hints <net::streambuf>(repeat, count, size); }
  213. ,[&](){ return do_random <net::streambuf>(repeat, count, size); }
  214. );
  215. log << std::endl;
  216. }
  217. pass();
  218. }
  219. };
  220. BEAST_DEFINE_TESTSUITE(beast,benchmarks,buffers);
  221. } // beast
  222. } // boost