• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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