bench_sort.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2015-2016.
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // See http://www.boost.org/libs/move for documentation.
  9. //
  10. //////////////////////////////////////////////////////////////////////////////
  11. #include <cstdlib> //std::srand
  12. #include <algorithm> //std::stable_sort, std::make|sort_heap, std::random_shuffle
  13. #include <cstdio> //std::printf
  14. #include <iostream> //std::cout
  15. #include <boost/container/vector.hpp> //boost::container::vector
  16. #include <boost/config.hpp>
  17. #include <boost/move/unique_ptr.hpp>
  18. #include <boost/timer/timer.hpp>
  19. using boost::timer::cpu_timer;
  20. using boost::timer::cpu_times;
  21. using boost::timer::nanosecond_type;
  22. #include "order_type.hpp"
  23. #include "random_shuffle.hpp"
  24. //#define BOOST_MOVE_ADAPTIVE_SORT_STATS
  25. //#define BOOST_MOVE_ADAPTIVE_SORT_INVARIANTS
  26. void print_stats(const char *str, boost::ulong_long_type element_count)
  27. {
  28. std::printf("%sCmp:%7.03f Cpy:%8.03f\n", str, double(order_perf_type::num_compare)/element_count, double(order_perf_type::num_copy)/element_count );
  29. }
  30. #include <boost/move/algo/adaptive_sort.hpp>
  31. #include <boost/move/algo/detail/merge_sort.hpp>
  32. #include <boost/move/algo/detail/pdqsort.hpp>
  33. #include <boost/move/algo/detail/heap_sort.hpp>
  34. #include <boost/move/core.hpp>
  35. template<class T>
  36. void generate_elements(boost::container::vector<T> &elements, std::size_t L, std::size_t NK)
  37. {
  38. elements.resize(L);
  39. boost::movelib::unique_ptr<std::size_t[]> key_reps(new std::size_t[NK ? NK : L]);
  40. std::srand(0);
  41. for (std::size_t i = 0; i < (NK ? NK : L); ++i) {
  42. key_reps[i] = 0;
  43. }
  44. for (std::size_t i = 0; i < L; ++i) {
  45. std::size_t key = NK ? (i % NK) : i;
  46. elements[i].key = key;
  47. }
  48. ::random_shuffle(elements.data(), elements.data() + L);
  49. ::random_shuffle(elements.data(), elements.data() + L);
  50. for (std::size_t i = 0; i < L; ++i) {
  51. elements[i].val = key_reps[elements[i].key]++;
  52. }
  53. }
  54. template<class T, class Compare>
  55. void adaptive_sort_buffered(T *elements, std::size_t element_count, Compare comp, std::size_t BufLen)
  56. {
  57. boost::movelib::unique_ptr<char[]> mem(new char[sizeof(T)*BufLen]);
  58. boost::movelib::adaptive_sort(elements, elements + element_count, comp, reinterpret_cast<T*>(mem.get()), BufLen);
  59. }
  60. template<class T, class Compare>
  61. void std_like_adaptive_stable_sort_buffered(T *elements, std::size_t element_count, Compare comp, std::size_t BufLen)
  62. {
  63. boost::movelib::unique_ptr<char[]> mem(new char[sizeof(T)*BufLen]);
  64. boost::movelib::stable_sort_adaptive_ONlogN2(elements, elements + element_count, comp, reinterpret_cast<T*>(mem.get()), BufLen);
  65. }
  66. template<class T, class Compare>
  67. void merge_sort_buffered(T *elements, std::size_t element_count, Compare comp)
  68. {
  69. boost::movelib::unique_ptr<char[]> mem(new char[sizeof(T)*((element_count+1)/2)]);
  70. boost::movelib::merge_sort(elements, elements + element_count, comp, reinterpret_cast<T*>(mem.get()));
  71. }
  72. enum AlgoType
  73. {
  74. MergeSort,
  75. StableSort,
  76. PdQsort,
  77. StdSort,
  78. AdaptiveSort,
  79. SqrtHAdaptiveSort,
  80. SqrtAdaptiveSort,
  81. Sqrt2AdaptiveSort,
  82. QuartAdaptiveSort,
  83. InplaceStableSort,
  84. StdSqrtHAdpSort,
  85. StdSqrtAdpSort,
  86. StdSqrt2AdpSort,
  87. StdQuartAdpSort,
  88. SlowStableSort,
  89. HeapSort,
  90. MaxSort
  91. };
  92. const char *AlgoNames [] = { "MergeSort "
  93. , "StableSort "
  94. , "PdQsort "
  95. , "StdSort "
  96. , "AdaptSort "
  97. , "SqrtHAdaptSort "
  98. , "SqrtAdaptSort "
  99. , "Sqrt2AdaptSort "
  100. , "QuartAdaptSort "
  101. , "InplStableSort "
  102. , "StdSqrtHAdpSort"
  103. , "StdSqrtAdpSort "
  104. , "StdSqrt2AdpSort"
  105. , "StdQuartAdpSort"
  106. , "SlowSort "
  107. , "HeapSort "
  108. };
  109. BOOST_STATIC_ASSERT((sizeof(AlgoNames)/sizeof(*AlgoNames)) == MaxSort);
  110. template<class T>
  111. bool measure_algo(T *elements, std::size_t element_count, std::size_t alg, nanosecond_type &prev_clock)
  112. {
  113. std::printf("%s ", AlgoNames[alg]);
  114. order_perf_type::num_compare=0;
  115. order_perf_type::num_copy=0;
  116. order_perf_type::num_elements = element_count;
  117. cpu_timer timer;
  118. timer.resume();
  119. switch(alg)
  120. {
  121. case MergeSort:
  122. merge_sort_buffered(elements, element_count, order_type_less());
  123. break;
  124. case StableSort:
  125. std::stable_sort(elements,elements+element_count,order_type_less());
  126. break;
  127. case PdQsort:
  128. boost::movelib::pdqsort(elements,elements+element_count,order_type_less());
  129. break;
  130. case StdSort:
  131. std::sort(elements,elements+element_count,order_type_less());
  132. break;
  133. case AdaptiveSort:
  134. boost::movelib::adaptive_sort(elements, elements+element_count, order_type_less());
  135. break;
  136. case SqrtHAdaptiveSort:
  137. adaptive_sort_buffered( elements, element_count, order_type_less()
  138. , boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count)/2+1);
  139. break;
  140. case SqrtAdaptiveSort:
  141. adaptive_sort_buffered( elements, element_count, order_type_less()
  142. , boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count));
  143. break;
  144. case Sqrt2AdaptiveSort:
  145. adaptive_sort_buffered( elements, element_count, order_type_less()
  146. , 2*boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count));
  147. break;
  148. case QuartAdaptiveSort:
  149. adaptive_sort_buffered( elements, element_count, order_type_less()
  150. , (element_count-1)/4+1);
  151. break;
  152. case InplaceStableSort:
  153. boost::movelib::inplace_stable_sort(elements, elements+element_count, order_type_less());
  154. break;
  155. case StdSqrtHAdpSort:
  156. std_like_adaptive_stable_sort_buffered( elements, element_count, order_type_less()
  157. , boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count)/2+1);
  158. break;
  159. case StdSqrtAdpSort:
  160. std_like_adaptive_stable_sort_buffered( elements, element_count, order_type_less()
  161. , boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count));
  162. break;
  163. case StdSqrt2AdpSort:
  164. std_like_adaptive_stable_sort_buffered( elements, element_count, order_type_less()
  165. , 2*boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count));
  166. break;
  167. case StdQuartAdpSort:
  168. std_like_adaptive_stable_sort_buffered( elements, element_count, order_type_less()
  169. , (element_count-1)/4+1);
  170. break;
  171. case SlowStableSort:
  172. boost::movelib::detail_adaptive::slow_stable_sort(elements, elements+element_count, order_type_less());
  173. break;
  174. case HeapSort:
  175. boost::movelib::heap_sort(elements, elements+element_count, order_type_less());
  176. boost::movelib::heap_sort((order_move_type*)0, (order_move_type*)0, order_type_less());
  177. break;
  178. }
  179. timer.stop();
  180. if(order_perf_type::num_elements == element_count){
  181. std::printf(" Tmp Ok ");
  182. } else{
  183. std::printf(" Tmp KO ");
  184. }
  185. nanosecond_type new_clock = timer.elapsed().wall;
  186. //std::cout << "Cmp:" << order_perf_type::num_compare << " Cpy:" << order_perf_type::num_copy; //for old compilers without ll size argument
  187. std::printf("Cmp:%7.03f Cpy:%8.03f", double(order_perf_type::num_compare)/element_count, double(order_perf_type::num_copy)/element_count );
  188. double time = double(new_clock);
  189. const char *units = "ns";
  190. if(time >= 1000000000.0){
  191. time /= 1000000000.0;
  192. units = " s";
  193. }
  194. else if(time >= 1000000.0){
  195. time /= 1000000.0;
  196. units = "ms";
  197. }
  198. else if(time >= 1000.0){
  199. time /= 1000.0;
  200. units = "us";
  201. }
  202. std::printf(" %6.02f%s (%6.02f)\n"
  203. , time
  204. , units
  205. , prev_clock ? double(new_clock)/double(prev_clock): 1.0);
  206. prev_clock = new_clock;
  207. bool res = is_order_type_ordered(elements, element_count, alg != HeapSort && alg != PdQsort && alg != StdSort);
  208. return res;
  209. }
  210. template<class T>
  211. bool measure_all(std::size_t L, std::size_t NK)
  212. {
  213. boost::container::vector<T> original_elements, elements;
  214. generate_elements(original_elements, L, NK);
  215. std::printf("\n - - N: %u, NK: %u - -\n", (unsigned)L, (unsigned)NK);
  216. nanosecond_type prev_clock = 0;
  217. nanosecond_type back_clock;
  218. bool res = true;
  219. elements = original_elements;
  220. res = res && measure_algo(elements.data(), L,MergeSort, prev_clock);
  221. back_clock = prev_clock;
  222. //
  223. prev_clock = back_clock;
  224. elements = original_elements;
  225. res = res && measure_algo(elements.data(), L,StableSort, prev_clock);
  226. //
  227. prev_clock = back_clock;
  228. elements = original_elements;
  229. res = res && measure_algo(elements.data(), L,PdQsort, prev_clock);
  230. //
  231. prev_clock = back_clock;
  232. elements = original_elements;
  233. res = res && measure_algo(elements.data(), L,StdSort, prev_clock);
  234. //
  235. prev_clock = back_clock;
  236. elements = original_elements;
  237. res = res && measure_algo(elements.data(), L,HeapSort, prev_clock);
  238. //
  239. prev_clock = back_clock;
  240. elements = original_elements;
  241. res = res && measure_algo(elements.data(), L,QuartAdaptiveSort, prev_clock);
  242. //
  243. prev_clock = back_clock;
  244. elements = original_elements;
  245. res = res && measure_algo(elements.data(), L, StdQuartAdpSort, prev_clock);
  246. //
  247. prev_clock = back_clock;
  248. elements = original_elements;
  249. res = res && measure_algo(elements.data(), L,Sqrt2AdaptiveSort, prev_clock);
  250. //
  251. prev_clock = back_clock;
  252. elements = original_elements;
  253. res = res && measure_algo(elements.data(), L, StdSqrt2AdpSort, prev_clock);
  254. //
  255. prev_clock = back_clock;
  256. elements = original_elements;
  257. res = res && measure_algo(elements.data(), L,SqrtAdaptiveSort, prev_clock);
  258. //
  259. prev_clock = back_clock;
  260. elements = original_elements;
  261. res = res && measure_algo(elements.data(), L, StdSqrtAdpSort, prev_clock);
  262. //
  263. prev_clock = back_clock;
  264. elements = original_elements;
  265. res = res && measure_algo(elements.data(), L,SqrtHAdaptiveSort, prev_clock);
  266. //
  267. prev_clock = back_clock;
  268. elements = original_elements;
  269. res = res && measure_algo(elements.data(), L, StdSqrtHAdpSort, prev_clock);
  270. //
  271. prev_clock = back_clock;
  272. elements = original_elements;
  273. res = res && measure_algo(elements.data(), L,AdaptiveSort, prev_clock);
  274. //
  275. prev_clock = back_clock;
  276. elements = original_elements;
  277. res = res && measure_algo(elements.data(), L,InplaceStableSort, prev_clock);
  278. //
  279. //prev_clock = back_clock;
  280. //elements = original_elements;
  281. //res = res && measure_algo(elements.data(), L,SlowStableSort, prev_clock);
  282. //
  283. if(!res)
  284. throw int(0);
  285. return res;
  286. }
  287. //Undef it to run the long test
  288. #define BENCH_SORT_SHORT
  289. #define BENCH_SORT_UNIQUE_VALUES
  290. int main()
  291. {
  292. #ifndef BENCH_SORT_UNIQUE_VALUES
  293. measure_all<order_perf_type>(101,1);
  294. measure_all<order_perf_type>(101,7);
  295. measure_all<order_perf_type>(101,31);
  296. #endif
  297. measure_all<order_perf_type>(101,0);
  298. //
  299. #ifndef BENCH_SORT_UNIQUE_VALUES
  300. measure_all<order_perf_type>(1101,1);
  301. measure_all<order_perf_type>(1001,7);
  302. measure_all<order_perf_type>(1001,31);
  303. measure_all<order_perf_type>(1001,127);
  304. measure_all<order_perf_type>(1001,511);
  305. #endif
  306. measure_all<order_perf_type>(1001,0);
  307. //
  308. #ifndef BENCH_SORT_UNIQUE_VALUES
  309. measure_all<order_perf_type>(10001,65);
  310. measure_all<order_perf_type>(10001,255);
  311. measure_all<order_perf_type>(10001,1023);
  312. measure_all<order_perf_type>(10001,4095);
  313. #endif
  314. measure_all<order_perf_type>(10001,0);
  315. //
  316. #ifdef NDEBUG
  317. #ifndef BENCH_SORT_UNIQUE_VALUES
  318. measure_all<order_perf_type>(100001,511);
  319. measure_all<order_perf_type>(100001,2047);
  320. measure_all<order_perf_type>(100001,8191);
  321. measure_all<order_perf_type>(100001,32767);
  322. #endif
  323. measure_all<order_perf_type>(100001,0);
  324. //
  325. #ifndef BENCH_SORT_SHORT
  326. #ifndef BENCH_SORT_UNIQUE_VALUES
  327. measure_all<order_perf_type>(1000001, 8192);
  328. measure_all<order_perf_type>(1000001, 32768);
  329. measure_all<order_perf_type>(1000001, 131072);
  330. measure_all<order_perf_type>(1000001, 524288);
  331. #endif
  332. measure_all<order_perf_type>(1000001,0);
  333. #ifndef BENCH_SORT_UNIQUE_VALUES
  334. measure_all<order_perf_type>(10000001, 65536);
  335. measure_all<order_perf_type>(10000001, 262144);
  336. measure_all<order_perf_type>(10000001, 1048576);
  337. measure_all<order_perf_type>(10000001, 4194304);
  338. #endif
  339. measure_all<order_perf_type>(1000001,0);
  340. #endif //#ifndef BENCH_SORT_SHORT
  341. #endif //NDEBUG
  342. //measure_all<order_perf_type>(100000001,0);
  343. return 0;
  344. }