perf_list.cpp 18 KB

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