• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga  2007-2013
4 //
5 // Distributed under the Boost Software License, Version 1.0.
6 //    (See accompanying file LICENSE_1_0.txt or copy at
7 //          http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // See http://www.boost.org/libs/intrusive for documentation.
10 //
11 /////////////////////////////////////////////////////////////////////////////
12 
13 //Includes for tests
14 #include <boost/intrusive/detail/config_begin.hpp>
15 #include <boost/config.hpp>
16 #include <list>
17 #include <functional>
18 #include <iostream>
19 #include <boost/intrusive/list.hpp>
20 #include <boost/date_time/posix_time/posix_time.hpp>
21 
22 using namespace boost::posix_time;
23 
24 //[perf_list_value_type
25 //Iteration and element count defines
26 const int NumIter = 4;
27 const int NumElements   = 50000;
28 
29 using namespace boost::intrusive;
30 
31 template<bool BigSize>  struct filler        {  int dummy[10];   };
32 template <>             struct filler<false> {};
33 
34 template<bool BigSize> //The object for non-intrusive containers
35 struct test_class :  private filler<BigSize>
36 {
37    int i_;
test_classtest_class38    test_class()               {}
test_classtest_class39    test_class(int i) :  i_(i) {}
operator <(const test_class & l,const test_class & r)40    friend bool operator <(const test_class &l, const test_class &r)  {  return l.i_ < r.i_;  }
operator >(const test_class & l,const test_class & r)41    friend bool operator >(const test_class &l, const test_class &r)  {  return l.i_ > r.i_;  }
42 };
43 
44 template <bool BigSize, link_mode_type LinkMode>
45 struct itest_class   //The object for intrusive containers
46    :  public list_base_hook<link_mode<LinkMode> >,  public test_class<BigSize>
47 {
itest_classitest_class48    itest_class()                                {}
itest_classitest_class49    itest_class(int i) : test_class<BigSize>(i)  {}
50 };
51 
52 template<class FuncObj> //Adapts functors taking values to functors taking pointers
53 struct func_ptr_adaptor  :  public FuncObj
54 {
55    typedef typename FuncObj::first_argument_type*  first_argument_type;
56    typedef typename FuncObj::second_argument_type* second_argument_type;
57    typedef typename FuncObj::result_type           result_type;
operator ()func_ptr_adaptor58    result_type operator()(first_argument_type a,  second_argument_type b) const
59       {  return FuncObj::operator()(*a, *b); }
60 };
61 //]
62 
63 template <bool BigSize, link_mode_type LinkMode>
64 struct get_ilist  //Helps to define an intrusive list from a policy
65 {
66    typedef list<itest_class<BigSize, LinkMode>, constant_time_size<false> > type;
67 };
68 
69 template <bool BigSize> //Helps to define an std list
70 struct get_list      {  typedef std::list<test_class<BigSize> > type;   };
71 
72 template <bool BigSize> //Helps to define an std pointer list
73 struct get_ptrlist   {  typedef std::list<test_class<BigSize>*> type;   };
74 
75 ////////////////////////////////////////////////////////////////////////
76 //
77 //                            PUSH_BACK
78 //
79 ////////////////////////////////////////////////////////////////////////
80 
81 template <bool BigSize, link_mode_type LinkMode>
test_intrusive_list_push_back()82 void test_intrusive_list_push_back()
83 {
84    typedef typename get_ilist<BigSize, LinkMode>::type ilist;
85    ptime tini = microsec_clock::universal_time();
86    for(int i = 0; i < NumIter; ++i){
87       //First create the elements and insert them in the intrusive list
88       //[perf_list_push_back_intrusive
89       std::vector<typename ilist::value_type> objects(NumElements);
90       ilist l;
91       for(int i = 0; i < NumElements; ++i)
92          l.push_back(objects[i]);
93       //Elements are unlinked in ilist's destructor
94       //Elements are destroyed in vector's destructor
95       //]
96    }
97    ptime tend = microsec_clock::universal_time();
98    std::cout << "link_mode: " << LinkMode << ", usecs/iteration: "
99              << (tend-tini).total_microseconds()/NumIter << std::endl;
100 }
101 
102 template <bool BigSize>
test_std_list_push_back()103 void test_std_list_push_back()
104 {
105    typedef typename get_list<BigSize>::type stdlist;
106    ptime tini = microsec_clock::universal_time();
107    for(int i = 0; i < NumIter; ++i){
108       //Now create the std list and insert
109       //[perf_list_push_back_stdlist
110       stdlist l;
111       for(int i = 0; i < NumElements; ++i)
112          l.push_back(typename stdlist::value_type(i));
113       //Elements unlinked and destroyed in stdlist's destructor
114       //]
115    }
116    ptime tend = microsec_clock::universal_time();
117    std::cout << "std::list usecs/iteration: "
118              << (tend-tini).total_microseconds()/NumIter << std::endl;
119 }
120 
121 template <bool BigSize>
test_compact_std_ptrlist_push_back()122 void test_compact_std_ptrlist_push_back()
123 {
124    typedef typename get_list<BigSize>::type stdlist;
125    typedef typename get_ptrlist<BigSize>::type stdptrlist;
126    //Now measure insertion time, including element creation
127    ptime tini = microsec_clock::universal_time();
128    for(int i = 0; i < NumIter; ++i){
129       //Create elements and insert their pointer in the list
130       //[perf_list_push_back_stdptrlist
131       std::vector<typename stdlist::value_type> objects(NumElements);
132       stdptrlist l;
133       for(int i = 0; i < NumElements; ++i)
134          l.push_back(&objects[i]);
135       //Pointers to elements unlinked and destroyed in stdptrlist's destructor
136       //Elements destroyed in vector's destructor
137       //]
138    }
139    ptime tend = microsec_clock::universal_time();
140    std::cout << "compact std::list usecs/iteration: "
141              << (tend-tini).total_microseconds()/NumIter << std::endl;
142 }
143 
144 template <bool BigSize>
test_disperse_std_ptrlist_push_back()145 void test_disperse_std_ptrlist_push_back()
146 {
147    typedef typename get_list<BigSize>::type stdlist;
148    typedef typename get_ptrlist<BigSize>::type stdptrlist;
149    //Now measure insertion time, including element creation
150    ptime tini = microsec_clock::universal_time();
151    for(int i = 0; i < NumIter; ++i){
152       //Create elements and insert their pointer in the list
153       //[perf_list_push_back_disperse_stdptrlist
154       stdlist objects;  stdptrlist l;
155       for(int i = 0; i < NumElements; ++i){
156          objects.push_back(typename stdlist::value_type(i));
157          l.push_back(&objects.back());
158       }
159       //Pointers to elements unlinked and destroyed in stdptrlist's destructor
160       //Elements unlinked and destroyed in stdlist's destructor
161       //]
162    }
163    ptime tend = microsec_clock::universal_time();
164    std::cout << "disperse std::list usecs/iteration: "
165              << (tend-tini).total_microseconds()/NumIter << std::endl;
166 }
167 
168 ////////////////////////////////////////////////////////////////////////
169 //
170 //                            REVERSE
171 //
172 ////////////////////////////////////////////////////////////////////////
173 
174 //[perf_list_reverse
175 template <bool BigSize, link_mode_type LinkMode>
test_intrusive_list_reverse()176 void test_intrusive_list_reverse()
177 {
178    typedef typename get_ilist<BigSize, LinkMode>::type ilist;
179    //First create the elements
180    std::vector<typename ilist::value_type> objects(NumElements);
181 
182    //Now create the intrusive list and insert data
183    ilist l(objects.begin(), objects.end());
184 
185    //Now measure sorting time
186    ptime tini = microsec_clock::universal_time();
187    for(int i = 0; i < NumIter; ++i){
188       l.reverse();
189    }
190    ptime tend = microsec_clock::universal_time();
191    std::cout << "link_mode: " << LinkMode << ", usecs/iteration: "
192              << (tend-tini).total_microseconds()/NumIter << std::endl;
193 }
194 
195 template <bool BigSize>
test_std_list_reverse()196 void test_std_list_reverse()
197 {
198    typedef typename get_list<BigSize>::type stdlist;
199 
200    //Create the list and insert values
201    stdlist l;
202    for(int i = 0; i < NumElements; ++i)
203       l.push_back(typename stdlist::value_type());
204 
205    //Now measure sorting time
206    ptime tini = microsec_clock::universal_time();
207    for(int i = 0; i < NumIter; ++i){
208       l.reverse();
209    }
210    ptime tend = microsec_clock::universal_time();
211    std::cout << "std::list usecs/iteration: "
212              << (tend-tini).total_microseconds()/NumIter << std::endl;
213 }
214 
215 template <bool BigSize>
test_compact_std_ptrlist_reverse()216 void test_compact_std_ptrlist_reverse()
217 {
218    typedef typename get_list<BigSize>::type stdlist;
219    typedef typename get_ptrlist<BigSize>::type stdptrlist;
220 
221    //First create the elements
222    std::vector<typename stdlist::value_type> objects(NumElements);
223 
224    //Now create the std list and insert
225    stdptrlist l;
226    for(int i = 0; i < NumElements; ++i)
227       l.push_back(&objects[i]);
228 
229    //Now measure sorting time
230    ptime tini = microsec_clock::universal_time();
231    for(int i = 0; i < NumIter; ++i){
232       l.reverse();
233    }
234    ptime tend = microsec_clock::universal_time();
235    std::cout << "compact std::list usecs/iteration: "
236              << (tend-tini).total_microseconds()/NumIter << std::endl;
237 }
238 
239 template <bool BigSize>
test_disperse_std_ptrlist_reverse()240 void test_disperse_std_ptrlist_reverse()
241 {
242    typedef typename get_list<BigSize>::type stdlist;
243    typedef typename get_ptrlist<BigSize>::type stdptrlist;
244 
245    //First create the elements
246    std::list<typename stdlist::value_type> objects;
247    //Now create the std list and insert
248    stdptrlist l;
249    for(int i = 0; i < NumElements; ++i){
250       objects.push_back(typename stdlist::value_type());
251       l.push_back(&objects.back());
252    }
253 
254    //Now measure sorting time
255    ptime tini = microsec_clock::universal_time();
256    for(int i = 0; i < NumIter; ++i){
257       l.reverse();
258    }
259    ptime tend = microsec_clock::universal_time();
260    std::cout << "disperse std::list usecs/iteration: "
261              << (tend-tini).total_microseconds()/NumIter << std::endl;
262 }
263 //]
264 
265 ////////////////////////////////////////////////////////////////////////
266 //
267 //                            SORT
268 //
269 ////////////////////////////////////////////////////////////////////////
270 
271 //[perf_list_sort
272 template <bool BigSize, link_mode_type LinkMode>
test_intrusive_list_sort()273 void test_intrusive_list_sort()
274 {
275    typedef typename get_ilist<BigSize, LinkMode>::type ilist;
276 
277    //First create the elements
278    std::vector<typename ilist::value_type> objects(NumElements);
279    for(int i = 0; i < NumElements; ++i)
280       objects[i].i_ = i;
281 
282    //Now create the intrusive list and insert data
283    ilist l(objects.begin(), objects.end());
284 
285    //Now measure sorting time
286    ptime tini = microsec_clock::universal_time();
287    for(int i = 0; i < NumIter; ++i){
288       if(!(i % 2)){
289          l.sort(std::greater<typename ilist::value_type>());
290       }
291       else{
292          l.sort(std::less<typename ilist::value_type>());
293       }
294    }
295    ptime tend = microsec_clock::universal_time();
296    std::cout << "link_mode: " << LinkMode << ", usecs/iteration: "
297              << (tend-tini).total_microseconds()/NumIter << std::endl;
298 }
299 
300 template <bool BigSize>
test_std_list_sort()301 void test_std_list_sort()
302 {
303    typedef typename get_list<BigSize>::type stdlist;
304 
305    //Create the list and insert values
306    stdlist l;
307    for(int i = 0; i < NumElements; ++i)
308       l.push_back(typename stdlist::value_type(i));
309 
310    //Now measure sorting time
311    ptime tini = microsec_clock::universal_time();
312    for(int i = 0; i < NumIter; ++i){
313       if(!(i % 2)){
314          l.sort(std::greater<typename stdlist::value_type>());
315       }
316       else{
317          l.sort(std::less<typename stdlist::value_type>());
318       }
319    }
320    ptime tend = microsec_clock::universal_time();
321    std::cout << "std::list usecs/iteration: "
322              << (tend-tini).total_microseconds()/NumIter << std::endl;
323 }
324 
325 template <bool BigSize>
test_compact_std_ptrlist_sort()326 void test_compact_std_ptrlist_sort()
327 {
328    typedef typename get_list<BigSize>::type stdlist;
329    typedef typename get_ptrlist<BigSize>::type stdptrlist;
330 
331    //First create the elements
332    std::vector<typename stdlist::value_type> objects(NumElements);
333    for(int i = 0; i < NumElements; ++i)
334       objects[i].i_ = i;
335    //Now create the std list and insert
336    stdptrlist l;
337    for(int i = 0; i < NumElements; ++i)
338       l.push_back(&objects[i]);
339 
340    //Now measure sorting time
341    ptime tini = microsec_clock::universal_time();
342    for(int i = 0; i < NumIter; ++i){
343       if(!(i % 2)){
344          l.sort(func_ptr_adaptor<std::greater<typename stdlist::value_type> >());
345       }
346       else{
347          l.sort(func_ptr_adaptor<std::less<typename stdlist::value_type> >());
348       }
349    }
350    ptime tend = microsec_clock::universal_time();
351    std::cout << "compact std::list usecs/iteration: "
352              << (tend-tini).total_microseconds()/NumIter << std::endl;
353 }
354 
355 template <bool BigSize>
test_disperse_std_ptrlist_sort()356 void test_disperse_std_ptrlist_sort()
357 {
358    typedef typename get_list<BigSize>::type stdlist;
359    typedef typename get_ptrlist<BigSize>::type stdptrlist;
360 
361    //First create the elements and the list
362    std::list<typename stdlist::value_type> objects;
363    stdptrlist l;
364    for(int i = 0; i < NumElements; ++i){
365       objects.push_back(typename stdlist::value_type(i));
366       l.push_back(&objects.back());
367    }
368 
369    //Now measure sorting time
370    ptime tini = microsec_clock::universal_time();
371    for(int i = 0; i < NumIter; ++i){
372       if(!(i % 2)){
373          l.sort(func_ptr_adaptor<std::greater<typename stdlist::value_type> >());
374       }
375       else{
376          l.sort(func_ptr_adaptor<std::less<typename stdlist::value_type> >());
377       }
378    }
379    ptime tend = microsec_clock::universal_time();
380    std::cout << "disperse std::list usecs/iteration: "
381              << (tend-tini).total_microseconds()/NumIter << std::endl;
382 }
383 //]
384 
385 ////////////////////////////////////////////////////////////////////////
386 //
387 //                            WRITE ACCESS
388 //
389 ////////////////////////////////////////////////////////////////////////
390 //[perf_list_write_access
391 template <bool BigSize, link_mode_type LinkMode>
test_intrusive_list_write_access()392 void test_intrusive_list_write_access()
393 {
394    typedef typename get_ilist<BigSize, LinkMode>::type ilist;
395 
396    //First create the elements
397    std::vector<typename ilist::value_type> objects(NumElements);
398    for(int i = 0; i < NumElements; ++i){
399       objects[i].i_ = i;
400    }
401 
402    //Now create the intrusive list and insert data
403    ilist l(objects.begin(), objects.end());
404 
405    //Now measure access time to the value type
406    ptime tini = microsec_clock::universal_time();
407    for(int i = 0; i < NumIter; ++i){
408       typename ilist::iterator it(l.begin()), end(l.end());
409       for(; it != end; ++it){
410          ++(it->i_);
411       }
412    }
413    ptime tend = microsec_clock::universal_time();
414    std::cout << "link_mode: " << LinkMode << ", usecs/iteration: "
415              << (tend-tini).total_microseconds()/NumIter << std::endl;
416 }
417 
418 template <bool BigSize>
test_std_list_write_access()419 void test_std_list_write_access()
420 {
421    typedef typename get_list<BigSize>::type stdlist;
422 
423    //Create the list and insert values
424    stdlist l;
425    for(int i = 0; i < NumElements; ++i)
426       l.push_back(typename stdlist::value_type(i));
427 
428    //Now measure access time to the value type
429    ptime tini = microsec_clock::universal_time();
430    for(int i = 0; i < NumIter; ++i){
431       typename stdlist::iterator it(l.begin()), end(l.end());
432       for(; it != end; ++it){
433          ++(it->i_);
434       }
435    }
436    ptime tend = microsec_clock::universal_time();
437    std::cout << "std::list usecs/iteration: "
438              << (tend-tini).total_microseconds()/NumIter << std::endl;
439 }
440 
441 template <bool BigSize>
test_compact_std_ptrlist_write_access()442 void test_compact_std_ptrlist_write_access()
443 {
444    typedef typename get_list<BigSize>::type stdlist;
445    typedef typename get_ptrlist<BigSize>::type stdptrlist;
446 
447    //First create the elements
448    std::vector<typename stdlist::value_type> objects(NumElements);
449    for(int i = 0; i < NumElements; ++i){
450       objects[i].i_ = i;
451    }
452 
453    //Now create the std list and insert
454    stdptrlist l;
455    for(int i = 0; i < NumElements; ++i)
456       l.push_back(&objects[i]);
457 
458    //Now measure access time to the value type
459    ptime tini = microsec_clock::universal_time();
460    for(int i = 0; i < NumIter; ++i){
461       typename stdptrlist::iterator it(l.begin()), end(l.end());
462       for(; it != end; ++it){
463          ++((*it)->i_);
464       }
465    }
466    ptime tend = microsec_clock::universal_time();
467    std::cout << "compact std::list usecs/iteration: "
468              << (tend-tini).total_microseconds()/NumIter << std::endl;
469 }
470 
471 template <bool BigSize>
test_disperse_std_ptrlist_write_access()472 void test_disperse_std_ptrlist_write_access()
473 {
474    typedef typename get_list<BigSize>::type stdlist;
475    typedef typename get_ptrlist<BigSize>::type stdptrlist;
476 
477    //First create the elements
478    std::list<typename stdlist::value_type> objects;
479    //Now create the std list and insert
480    stdptrlist l;
481    for(int i = 0; i < NumElements; ++i){
482       objects.push_back(typename stdlist::value_type(i));
483       l.push_back(&objects.back());
484    }
485 
486    //Now measure access time to the value type
487    ptime tini = microsec_clock::universal_time();
488    for(int i = 0; i < NumIter; ++i){
489       typename stdptrlist::iterator it(l.begin()), end(l.end());
490       for(; it != end; ++it){
491          ++((*it)->i_);
492       }
493    }
494    ptime tend = microsec_clock::universal_time();
495    std::cout << "disperse std::list usecs/iteration: "
496              << (tend-tini).total_microseconds()/NumIter << std::endl;
497 }
498 //]
499 
500 ////////////////////////////////////////////////////////////////////////
501 //
502 //                            ALL TESTS
503 //
504 ////////////////////////////////////////////////////////////////////////
505 template<bool BigSize>
do_all_tests()506 void do_all_tests()
507 {
508    std::cout << "\n\nTesting push back() with BigSize:" << BigSize << std::endl;
509    test_intrusive_list_push_back<BigSize, normal_link>();
510    test_intrusive_list_push_back<BigSize, safe_link>();
511    test_intrusive_list_push_back<BigSize, auto_unlink>();
512    test_std_list_push_back<BigSize> ();
513    test_compact_std_ptrlist_push_back<BigSize>();
514    test_disperse_std_ptrlist_push_back<BigSize>();
515    //reverse
516    std::cout << "\n\nTesting reverse() with BigSize:" << BigSize << std::endl;
517    test_intrusive_list_reverse<BigSize, normal_link>();
518    test_intrusive_list_reverse<BigSize, safe_link>();
519    test_intrusive_list_reverse<BigSize, auto_unlink>();
520    test_std_list_reverse<BigSize>();
521    test_compact_std_ptrlist_reverse<BigSize>();
522    test_disperse_std_ptrlist_reverse<BigSize>();
523    //sort
524    std::cout << "\n\nTesting sort() with BigSize:" << BigSize << std::endl;
525    test_intrusive_list_sort<BigSize, normal_link>();
526    test_intrusive_list_sort<BigSize, safe_link>();
527    test_intrusive_list_sort<BigSize, auto_unlink>();
528    test_std_list_sort<BigSize>();
529    test_compact_std_ptrlist_sort<BigSize>();
530    test_disperse_std_ptrlist_sort<BigSize>();
531    //write_access
532    std::cout << "\n\nTesting write_access() with BigSize:" << BigSize << std::endl;
533    test_intrusive_list_write_access<BigSize, normal_link>();
534    test_intrusive_list_write_access<BigSize, safe_link>();
535    test_intrusive_list_write_access<BigSize, auto_unlink>();
536    test_std_list_write_access<BigSize>();
537    test_compact_std_ptrlist_write_access<BigSize>();
538    test_disperse_std_ptrlist_write_access<BigSize>();
539 }
540 
main()541 int main()
542 {
543    //First pass the tests with a small size class
544    do_all_tests<false>();
545    //Now pass the tests with a big size class
546    do_all_tests<true>();
547    return 0;
548 }
549 
550 #include <boost/intrusive/detail/config_end.hpp>
551