blob: 4af500c0c0505db01e1bafba14cddbf3a7fb83f9 [file] [log] [blame]
Brian Silvermanfad8f552018-08-04 23:36:19 -07001//////////////////////////////////////////////////////////////////////////////
2//
3// (C) Copyright Ion Gaztanaga 2013-2014. Distributed under the Boost
4// Software License, Version 1.0. (See accompanying file
5// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7// See http://www.boost.org/libs/container for documentation.
8//
9//////////////////////////////////////////////////////////////////////////////
10
11#ifndef BOOST_CONTAINER_BENCH_BENCH_SET_HPP
12#define BOOST_CONTAINER_BENCH_BENCH_SET_HPP
13
14#include <iostream>
15#include <boost/timer/timer.hpp>
16#include <algorithm> //sort
17#include <exception>
18#include <sstream>
19#include <iomanip>
20#include <boost/container/vector.hpp>
21#include <boost/container/string.hpp>
22
23using boost::timer::cpu_timer;
24using boost::timer::cpu_times;
25using boost::timer::nanosecond_type;
26
27static const std::size_t NElements = 1000;
28
29#ifdef NDEBUG
30static const std::size_t NIter = 250;
31#else
32static const std::size_t NIter = 25;
33#endif
34
35void compare_times(cpu_times time_numerator, cpu_times time_denominator){
36 std::cout << ((double)time_numerator.wall/(double)time_denominator.wall) << std::endl;
37 std::cout << "----------------------------------------------" << '\n' << std::endl;
38}
39
40template< class RandomIt >
41void random_shuffle( RandomIt first, RandomIt last )
42{
43 typedef typename boost::container::iterator_traits<RandomIt>::difference_type difference_type;
44 difference_type n = last - first;
45 for (difference_type i = n-1; i > 0; --i) {
46 difference_type j = std::rand() % (i+1);
47 if(j != i) {
48 boost::adl_move_swap(first[i], first[j]);
49 }
50 }
51}
52
53boost::container::vector<int> sorted_unique_range_int;
54boost::container::vector<int> sorted_range_int;
55boost::container::vector<int> random_unique_range_int;
56boost::container::vector<int> random_range_int;
57
58void fill_range_ints()
59{
60 //sorted_unique_range_int
61 sorted_unique_range_int.resize(NElements);
62 for(std::size_t i = 0, max = sorted_unique_range_int.size(); i != max; ++i){
63 sorted_unique_range_int[i] = static_cast<int>(i);
64 }
65 //sorted_range_int
66 sorted_range_int = sorted_unique_range_int;
67 sorted_range_int.insert(sorted_range_int.end(), sorted_unique_range_int.begin(), sorted_unique_range_int.end());
68 std::sort(sorted_range_int.begin(), sorted_range_int.end());
69
70 //random_range_int
71 std::srand(0);
72 random_range_int.assign(sorted_range_int.begin(), sorted_range_int.end());
73 ::random_shuffle(random_range_int.begin(), random_range_int.end());
74 //random_unique_range_int
75 std::srand(0);
76 random_unique_range_int.assign(sorted_unique_range_int.begin(), sorted_unique_range_int.end());
77 ::random_shuffle(random_unique_range_int.begin(), random_unique_range_int.end());
78}
79
80boost::container::vector<boost::container::string> sorted_unique_range_string;
81boost::container::vector<boost::container::string> sorted_range_string;
82boost::container::vector<boost::container::string> random_unique_range_string;
83boost::container::vector<boost::container::string> random_range_string;
84
85void fill_range_strings()
86{
87 boost::container::string model_s;
88 model_s.append(sizeof(boost::container::string), '*');
89
90 //sorted_unique_range_int
91 sorted_unique_range_string.resize(NElements);
92 std::stringstream sstr;
93
94 for(std::size_t i = 0, max = sorted_unique_range_string.size(); i != max; ++i){
95 sstr.str(std::string());
96 sstr << std::setfill('0') << std::setw(10) << i;
97 sorted_unique_range_string[i] = model_s;
98 const std::string &s = sstr.str();
99 sorted_unique_range_string[i].append(s.begin(), s.end());
100 }
101 //sorted_range_string
102 sorted_range_string = sorted_unique_range_string;
103 sorted_range_string.insert(sorted_range_string.end(), sorted_unique_range_string.begin(), sorted_unique_range_string.end());
104 std::sort(sorted_range_string.begin(), sorted_range_string.end());
105
106 //random_range_string
107 std::srand(0);
108 random_range_string.assign(sorted_range_string.begin(), sorted_range_string.end());
109 ::random_shuffle(random_range_string.begin(), random_range_string.end());
110 //random_unique_range_string
111 std::srand(0);
112 random_unique_range_string.assign(sorted_unique_range_string.begin(), sorted_unique_range_string.end());
113 ::random_shuffle(random_unique_range_string.begin(), random_unique_range_string.end());
114}
115
116template<class T>
117struct range_provider;
118
119template<>
120struct range_provider<int>
121{
122 typedef boost::container::vector<int> type;
123
124 static type &sorted_unique()
125 { return sorted_unique_range_int; }
126
127 static type &sorted()
128 { return sorted_range_int; }
129
130 static type &random_unique()
131 { return random_unique_range_int; }
132
133 static type &random()
134 { return random_range_int; }
135};
136
137template<>
138struct range_provider<boost::container::string>
139{
140 typedef boost::container::vector<boost::container::string> type;
141
142 static type &sorted_unique()
143 { return sorted_unique_range_string; }
144
145 static type &sorted()
146 { return sorted_range_string; }
147
148 static type &random_unique()
149 { return random_unique_range_string; }
150
151 static type &random()
152 { return random_range_string; }
153};
154
155template<typename C>
156cpu_times copy_destroy_time(boost::container::vector<typename C::value_type> &unique_range)
157{
158 cpu_timer copy_timer, assign_timer, destroy_timer;
159
160 cpu_timer total_time;
161
162 for(std::size_t i = 0; i != NIter; ++i){
163 {
164 C c(unique_range.begin(), unique_range.end());
165 total_time.resume();
166 copy_timer.resume();
167 C caux(c);
168 copy_timer.stop();
169 assign_timer.resume();
170 c = caux;
171 assign_timer.stop();
172 destroy_timer.resume();
173 }
174 destroy_timer.stop();
175 total_time.stop();
176 }
177 total_time.stop();
178
179 std::cout << " Copy sorted range " << boost::timer::format(copy_timer.elapsed(), boost::timer::default_places, "%ws\n");
180 std::cout << " Assign sorted range " << boost::timer::format(assign_timer.elapsed(), boost::timer::default_places, "%ws\n");
181 std::cout << " Destroy " << boost::timer::format(destroy_timer.elapsed(), boost::timer::default_places, "%ws\n");
182 std::cout << " Total time = " << boost::timer::format(total_time.elapsed(), boost::timer::default_places, "%ws\n") << std::endl;
183 return total_time.elapsed();
184}
185
186template<typename C>
187cpu_times construct_time( boost::container::vector<typename C::value_type> &unique_range
188 , boost::container::vector<typename C::value_type> &range
189 , const char *RangeType)
190{
191 cpu_timer sur_timer, sr_timer;
192
193 cpu_timer total_time;
194
195 for(std::size_t i = 0; i != NIter; ++i){
196 {
197 sur_timer.resume();
198 total_time.resume();
199 C c(unique_range.begin(), unique_range.end());
200 sur_timer.stop();
201 total_time.stop();
202 }
203 {
204 total_time.resume();
205 sr_timer.resume();
206 C c(range.begin(), range.end());
207 sr_timer.stop();
208 total_time.stop();
209 }
210 }
211
212 std::cout << " Construct " << RangeType << " unique_range " << boost::timer::format(sur_timer.elapsed(), boost::timer::default_places, "%ws\n");
213 std::cout << " Construct " << RangeType << " range " << boost::timer::format(sr_timer.elapsed(), boost::timer::default_places, "%ws\n");
214 std::cout << " Total time = " << boost::timer::format(total_time.elapsed(), boost::timer::default_places, "%ws\n") << std::endl;
215 return total_time.elapsed();
216}
217
218template<typename C>
219cpu_times insert_time( boost::container::vector<typename C::value_type> &unique_range
220 , boost::container::vector<typename C::value_type> &range
221 , const char *RangeType)
222{
223 cpu_timer ur_timer,r_timer;
224 ur_timer.stop();r_timer.stop();
225
226 cpu_timer total_time;
227 total_time.resume();
228
229 for(std::size_t i = 0; i != NIter; ++i){
230 {
231 total_time.resume();
232 ur_timer.resume();
233 C c;
234 c.insert(unique_range.begin(), unique_range.end());
235 ur_timer.stop();
236 total_time.stop();
237 }
238 {
239 total_time.resume();
240 r_timer.resume();
241 C c;
242 c.insert(range.begin(), range.end());
243 r_timer.stop();
244 total_time.stop();
245 }
246 }
247
248 std::cout << " Insert " << RangeType << " unique_range " << boost::timer::format(ur_timer.elapsed(), boost::timer::default_places, "%ws\n");
249 std::cout << " Insert " << RangeType << " range " << boost::timer::format(r_timer.elapsed(), boost::timer::default_places, "%ws\n");
250 std::cout << " Total time = " << boost::timer::format(total_time.elapsed(), boost::timer::default_places, "%ws\n") << std::endl;
251 return total_time.elapsed();
252}
253
254template<typename Iterator>
255bool check_not_end(boost::container::vector<Iterator> &iterators, Iterator itend, std::size_t number_of_ends = 0)
256{
257 std::size_t end_count = 0;
258 for(std::size_t i = 0, max = iterators.size(); i != max; ++i){
259 if(iterators[i] == itend && (++end_count > number_of_ends) )
260 return false;
261 }
262 return true;
263}
264
265template<typename Iterator>
266bool check_all_not_empty(boost::container::vector< std::pair<Iterator, Iterator > > &iterator_pairs)
267{
268 for(std::size_t i = 0, max = iterator_pairs.size(); i != max; ++i){
269 if(iterator_pairs[i].first == iterator_pairs[i].second)
270 return false;
271 }
272 return true;
273}
274
275template<typename C>
276cpu_times search_time(boost::container::vector<typename C::value_type> &unique_range, const char *RangeType)
277{
278 cpu_timer find_timer, lower_timer, upper_timer, equal_range_timer, count_timer;
279
280 C c(unique_range.begin(), unique_range.end());
281
282 cpu_timer total_time;
283 total_time.resume();
284
285 boost::container::vector<typename C::iterator> v_it(NElements);
286 boost::container::vector< std::pair<typename C::iterator, typename C::iterator> > v_itp(NElements);
287
288 for(std::size_t i = 0; i != NIter; ++i){
289 //Find
290 {
291 find_timer.resume();
292 for(std::size_t rep = 0; rep != 2; ++rep)
293 for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
294 v_it[i] = c.find(unique_range[i]);
295 }
296 find_timer.stop();
297 if(!check_not_end(v_it, c.end())){
298 std::cout << "ERROR! find all elements not found" << std::endl;
299 }
300 }
301 //Lower
302 {
303 lower_timer.resume();
304 for(std::size_t rep = 0; rep != 2; ++rep)
305 for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
306 v_it[i] = c.lower_bound(unique_range[i]);
307 }
308 lower_timer.stop();
309 if(!check_not_end(v_it, c.end())){
310 std::cout << "ERROR! lower_bound all elements not found" << std::endl;
311 }
312 }
313 //Upper
314 {
315 upper_timer.resume();
316 for(std::size_t rep = 0; rep != 2; ++rep)
317 for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
318 v_it[i] = c.upper_bound(unique_range[i]);
319 }
320 upper_timer.stop();
321 if(!check_not_end(v_it, c.end(), 1u)){
322 std::cout << "ERROR! upper_bound all elements not found" << std::endl;
323 }
324 }
325 //Equal
326 {
327 equal_range_timer.resume();
328 for(std::size_t rep = 0; rep != 2; ++rep)
329 for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
330 v_itp[i] = c.equal_range(unique_range[i]);
331 }
332 equal_range_timer.stop();
333 if(!check_all_not_empty(v_itp)){
334 std::cout << "ERROR! equal_range all elements not found" << std::endl;
335 }
336 }
337 //Count
338 {
339 std::size_t count = 0;
340 count_timer.resume();
341 for(std::size_t rep = 0; rep != 2; ++rep)
342 for(std::size_t i = 0, max = unique_range.size(); i != max; ++i){
343 count += c.count(unique_range[i]);
344 }
345 count_timer.stop();
346 if(count/2 != c.size()){
347 std::cout << "ERROR! count all elements not found" << std::endl;
348 }
349 }
350 }
351 total_time.stop();
352
353 std::cout << " Find " << RangeType << " " << boost::timer::format(find_timer.elapsed(), boost::timer::default_places, "%ws\n");
354 std::cout << " Lower Bound " << RangeType << " " << boost::timer::format(lower_timer.elapsed(), boost::timer::default_places, "%ws\n");
355 std::cout << " Upper Bound " << RangeType << " " << boost::timer::format(upper_timer.elapsed(), boost::timer::default_places, "%ws\n");
356 std::cout << " Equal Range " << RangeType << " " << boost::timer::format(equal_range_timer.elapsed(), boost::timer::default_places, "%ws\n");
357 std::cout << " Count " << RangeType << " " << boost::timer::format(count_timer.elapsed(), boost::timer::default_places, "%ws\n");
358 std::cout << " Total time = " << boost::timer::format(total_time.elapsed(), boost::timer::default_places, "%ws\n") << std::endl;
359 return total_time.elapsed();
360}
361
362template<typename C>
363void extensions_time(boost::container::vector<typename C::value_type> &sorted_unique_range)
364{
365 cpu_timer sur_timer,sur_opt_timer;
366 sur_timer.stop();sur_opt_timer.stop();
367
368 for(std::size_t i = 0; i != NIter; ++i){
369 {
370 sur_timer.resume();
371 C c(sorted_unique_range.begin(), sorted_unique_range.end());
372 sur_timer.stop();
373 }
374 {
375 sur_opt_timer.resume();
376 C c(boost::container::ordered_unique_range, sorted_unique_range.begin(), sorted_unique_range.end());
377 sur_opt_timer.stop();
378 }
379
380 }
381 std::cout << " Construct sorted_unique_range " << boost::timer::format(sur_timer.elapsed(), boost::timer::default_places, "%ws\n");
382 std::cout << " Construct sorted_unique_range (extension) " << boost::timer::format(sur_opt_timer.elapsed(), boost::timer::default_places, "%ws\n");
383 std::cout << "Extension/Standard: ";
384 compare_times(sur_opt_timer.elapsed(), sur_timer.elapsed());
385}
386
387template<class BoostClass, class StdClass>
388void launch_tests(const char *BoostContName, const char *StdContName)
389{
390 typedef range_provider<typename BoostClass::value_type> get_range_t;
391 try {
392 std::cout << "**********************************************" << '\n';
393 std::cout << "**********************************************" << '\n';
394 std::cout << '\n';
395 std::cout << BoostContName << " .VS " << StdContName << '\n';
396 std::cout << '\n';
397 std::cout << "**********************************************" << '\n';
398 std::cout << "**********************************************" << '\n' << std::endl;
399 {
400 std::cout << "Copy/Assign/Destroy benchmark:" << BoostContName << std::endl;
401 cpu_times boost_set_time = copy_destroy_time< BoostClass >(get_range_t::sorted_unique());
402
403 std::cout << "Copy/Assign/Destroy benchmark:" << StdContName << std::endl;
404 cpu_times std_set_time = copy_destroy_time< StdClass >(get_range_t::sorted_unique());
405
406 std::cout << BoostContName << "/" << StdContName << ": ";
407 compare_times(boost_set_time, std_set_time);
408 }
409 {
410 std::cout << "Ordered construct benchmark:" << BoostContName << std::endl;
411 cpu_times boost_set_time = construct_time< BoostClass >(get_range_t::sorted_unique(), get_range_t::sorted(), "(ord)");
412
413 std::cout << "Ordered construct benchmark:" << StdContName << std::endl;
414 cpu_times std_set_time = construct_time< StdClass >(get_range_t::sorted_unique(), get_range_t::sorted(), "(ord)");;
415
416 std::cout << BoostContName << "/" << StdContName << ": ";
417 compare_times(boost_set_time, std_set_time);
418 }
419 {
420 std::cout << "Random construct benchmark:" << BoostContName << std::endl;
421 cpu_times boost_set_time = construct_time< BoostClass >(get_range_t::random_unique(), get_range_t::random(), "(rnd)");
422
423 std::cout << "Random construct benchmark:" << StdContName << std::endl;
424 cpu_times std_set_time = construct_time< StdClass >(get_range_t::random_unique(), get_range_t::random(), "(rnd)");;
425
426 std::cout << BoostContName << "/" << StdContName << ": ";
427 compare_times(boost_set_time, std_set_time);
428 }
429 {
430 std::cout << "Ordered Insert benchmark:" << BoostContName << std::endl;
431 cpu_times boost_set_time = insert_time< BoostClass >(get_range_t::sorted_unique(), get_range_t::sorted(), "(ord)");
432
433 std::cout << "Ordered Insert benchmark:" << StdContName << std::endl;
434 cpu_times std_set_time = insert_time< StdClass >(get_range_t::sorted_unique(), get_range_t::sorted(), "(ord)");
435
436 std::cout << BoostContName << "/" << StdContName << ": ";
437 compare_times(boost_set_time, std_set_time);
438 }
439 {
440 std::cout << "Random Insert benchmark:" << BoostContName << std::endl;
441 cpu_times boost_set_time = insert_time< BoostClass >(get_range_t::random_unique(), get_range_t::random(), "(rnd)");
442
443 std::cout << "Random Insert benchmark:" << StdContName << std::endl;
444 cpu_times std_set_time = insert_time< StdClass >(get_range_t::random_unique(), get_range_t::random(), "(rnd)");
445
446 std::cout << BoostContName << "/" << StdContName << ": ";
447 compare_times(boost_set_time, std_set_time);
448 }
449 {
450 std::cout << "Ordered Search benchmark:" << BoostContName << std::endl;
451 cpu_times boost_set_time = search_time< BoostClass >(get_range_t::sorted_unique(), "(ord)");
452
453 std::cout << "Ordered Search benchmark:" << StdContName << std::endl;
454 cpu_times std_set_time = search_time< StdClass >(get_range_t::sorted_unique(), "(ord)");
455
456 std::cout << BoostContName << "/" << StdContName << ": ";
457 compare_times(boost_set_time, std_set_time);
458 }
459 {
460 std::cout << "Random Search benchmark:" << BoostContName << std::endl;
461 cpu_times boost_set_time = search_time< BoostClass >(get_range_t::random_unique(), "(rnd)");
462
463 std::cout << "Random Search benchmark:" << StdContName << std::endl;
464 cpu_times std_set_time = search_time< StdClass >(get_range_t::random_unique(), "(rnd)");
465
466 std::cout << BoostContName << "/" << StdContName << ": ";
467 compare_times(boost_set_time, std_set_time);
468 }
469 {
470 std::cout << "Extensions benchmark:" << BoostContName << std::endl;
471 extensions_time< BoostClass >(get_range_t::sorted_unique());
472 }
473
474 }catch(std::exception e){
475 std::cout << e.what();
476 }
477}
478
479#endif //#ifndef BOOST_CONTAINER_BENCH_BENCH_SET_HPP