diff --git a/experimental/bench_hub.cpp b/experimental/bench_hub.cpp index e80ed9a..e75c037 100644 --- a/experimental/bench_hub.cpp +++ b/experimental/bench_hub.cpp @@ -16,9 +16,9 @@ int main() { return 0; } #include #include -#include #include #include +#include #include "../bench/bench_utils.hpp" #include @@ -30,8 +30,9 @@ int main() { return 0; } //reflects the actual (possibly padded) size. #ifndef ELEMENT_SIZES //#define ELEMENT_SIZES { 16, 32, 64, 96, 128, 192, 256 } -#define ELEMENT_SIZES { 16, 64, 128, 256 } +//#define ELEMENT_SIZES { 16, 64, 128, 256 } //#define ELEMENT_SIZES { 64, 80 } +#define ELEMENT_SIZES { 64 } #endif inline constexpr std::size_t element_sizes[] = ELEMENT_SIZES; inline constexpr std::size_t element_sizes_count = @@ -39,40 +40,45 @@ inline constexpr std::size_t element_sizes_count = #define NONTRIVIAL_ELEMENT -std::chrono::high_resolution_clock::time_point measure_start, measure_pause; +//Wall-clock measured in nanoseconds via boost::move_detail::nsec_clock(). +//measure_start is advanced forward by resume_timing() so that +//(now - measure_start) yields measured (non-paused) time. +boost::move_detail::nanosecond_type measure_start, measure_pause; template BOOST_NOINLINE double measure(F f) { - using namespace std::chrono; + typedef boost::move_detail::nanosecond_type nsec_t; #ifdef NDEBUG - //static const std::size_t num_trials = 8; - //static const milliseconds min_time_per_trial(100); - static const int num_trials = 1; - static const milliseconds min_time_per_trial(0); + //static const std::size_t num_trials = 10; + //static const nsec_t min_time_per_trial = 150000000u; //150 ms + static const std::size_t num_trials = 8; + static const nsec_t min_time_per_trial = 100000000u; //75 ms + //static const std::size_t num_trials = 1; + //static const nsec_t min_time_per_trial = 0u; #else - static const std::size_t num_trials = 1; - static const milliseconds min_time_per_trial(0); + static const std::size_t num_trials = 1; + static const nsec_t min_time_per_trial = 0u; #endif std::array trials; for(std::size_t i = 0; i < num_trials; ++i) { - int runs = 0; - high_resolution_clock::time_point t2; - decltype(f()) res; + int runs = 0; + nsec_t t1; + nsec_t t2; + decltype(f()) res; - measure_start = high_resolution_clock::now(); + measure_start = t1 = boost::move_detail::nsec_clock(); do{ clobber(); res = f(); escape(&res); - t2 = high_resolution_clock::now(); + t2 = boost::move_detail::nsec_clock(); ++runs; - }while((t2 - measure_start) < min_time_per_trial); - trials[i] = - duration_cast>(t2 - measure_start).count() / runs; + }while((t2 - t1) < min_time_per_trial); + trials[i] = double(t2 - measure_start) / 1.0e9 / runs; } std::sort(trials.begin(), trials.end()); @@ -83,12 +89,12 @@ BOOST_NOINLINE double measure(F f) BOOST_CONTAINER_FORCEINLINE void pause_timing() { - measure_pause = std::chrono::high_resolution_clock::now(); + measure_pause = boost::move_detail::nsec_clock(); } BOOST_CONTAINER_FORCEINLINE void resume_timing() { - measure_start += std::chrono::high_resolution_clock::now() - measure_pause; + measure_start += boost::move_detail::nsec_clock() - measure_pause; } #include @@ -208,6 +214,7 @@ void fill(Container& c, std::size_t n) while(n--) c.insert((int)rng()); } } + /* static std::size_t min_size_exp = 3, max_size_exp = 7; @@ -306,7 +313,7 @@ benchmark_result benchmark(const char* title, std::size_t element_size, FNum fnu } template -struct create +struct create_fill { unsigned int operator()(std::size_t n, double erasure_rate) const { @@ -323,7 +330,7 @@ struct create }; template -struct create_and_destroy +struct create_fill_and_destroy { unsigned int operator()(std::size_t n, double erasure_rate) const { @@ -333,6 +340,93 @@ struct create_and_destroy } }; +//Isolates the cost of make() alone (the insert + shuffle + +//random-erase build), excluding the subsequent destruction. +template +struct creation +{ + unsigned int operator()(std::size_t n, double erasure_rate) const + { + unsigned int res = 0; + { + auto c = make(n, erasure_rate); // measured + res = (unsigned int)c.size(); + pause_timing(); // exclude destruction + } + resume_timing(); + return res; + } +}; + +//Isolates the cost of fill() alone (re-inserting up to n elements into an +//already-built, partially-erased container), excluding make and destruction. +template +struct filling +{ + unsigned int operator()(std::size_t n, double erasure_rate) const + { + unsigned int res = 0; + { + pause_timing(); + auto c = make(n, erasure_rate); // excluded + resume_timing(); + fill(c, n); // measured + res = (unsigned int)c.size(); + pause_timing(); // exclude destruction + } + resume_timing(); + return res; + } +}; + +template +struct erasure +{ + unsigned int operator()(std::size_t n, double erasure_rate) const + { + unsigned int res = 0; + { + pause_timing(); + std::uint64_t erasure_cut = + (std::uint64_t)(erasure_rate * (double)(std::uint64_t)(-1)); + + Container c; + urbg rng; + std::vector iterators; + + iterators.reserve(n); + for (std::size_t i = 0; i < n; ++i) iterators.push_back(c.insert((int)rng())); + std::shuffle(iterators.begin(), iterators.end(), rng); + resume_timing(); + + for (auto it : iterators) { + if (rng() < erasure_cut) erase_void(c, it); + } + pause_timing(); + res = (unsigned)c.size(); + } + return res; + } +}; + +//Isolates the cost of the container destructor alone, over a fully built and +//filled container, excluding make and fill. +template +struct destruction +{ + unsigned int operator()(std::size_t n, double erasure_rate) const + { + unsigned int res = 0; + { + pause_timing(); + auto c = make(n, erasure_rate); // excluded + res = (unsigned int)c.size(); + resume_timing(); // measure only the dtor below + } // ~Container() measured here + return res; + } +}; + template struct prepare { @@ -525,6 +619,7 @@ run_summary run_bench() //using num = nest, store_data_in_block > >; #endif using den = nest; + //using den = hub; //using den = nest > >; //using den = nest > >; @@ -534,7 +629,7 @@ run_summary run_bench() << "ELEMENT SIZE: " << element_size << " bytes\n" << std::string(41, '=') << "\n"; - table t; + table t;/* t.push_back(benchmark( "iteration", element_size, ::iteration{}, ::iteration{})); @@ -545,11 +640,23 @@ run_summary run_bench() "sort", element_size, sort{}, sort{})); t.push_back(benchmark( - "creat, ins, erase, ins", element_size, - create{}, create{})); + "create, fill", element_size, + create_fill{}, create_fill{})); t.push_back(benchmark( - "creat, ins, erase, ins, destroy", element_size, - create_and_destroy{}, create_and_destroy{})); + "create, fill, destroy", element_size, + create_fill_and_destroy{}, create_fill_and_destroy{})); + t.push_back(benchmark( + "destroy (dtor)", element_size, + destruction{}, destruction{})); + t.push_back(benchmark( + "creation (make)", element_size, + creation{}, creation{}));*/ + t.push_back(benchmark( + "filling", element_size, + filling{}, filling{}));/* + t.push_back(benchmark( + "erasure", element_size, + ::erasure{}, ::erasure{}));*/ const std::string filename = "hub_test_" + std::to_string(element_size) + ".txt"; write_table(t, filename.c_str(), element_size);