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