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