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