bench_adaptive_node_pool.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2007-2013. 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. //Enable checks in debug mode
  11. #ifndef NDEBUG
  12. #define BOOST_CONTAINER_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS
  13. #endif
  14. #ifdef _MSC_VER
  15. #pragma warning (disable : 4512)
  16. #pragma warning (disable : 4127)
  17. #pragma warning (disable : 4244)
  18. #pragma warning (disable : 4267)
  19. #endif
  20. #include <boost/container/adaptive_pool.hpp>
  21. #include <boost/container/node_allocator.hpp>
  22. #include <boost/container/allocator.hpp>
  23. #include <boost/container/list.hpp>
  24. #include <memory> //std::allocator
  25. #include <iostream> //std::cout, std::endl
  26. #include <vector> //std::vector
  27. #include <cstddef> //std::size_t
  28. #include <cassert> //assert
  29. #include <boost/timer/timer.hpp>
  30. using boost::timer::cpu_timer;
  31. using boost::timer::cpu_times;
  32. using boost::timer::nanosecond_type;
  33. namespace bc = boost::container;
  34. typedef std::allocator<int> StdAllocator;
  35. typedef bc::allocator<int, 2> AllocatorPlusV2;
  36. typedef bc::allocator<int, 1> AllocatorPlusV1;
  37. typedef bc::adaptive_pool
  38. < int
  39. , bc::ADP_nodes_per_block
  40. , bc::ADP_max_free_blocks
  41. , bc::ADP_only_alignment
  42. , 1> AdPoolAlignOnlyV1;
  43. typedef bc::adaptive_pool
  44. < int
  45. , bc::ADP_nodes_per_block
  46. , bc::ADP_max_free_blocks
  47. , bc::ADP_only_alignment
  48. , 2> AdPoolAlignOnlyV2;
  49. typedef bc::adaptive_pool
  50. < int
  51. , bc::ADP_nodes_per_block
  52. , bc::ADP_max_free_blocks
  53. , 2
  54. , 1> AdPool2PercentV1;
  55. typedef bc::adaptive_pool
  56. < int
  57. , bc::ADP_nodes_per_block
  58. , bc::ADP_max_free_blocks
  59. , 2
  60. , 2> AdPool2PercentV2;
  61. typedef bc::node_allocator
  62. < int
  63. , bc::NodeAlloc_nodes_per_block
  64. , 1> SimpleSegregatedStorageV1;
  65. typedef bc::node_allocator
  66. < int
  67. , bc::NodeAlloc_nodes_per_block
  68. , 2> SimpleSegregatedStorageV2;
  69. //Explicit instantiation
  70. template class bc::adaptive_pool
  71. < int
  72. , bc::ADP_nodes_per_block
  73. , bc::ADP_max_free_blocks
  74. , bc::ADP_only_alignment
  75. , 2>;
  76. template class bc::node_allocator
  77. < int
  78. , bc::NodeAlloc_nodes_per_block
  79. , 2>;
  80. template<class Allocator> struct get_allocator_name;
  81. template<> struct get_allocator_name<StdAllocator>
  82. { static const char *get() { return "StdAllocator"; } };
  83. template<> struct get_allocator_name<AllocatorPlusV2>
  84. { static const char *get() { return "AllocatorPlusV2"; } };
  85. template<> struct get_allocator_name<AllocatorPlusV1>
  86. { static const char *get() { return "AllocatorPlusV1"; } };
  87. template<> struct get_allocator_name<AdPoolAlignOnlyV1>
  88. { static const char *get() { return "AdPoolAlignOnlyV1"; } };
  89. template<> struct get_allocator_name<AdPoolAlignOnlyV2>
  90. { static const char *get() { return "AdPoolAlignOnlyV2"; } };
  91. template<> struct get_allocator_name<AdPool2PercentV1>
  92. { static const char *get() { return "AdPool2PercentV1"; } };
  93. template<> struct get_allocator_name<AdPool2PercentV2>
  94. { static const char *get() { return "AdPool2PercentV2"; } };
  95. template<> struct get_allocator_name<SimpleSegregatedStorageV1>
  96. { static const char *get() { return "SimpleSegregatedStorageV1"; } };
  97. template<> struct get_allocator_name<SimpleSegregatedStorageV2>
  98. { static const char *get() { return "SimpleSegregatedStorageV2"; } };
  99. class MyInt
  100. {
  101. std::size_t int_;
  102. public:
  103. explicit MyInt(std::size_t i = 0) : int_(i){}
  104. MyInt(const MyInt &other)
  105. : int_(other.int_)
  106. {}
  107. MyInt & operator=(const MyInt &other)
  108. {
  109. int_ = other.int_;
  110. return *this;
  111. }
  112. };
  113. template<class Allocator>
  114. void list_test_template(std::size_t num_iterations, std::size_t num_elements, bool csv_output)
  115. {
  116. typedef typename Allocator::template rebind<MyInt>::other IntAllocator;
  117. nanosecond_type tinsert, terase;
  118. bc::dlmalloc_malloc_stats_t insert_stats, erase_stats;
  119. std::size_t insert_inuse, erase_inuse;
  120. const size_t sizeof_node = 2*sizeof(void*)+sizeof(int);
  121. typedef bc::list<MyInt, IntAllocator> list_t;
  122. typedef typename list_t::iterator iterator_t;
  123. {
  124. cpu_timer timer;
  125. timer.resume();
  126. list_t l;
  127. for(std::size_t r = 0; r != num_iterations; ++r){
  128. l.insert(l.end(), num_elements, MyInt(r));
  129. }
  130. timer.stop();
  131. tinsert = timer.elapsed().wall;
  132. insert_inuse = bc::dlmalloc_in_use_memory();
  133. insert_stats = bc::dlmalloc_malloc_stats();
  134. /*
  135. iterator_t it(l.begin());
  136. iterator_t last(--l.end());
  137. for(std::size_t n_elem = 0, n_max = l.size()/2-1; n_elem != n_max; ++n_elem)
  138. {
  139. l.splice(it++, l, last--);
  140. }
  141. */
  142. //l.reverse();
  143. //Now preprocess erase ranges
  144. std::vector<iterator_t> ranges_to_erase;
  145. ranges_to_erase.push_back(l.begin());
  146. for(std::size_t r = 0; r != num_iterations; ++r){
  147. iterator_t next_pos(ranges_to_erase[r]);
  148. std::size_t n = num_elements;
  149. while(n--){ ++next_pos; }
  150. ranges_to_erase.push_back(next_pos);
  151. }
  152. //Measure range erasure function
  153. timer.start();
  154. for(std::size_t r = 0; r != num_iterations; ++r){
  155. assert((r+1) < ranges_to_erase.size());
  156. l.erase(ranges_to_erase[r], ranges_to_erase[r+1]);
  157. }
  158. timer.stop();
  159. terase = timer.elapsed().wall;
  160. erase_inuse = bc::dlmalloc_in_use_memory();
  161. erase_stats = bc::dlmalloc_malloc_stats();
  162. }
  163. if(csv_output){
  164. std::cout << get_allocator_name<Allocator>::get()
  165. << ";"
  166. << num_iterations
  167. << ";"
  168. << num_elements
  169. << ";"
  170. << float(tinsert)/(num_iterations*num_elements)
  171. << ";"
  172. << (unsigned int)insert_stats.system_bytes
  173. << ";"
  174. << float(insert_stats.system_bytes)/(num_iterations*num_elements*sizeof_node)*100.0-100.0
  175. << ";"
  176. << (unsigned int)insert_inuse
  177. << ";"
  178. << (float(insert_inuse)/(num_iterations*num_elements*sizeof_node)*100.0)-100.0
  179. << ";";
  180. std::cout << float(terase)/(num_iterations*num_elements)
  181. << ";"
  182. << (unsigned int)erase_stats.system_bytes
  183. << ";"
  184. << (unsigned int)erase_inuse
  185. << std::endl;
  186. }
  187. else{
  188. std::cout << std::endl
  189. << "Allocator: " << get_allocator_name<Allocator>::get()
  190. << std::endl
  191. << " allocation/deallocation(ns): " << float(tinsert)/(num_iterations*num_elements) << '\t' << float(terase)/(num_iterations*num_elements)
  192. << std::endl
  193. << " Sys MB(overh.)/Inuse MB(overh.): " << (float)insert_stats.system_bytes/(1024*1024) << "(" << float(insert_stats.system_bytes)/(num_iterations*num_elements*sizeof_node)*100.0-100.0 << "%)"
  194. << " / "
  195. << (float)insert_inuse/(1024*1024) << "(" << (float(insert_inuse)/(num_iterations*num_elements*sizeof_node)*100.0)-100.0 << "%)"
  196. << std::endl
  197. << " system MB/inuse bytes after: " << (float)erase_stats.system_bytes/(1024*1024) << '\t' << bc::dlmalloc_in_use_memory()
  198. << std::endl << std::endl;
  199. }
  200. //Release node_allocator cache
  201. typedef boost::container::dtl::shared_node_pool
  202. < (2*sizeof(void*)+sizeof(int))
  203. , AdPoolAlignOnlyV2::nodes_per_block> shared_node_pool_t;
  204. boost::container::dtl::singleton_default
  205. <shared_node_pool_t>::instance().purge_blocks();
  206. //Release adaptive_pool cache
  207. typedef boost::container::dtl::shared_adaptive_node_pool
  208. < (2*sizeof(void*)+sizeof(int))
  209. , AdPool2PercentV2::nodes_per_block
  210. , AdPool2PercentV2::max_free_blocks
  211. , AdPool2PercentV2::overhead_percent> shared_adaptive_pool_plus_t;
  212. boost::container::dtl::singleton_default
  213. <shared_adaptive_pool_plus_t>::instance().deallocate_free_blocks();
  214. //Release adaptive_pool cache
  215. typedef boost::container::dtl::shared_adaptive_node_pool
  216. < (2*sizeof(void*)+sizeof(int))
  217. , AdPool2PercentV2::nodes_per_block
  218. , AdPool2PercentV2::max_free_blocks
  219. , 0u> shared_adaptive_pool_plus_align_only_t;
  220. boost::container::dtl::singleton_default
  221. <shared_adaptive_pool_plus_align_only_t>::instance().deallocate_free_blocks();
  222. //Release dlmalloc memory
  223. bc::dlmalloc_trim(0);
  224. }
  225. void print_header()
  226. {
  227. std::cout << "Allocator" << ";" << "Iterations" << ";" << "Size" << ";"
  228. << "Insertion time(ns)" << ";"
  229. << "System bytes" << ";"
  230. << "System overhead(%)" << ";"
  231. << "In use bytes" << ";"
  232. << "In use overhead(%)" << ";"
  233. << "Erasure time (ns)" << ";"
  234. << "System bytes after" << ";"
  235. << "In use bytes after"
  236. << std::endl;
  237. }
  238. int main(int argc, const char *argv[])
  239. {
  240. //#define SINGLE_TEST
  241. #define SIMPLE_IT
  242. #ifdef SINGLE_TEST
  243. #ifdef BOOST_CONTAINER_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS
  244. std::size_t numrep[] = { 1000 };
  245. #elif defined(NDEBUG)
  246. std::size_t numrep [] = { 15000 };
  247. #else
  248. std::size_t numrep [] = { 1000 };
  249. #endif
  250. std::size_t numele [] = { 100 };
  251. #elif defined(SIMPLE_IT)
  252. std::size_t numrep [] = { 3 };
  253. std::size_t numele [] = { 100 };
  254. #else
  255. #ifdef NDEBUG
  256. std::size_t numrep [] = { 300, 3000, 30000, 300000, 600000, 1500000, 3000000 };
  257. #else
  258. std::size_t numrep [] = { 20, 200, 2000, 20000, 40000, 100000, 200000 };
  259. #endif
  260. std::size_t numele [] = { 10000, 1000, 100, 10, 5, 2, 1 };
  261. #endif
  262. bool csv_output = argc == 2 && (strcmp(argv[1], "--csv-output") == 0);
  263. if(csv_output){/*
  264. print_header();
  265. for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
  266. list_test_template<AllocatorPlusV1>(numrep[i], numele[i], csv_output);
  267. }
  268. for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
  269. list_test_template<AllocatorPlusV2>(numrep[i], numele[i], csv_output);
  270. }
  271. for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
  272. list_test_template<AdPoolAlignOnlyV1>(numrep[i], numele[i], csv_output);
  273. }
  274. for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
  275. list_test_template<AdPoolAlignOnlyV2>(numrep[i], numele[i], csv_output);
  276. }
  277. for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
  278. list_test_template<AdPool2PercentV1>(numrep[i], numele[i], csv_output);
  279. }
  280. for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
  281. list_test_template<AdPool2PercentV2>(numrep[i], numele[i], csv_output);
  282. }
  283. for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
  284. list_test_template<SimpleSegregatedStorageV1>(numrep[i], numele[i], csv_output);
  285. }
  286. for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
  287. list_test_template<SimpleSegregatedStorageV2>(numrep[i], numele[i], csv_output);
  288. }*/
  289. }
  290. else{
  291. for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
  292. std::cout << "\n ----------------------------------- \n"
  293. << " Iterations/Elements: " << numrep[i] << "/" << numele[i]
  294. << "\n ----------------------------------- \n";
  295. list_test_template<AllocatorPlusV1>(numrep[i], numele[i], csv_output);
  296. list_test_template<AllocatorPlusV2>(numrep[i], numele[i], csv_output);
  297. list_test_template<AdPoolAlignOnlyV1>(numrep[i], numele[i], csv_output);
  298. list_test_template<AdPoolAlignOnlyV2>(numrep[i], numele[i], csv_output);
  299. list_test_template<AdPool2PercentV1>(numrep[i], numele[i], csv_output);
  300. list_test_template<AdPool2PercentV2>(numrep[i], numele[i], csv_output);
  301. list_test_template<SimpleSegregatedStorageV1>(numrep[i], numele[i], csv_output);
  302. list_test_template<SimpleSegregatedStorageV2>(numrep[i], numele[i], csv_output);
  303. }
  304. }
  305. return 0;
  306. }