From baa5f0bbe70c42b3895211ef2230a265f24cfdaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 19 Mar 2016 12:20:15 +0100 Subject: [PATCH] Added adaptive sort test and refactored utilities between adaptive benches and the new test --- proj/vc7ide/Move.sln | 8 ++ proj/vc7ide/adaptive_sort_test.vcproj | 134 +++++++++++++++++++++ test/adaptive_sort_test.cpp | 91 ++++++++++++++ test/bench_merge.cpp | 163 ++++++++----------------- test/bench_sort.cpp | 164 ++++++++------------------ test/order_type.hpp | 82 +++++++++++++ 6 files changed, 412 insertions(+), 230 deletions(-) create mode 100644 proj/vc7ide/adaptive_sort_test.vcproj create mode 100644 test/adaptive_sort_test.cpp create mode 100644 test/order_type.hpp diff --git a/proj/vc7ide/Move.sln b/proj/vc7ide/Move.sln index 361ebae..905c497 100644 --- a/proj/vc7ide/Move.sln +++ b/proj/vc7ide/Move.sln @@ -119,6 +119,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_merge", "bench_merge. ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adaptive_sort_test", "adaptive_sort_test.vcproj", "{CD617A28-6217-B79E-4CE2-6BA035379A6A}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -247,6 +251,10 @@ Global {CD2617A8-6217-9EB7-24CE-6C9AA035376A}.Debug.Build.0 = Debug|Win32 {CD2617A8-6217-9EB7-24CE-6C9AA035376A}.Release.ActiveCfg = Release|Win32 {CD2617A8-6217-9EB7-24CE-6C9AA035376A}.Release.Build.0 = Release|Win32 + {CD617A28-6217-B79E-4CE2-6BA035379A6A}.Debug.ActiveCfg = Debug|Win32 + {CD617A28-6217-B79E-4CE2-6BA035379A6A}.Debug.Build.0 = Debug|Win32 + {CD617A28-6217-B79E-4CE2-6BA035379A6A}.Release.ActiveCfg = Release|Win32 + {CD617A28-6217-B79E-4CE2-6BA035379A6A}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionItems) = postSolution ..\..\..\..\boost\move\algo\adaptive_merge.hpp = ..\..\..\..\boost\move\algo\adaptive_merge.hpp diff --git a/proj/vc7ide/adaptive_sort_test.vcproj b/proj/vc7ide/adaptive_sort_test.vcproj new file mode 100644 index 0000000..7600c88 --- /dev/null +++ b/proj/vc7ide/adaptive_sort_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/adaptive_sort_test.cpp b/test/adaptive_sort_test.cpp new file mode 100644 index 0000000..4f44eeb --- /dev/null +++ b/test/adaptive_sort_test.cpp @@ -0,0 +1,91 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include //std::srand +#include //std::next_permutation +#include //std::cout + +#include + +#include +#include +#include + +using boost::timer::cpu_timer; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; + +#include "order_type.hpp" + +#include +#include + + +template +void adaptive_sort_buffered(T *elements, std::size_t element_count, Compare comp, std::size_t BufLen) +{ + boost::movelib::unique_ptr mem(new char[sizeof(T)*BufLen]); + boost::movelib::adaptive_sort(elements, elements + element_count, comp, reinterpret_cast(mem.get()), BufLen); +} + +template +bool test_all_permutations(std::size_t const element_count, std::size_t const num_keys, std::size_t const num_iter) +{ + boost::movelib::unique_ptr elements(new T[element_count]); + boost::movelib::unique_ptr key_reps(new std::size_t[num_keys ? num_keys : element_count]); + std::cout << "- - N: " << element_count << ", Keys: " << num_keys << ", It: " << num_iter << " \n"; + + //Initialize keys + for(std::size_t i=0; i < element_count; ++i){ + std::size_t key = num_keys ? (i % num_keys) : i; + elements[i].key=key; + } + + std::srand(255); + + for (std::size_t i = 0; i != num_iter; ++i) + { + std::random_shuffle(elements.get(), elements.get() + element_count); + for(std::size_t i = 0; i < (num_keys ? num_keys : element_count); ++i){ + key_reps[i]=0; + } + for(std::size_t i = 0; i < element_count; ++i){ + elements[i].val = key_reps[elements[i].key]++; + } + + boost::container::vector tmp(elements.get(), elements.get()+element_count); + + boost::movelib::adaptive_sort(tmp.data(), tmp.data()+element_count, order_type_less()); + + if (!is_order_type_ordered(tmp.data(), element_count)) + { + std::cout << "\n ERROR\n"; + throw int(0); + } + } + return true; +} + +int main() +{ + #ifdef NDEBUG + const std::size_t NIter = 100; + #else + const std::size_t NIter = 10; + #endif + test_all_permutations(10001, 65, NIter); + test_all_permutations(10001, 101, NIter); + test_all_permutations(10001, 1023, NIter); + test_all_permutations(10001, 4095, NIter); + test_all_permutations(10001, 0, NIter); + + return 0; +} diff --git a/test/bench_merge.cpp b/test/bench_merge.cpp index 2ee980b..d9d3272 100644 --- a/test/bench_merge.cpp +++ b/test/bench_merge.cpp @@ -18,62 +18,18 @@ #include #include +#include "order_type.hpp" + using boost::timer::cpu_timer; using boost::timer::cpu_times; using boost::timer::nanosecond_type; - -boost::ulong_long_type num_copy; -boost::ulong_long_type num_elements; - -struct merged_type -{ - public: - std::size_t key; - std::size_t val; - - merged_type() - { - ++num_elements; - } - - merged_type(const merged_type& other) - : key(other.key), val(other.val) - { - ++num_elements; - ++num_copy; - } - - merged_type & operator=(const merged_type& other) - { - ++num_copy; - key = other.key; - val = other.val; - return *this; - } - - ~merged_type () - { - --num_elements; - } -}; - -boost::ulong_long_type num_compare; - //#define BOOST_MOVE_ADAPTIVE_SORT_STATS void print_stats(const char *str, boost::ulong_long_type element_count) { - std::printf("%sCmp:%8.04f Cpy:%9.04f\n", str, double(num_compare)/element_count, double(num_copy)/element_count ); + std::printf("%sCmp:%8.04f Cpy:%9.04f\n", str, double(order_type::num_compare)/element_count, double(order_type::num_copy)/element_count ); } - -template -struct counted_less -{ - bool operator()(const T &a,T const &b) const - { ++num_compare; return a.key < b.key; } -}; - #include #include #include @@ -101,21 +57,7 @@ std::size_t generate_elements(T elements[], std::size_t element_count, std::size return split_count; } -template -bool test_order(T *elements, std::size_t element_count, bool stable = true) -{ - for(std::size_t i = 1; i < element_count; ++i){ - if(counted_less()(elements[i], elements[i-1])){ - std::printf("\n Ord KO !!!!"); - return false; - } - if( stable && !(counted_less()(elements[i-1], elements[i])) && (elements[i-1].val > elements[i].val) ){ - std::printf("\n Stb KO !!!! "); - return false; - } - } - return true; -} + template void adaptive_merge_buffered(T *elements, T *mid, T *last, Compare comp, std::size_t BufLen) @@ -150,53 +92,53 @@ BOOST_STATIC_ASSERT((sizeof(AlgoNames)/sizeof(*AlgoNames)) == MaxMerge); template bool measure_algo(T *elements, std::size_t key_reps[], std::size_t element_count, std::size_t key_len, unsigned alg, nanosecond_type &prev_clock) { - std::size_t const split_pos = generate_elements(elements, element_count, key_reps, key_len, counted_less()); + std::size_t const split_pos = generate_elements(elements, element_count, key_reps, key_len, order_type_less()); std::printf("%s ", AlgoNames[alg]); - num_compare=0; - num_copy=0; - num_elements = element_count; + order_type::num_compare=0; + order_type::num_copy=0; + order_type::num_elements = element_count; cpu_timer timer; timer.resume(); switch(alg) { case InplaceMerge: - std::inplace_merge(elements, elements+split_pos, elements+element_count, counted_less()); + std::inplace_merge(elements, elements+split_pos, elements+element_count, order_type_less()); break; case AdaptiveMerge: - boost::movelib::adaptive_merge(elements, elements+split_pos, elements+element_count, counted_less()); + boost::movelib::adaptive_merge(elements, elements+split_pos, elements+element_count, order_type_less()); break; case SqrtHAdaptiveMerge: - adaptive_merge_buffered( elements, elements+split_pos, elements+element_count, counted_less() + adaptive_merge_buffered( elements, elements+split_pos, elements+element_count, order_type_less() , boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count)/2+1); break; case SqrtAdaptiveMerge: - adaptive_merge_buffered( elements, elements+split_pos, elements+element_count, counted_less() + adaptive_merge_buffered( elements, elements+split_pos, elements+element_count, order_type_less() , boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count)); break; case Sqrt2AdaptiveMerge: - adaptive_merge_buffered( elements, elements+split_pos, elements+element_count, counted_less() + adaptive_merge_buffered( elements, elements+split_pos, elements+element_count, order_type_less() , 2*boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count)); break; case QuartAdaptiveMerge: - adaptive_merge_buffered( elements, elements+split_pos, elements+element_count, counted_less() + adaptive_merge_buffered( elements, elements+split_pos, elements+element_count, order_type_less() , (element_count-1)/4+1); break; case BuflessMerge: - boost::movelib::merge_bufferless(elements, elements+split_pos, elements+element_count, counted_less()); + boost::movelib::merge_bufferless(elements, elements+split_pos, elements+element_count, order_type_less()); break; } timer.stop(); - if(num_elements == element_count){ + if(order_type::num_elements == element_count){ std::printf(" Tmp Ok "); } else{ std::printf(" Tmp KO "); } nanosecond_type new_clock = timer.elapsed().wall; - //std::cout << "Cmp:" << num_compare << " Cpy:" << num_copy; //for old compilers without ll size argument - std::printf("Cmp:%8.04f Cpy:%9.04f", double(num_compare)/element_count, double(num_copy)/element_count ); + //std::cout << "Cmp:" << order_type::num_compare << " Cpy:" << order_type::num_copy; //for old compilers without ll size argument + std::printf("Cmp:%8.04f Cpy:%9.04f", double(order_type::num_compare)/element_count, double(order_type::num_copy)/element_count ); double time = double(new_clock); @@ -219,7 +161,7 @@ bool measure_algo(T *elements, std::size_t key_reps[], std::size_t element_count , units , prev_clock ? double(new_clock)/double(prev_clock): 1.0); prev_clock = new_clock; - bool res = test_order(elements, element_count, true); + bool res = is_order_type_ordered(elements, element_count, true); return res; } @@ -261,62 +203,55 @@ bool measure_all(std::size_t L, std::size_t NK) return res; } -struct less -{ - template - bool operator()(const T &t, const U &u) - { return t < u; } -}; - //Undef it to run the long test #define BENCH_MERGE_SHORT int main() { try{ - measure_all(101,1); - measure_all(101,7); - measure_all(101,31); - measure_all(101,0); + measure_all(101,1); + measure_all(101,7); + measure_all(101,31); + measure_all(101,0); // - measure_all(1101,1); - measure_all(1001,7); - measure_all(1001,31); - measure_all(1001,127); - measure_all(1001,511); - measure_all(1001,0); + measure_all(1101,1); + measure_all(1001,7); + measure_all(1001,31); + measure_all(1001,127); + measure_all(1001,511); + measure_all(1001,0); // #ifndef BENCH_MERGE_SHORT - measure_all(10001,65); - measure_all(10001,255); - measure_all(10001,1023); - measure_all(10001,4095); - measure_all(10001,0); + measure_all(10001,65); + measure_all(10001,255); + measure_all(10001,1023); + measure_all(10001,4095); + measure_all(10001,0); // - measure_all(100001,511); - measure_all(100001,2047); - measure_all(100001,8191); - measure_all(100001,32767); - measure_all(100001,0); + measure_all(100001,511); + measure_all(100001,2047); + measure_all(100001,8191); + measure_all(100001,32767); + measure_all(100001,0); // #ifdef NDEBUG - measure_all(1000001,1); - measure_all(1000001,1024); - measure_all(1000001,32768); - measure_all(1000001,524287); - measure_all(1000001,0); - measure_all(1500001,0); - //measure_all(10000001,0); - //measure_all(15000001,0); - //measure_all(100000001,0); + measure_all(1000001,1); + measure_all(1000001,1024); + measure_all(1000001,32768); + measure_all(1000001,524287); + measure_all(1000001,0); + measure_all(1500001,0); + //measure_all(10000001,0); + //measure_all(15000001,0); + //measure_all(100000001,0); #endif //NDEBUG #endif //#ifndef BENCH_MERGE_SHORT - //measure_all(100000001,0); + //measure_all(100000001,0); } catch(...) { diff --git a/test/bench_sort.cpp b/test/bench_sort.cpp index 6fe30e8..4945efa 100644 --- a/test/bench_sort.cpp +++ b/test/bench_sort.cpp @@ -23,58 +23,15 @@ using boost::timer::cpu_timer; using boost::timer::cpu_times; using boost::timer::nanosecond_type; - -boost::ulong_long_type num_copy; -boost::ulong_long_type num_elements; - -struct sorted_type -{ - public: - std::size_t key; - std::size_t val; - - sorted_type() - { - ++num_elements; - } - - sorted_type(const sorted_type& other) - : key(other.key), val(other.val) - { - ++num_elements; - ++num_copy; - } - - sorted_type & operator=(const sorted_type& other) - { - ++num_copy; - key = other.key; - val = other.val; - return *this; - } - - ~sorted_type () - { - --num_elements; - } -}; - -boost::ulong_long_type num_compare; +#include "order_type.hpp" //#define BOOST_MOVE_ADAPTIVE_SORT_STATS void print_stats(const char *str, boost::ulong_long_type element_count) { - std::printf("%sCmp:%7.03f Cpy:%8.03f\n", str, double(num_compare)/element_count, double(num_copy)/element_count ); + std::printf("%sCmp:%7.03f Cpy:%8.03f\n", str, double(order_type::num_compare)/element_count, double(order_type::num_copy)/element_count ); } -template -struct counted_less -{ - bool operator()(const T &a,T const &b) const - { ++num_compare; return a.key < b.key; } -}; - #include #include #include @@ -99,22 +56,6 @@ void generate_elements(T elements[], std::size_t element_count, std::size_t key_ } } -template -bool test_order(T *elements, std::size_t element_count, bool stable = true) -{ - for(std::size_t i = 1; i < element_count; ++i){ - if(counted_less()(elements[i], elements[i-1])){ - std::printf("\n Ord KO !!!!"); - return false; - } - if( stable && !(counted_less()(elements[i-1], elements[i])) && (elements[i-1].val > elements[i].val) ){ - std::printf("\n Stb KO !!!! "); - return false; - } - } - return true; -} - template void adaptive_sort_buffered(T *elements, std::size_t element_count, Compare comp, std::size_t BufLen) { @@ -164,60 +105,60 @@ bool measure_algo(T *elements, std::size_t key_reps[], std::size_t element_count generate_elements(elements, element_count, key_reps, key_len); std::printf("%s ", AlgoNames[alg]); - num_compare=0; - num_copy=0; - num_elements = element_count; + order_type::num_compare=0; + order_type::num_copy=0; + order_type::num_elements = element_count; cpu_timer timer; timer.resume(); switch(alg) { case MergeSort: - merge_sort_buffered(elements, element_count, counted_less()); + merge_sort_buffered(elements, element_count, order_type_less()); break; case StableSort: - std::stable_sort(elements,elements+element_count,counted_less()); + std::stable_sort(elements,elements+element_count,order_type_less()); break; case AdaptiveSort: - boost::movelib::adaptive_sort(elements, elements+element_count, counted_less()); + boost::movelib::adaptive_sort(elements, elements+element_count, order_type_less()); break; case SqrtHAdaptiveSort: - adaptive_sort_buffered( elements, element_count, counted_less() + adaptive_sort_buffered( elements, element_count, order_type_less() , boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count)/2+1); break; case SqrtAdaptiveSort: - adaptive_sort_buffered( elements, element_count, counted_less() + adaptive_sort_buffered( elements, element_count, order_type_less() , boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count)); break; case Sqrt2AdaptiveSort: - adaptive_sort_buffered( elements, element_count, counted_less() + adaptive_sort_buffered( elements, element_count, order_type_less() , 2*boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count)); break; case QuartAdaptiveSort: - adaptive_sort_buffered( elements, element_count, counted_less() + adaptive_sort_buffered( elements, element_count, order_type_less() , (element_count-1)/4+1); break; case NoBufMergeSort: - boost::movelib::bufferless_merge_sort(elements, elements+element_count, counted_less()); + boost::movelib::bufferless_merge_sort(elements, elements+element_count, order_type_less()); break; case SlowStableSort: - boost::movelib::detail_adaptive::slow_stable_sort(elements, elements+element_count, counted_less()); + boost::movelib::detail_adaptive::slow_stable_sort(elements, elements+element_count, order_type_less()); break; case HeapSort: - std::make_heap(elements, elements+element_count, counted_less()); - std::sort_heap(elements, elements+element_count, counted_less()); + std::make_heap(elements, elements+element_count, order_type_less()); + std::sort_heap(elements, elements+element_count, order_type_less()); break; } timer.stop(); - if(num_elements == element_count){ + if(order_type::num_elements == element_count){ std::printf(" Tmp Ok "); } else{ std::printf(" Tmp KO "); } nanosecond_type new_clock = timer.elapsed().wall; - //std::cout << "Cmp:" << num_compare << " Cpy:" << num_copy; //for old compilers without ll size argument - std::printf("Cmp:%7.03f Cpy:%8.03f", double(num_compare)/element_count, double(num_copy)/element_count ); + //std::cout << "Cmp:" << order_type::num_compare << " Cpy:" << order_type::num_copy; //for old compilers without ll size argument + std::printf("Cmp:%7.03f Cpy:%8.03f", double(order_type::num_compare)/element_count, double(order_type::num_copy)/element_count ); double time = double(new_clock); @@ -240,7 +181,7 @@ bool measure_algo(T *elements, std::size_t key_reps[], std::size_t element_count , units , prev_clock ? double(new_clock)/double(prev_clock): 1.0); prev_clock = new_clock; - bool res = test_order(elements, element_count, alg != HeapSort && alg != NoBufMergeSort); + bool res = is_order_type_ordered(elements, element_count, alg != HeapSort && alg != NoBufMergeSort); return res; } @@ -294,58 +235,49 @@ bool measure_all(std::size_t L, std::size_t NK) //Undef it to run the long test #define BENCH_SORT_SHORT -struct less -{ - template - bool operator()(const T &t, const U &u) - { return t < u; } -}; - - int main() { - measure_all(101,1); - measure_all(101,7); - measure_all(101,31); - measure_all(101,0); + measure_all(101,1); + measure_all(101,7); + measure_all(101,31); + measure_all(101,0); // - measure_all(1101,1); - measure_all(1001,7); - measure_all(1001,31); - measure_all(1001,127); - measure_all(1001,511); - measure_all(1001,0); + measure_all(1101,1); + measure_all(1001,7); + measure_all(1001,31); + measure_all(1001,127); + measure_all(1001,511); + measure_all(1001,0); // #ifndef BENCH_SORT_SHORT - measure_all(10001,65); - measure_all(10001,255); - measure_all(10001,1023); - measure_all(10001,4095); - measure_all(10001,0); + measure_all(10001,65); + measure_all(10001,255); + measure_all(10001,1023); + measure_all(10001,4095); + measure_all(10001,0); // - measure_all(100001,511); - measure_all(100001,2047); - measure_all(100001,8191); - measure_all(100001,32767); - measure_all(100001,0); + measure_all(100001,511); + measure_all(100001,2047); + measure_all(100001,8191); + measure_all(100001,32767); + measure_all(100001,0); // #ifdef NDEBUG - measure_all(1000001,1); - measure_all(1000001,1024); - measure_all(1000001,32768); - measure_all(1000001,524287); - measure_all(1000001,0); - measure_all(1500001,0); - //measure_all(10000001,0); + measure_all(1000001,1); + measure_all(1000001,1024); + measure_all(1000001,32768); + measure_all(1000001,524287); + measure_all(1000001,0); + measure_all(1500001,0); + //measure_all(10000001,0); #endif //NDEBUG #endif //#ifndef BENCH_SORT_SHORT - //measure_all(100000001,0); + //measure_all(100000001,0); return 0; } - diff --git a/test/order_type.hpp b/test/order_type.hpp new file mode 100644 index 0000000..5953cb4 --- /dev/null +++ b/test/order_type.hpp @@ -0,0 +1,82 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_MOVE_TEST_ORDER_TYPE_HPP +#define BOOST_MOVE_TEST_ORDER_TYPE_HPP + +#include +#include +#include + +struct order_type +{ + public: + std::size_t key; + std::size_t val; + + order_type() + { + ++num_elements; + } + + order_type(const order_type& other) + : key(other.key), val(other.val) + { + ++num_elements; + ++num_copy; + } + + order_type & operator=(const order_type& other) + { + ++num_copy; + key = other.key; + val = other.val; + return *this; + } + + ~order_type () + { + --num_elements; + } + + static boost::ulong_long_type num_compare; + static boost::ulong_long_type num_copy; + static boost::ulong_long_type num_elements; +}; + +boost::ulong_long_type order_type::num_compare = 0; +boost::ulong_long_type order_type::num_copy = 0; +boost::ulong_long_type order_type::num_elements = 0; + +template +struct order_type_less +{ + bool operator()(const T &a,T const &b) const + { ++order_type::num_compare; return a.key < b.key; } +}; + +template +inline bool is_order_type_ordered(T *elements, std::size_t element_count, bool stable = true) +{ + for(std::size_t i = 1; i < element_count; ++i){ + if(order_type_less()(elements[i], elements[i-1])){ + std::printf("\n Ord KO !!!!"); + return false; + } + if( stable && !(order_type_less()(elements[i-1], elements[i])) && (elements[i-1].val > elements[i].val) ){ + std::printf("\n Stb KO !!!! "); + return false; + } + } + return true; +} + +#endif //BOOST_MOVE_TEST_ORDER_TYPE_HPP