From 82dfcf54bebf1fe765b30847d937da7dd05472cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 14 Mar 2026 01:11:11 +0100 Subject: [PATCH] Add segmented algorithms simple benchmark --- experimental/bench_segmented_algos.cpp | 1215 ++++++++++++++++++++++++ 1 file changed, 1215 insertions(+) create mode 100644 experimental/bench_segmented_algos.cpp diff --git a/experimental/bench_segmented_algos.cpp b/experimental/bench_segmented_algos.cpp new file mode 100644 index 0000000..997dd8f --- /dev/null +++ b/experimental/bench_segmented_algos.cpp @@ -0,0 +1,1215 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2025-2026. 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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using boost::move_detail::cpu_timer; +using boost::move_detail::cpu_times; +using boost::move_detail::nanosecond_type; + +namespace bc = boost::container; + +volatile int sink = 0; + +inline void escape(void* p) +{ + #if defined(_MSC_VER) + sink = *static_cast(p); + #elif defined(__GNUC__) + asm volatile("" : : "g"(p) : "memory"); + #endif +} + +////////////////////////////////////////////////////////////////////////////// +// Value types +////////////////////////////////////////////////////////////////////////////// + +class MyInt +{ + int int_; + + public: + inline explicit MyInt(int i = 0) + : int_(i) + {} + + inline MyInt(const MyInt &other) + : int_(other.int_) + {} + + inline MyInt & operator=(const MyInt &other) + { + int_ = other.int_; + return *this; + } + + inline ~MyInt() + { + int_ = 0; + } + + inline int int_value() const { return int_; } + + friend inline bool operator==(const MyInt& a, const MyInt& b) { return a.int_ == b.int_; } + friend inline bool operator!=(const MyInt& a, const MyInt& b) { return a.int_ != b.int_; } + friend inline bool operator<(const MyInt& a, const MyInt& b) { return a.int_ < b.int_; } +}; + +class MyFatInt +{ + int int0_; + int int1_; + int int2_; + int int3_; + int int4_; + int int5_; + int int6_; + int int7_; + + public: + inline explicit MyFatInt(int i = 0) + : int0_(i++) + , int1_(i++) + , int2_(i++) + , int3_(i++) + , int4_(i++) + , int5_(i++) + , int6_(i++) + , int7_(i++) + {} + + inline MyFatInt(const MyFatInt &other) + : int0_(other.int0_) + , int1_(other.int1_) + , int2_(other.int2_) + , int3_(other.int3_) + , int4_(other.int4_) + , int5_(other.int5_) + , int6_(other.int6_) + , int7_(other.int7_) + {} + + inline MyFatInt & operator=(const MyFatInt &other) + { + int0_ = other.int0_; + int1_ = other.int1_; + int2_ = other.int2_; + int3_ = other.int3_; + int4_ = other.int4_; + int5_ = other.int5_; + int6_ = other.int6_; + int7_ = other.int7_; + return *this; + } + + inline ~MyFatInt() + { + int0_ = 0; + int1_ = 0; + int2_ = 0; + int3_ = 0; + int4_ = 0; + int5_ = 0; + int6_ = 0; + int7_ = 0; + } + + inline int int_value() const { return int0_; } + + friend inline bool operator==(const MyFatInt& a, const MyFatInt& b) { return a.int0_ == b.int0_; } + friend inline bool operator!=(const MyFatInt& a, const MyFatInt& b) { return a.int0_ != b.int0_; } + friend inline bool operator<(const MyFatInt& a, const MyFatInt& b) { return a.int0_ < b.int0_; } +}; + +inline int int_value(int x) { return x; } +inline int int_value(const MyInt& x) { return x.int_value(); } +inline int int_value(const MyFatInt& x) { return x.int_value(); } + +////////////////////////////////////////////////////////////////////////////// +// Functors +////////////////////////////////////////////////////////////////////////////// + +template +struct add_one +{ + T operator()(const T& x) const { return T(int_value(x) + 1); } +}; + +template +struct is_odd +{ + bool operator()(const T& x) const { return (int_value(x) & 1) != 0; } +}; + +template +struct summer +{ + int sum; + summer() : sum(0) {} + void operator()(const T& x) { sum = static_cast((static_cast(sum) + static_cast(int_value(x)))); } +}; + +template +struct is_negative +{ + bool operator()(const T& x) const { return int_value(x) < 0; } +}; + +template +struct counter +{ + int n; + counter() : n(0) {} + T operator()() { return T(n++); } +}; + +////////////////////////////////////////////////////////////////////////////// +// C++03 fallbacks for C++11-only functions +////////////////////////////////////////////////////////////////////////////// + +namespace bench_detail { + +template +OutIt copy_if(InIt first, InIt last, OutIt d_first, Pred pred) +{ + for (; first != last; ++first) + if (pred(*first)) + *d_first++ = *first; + return d_first; +} + +template +OutIt copy_n(InIt first, Size count, OutIt result) +{ + for (Size i = 0; i < count; ++i, ++first, ++result) + *result = *first; + return result; +} + +template +bool is_sorted(FwdIt first, FwdIt last) +{ + if (first == last) return true; + FwdIt next = first; + for (++next; next != last; first = next, ++next) + if (*next < *first) return false; + return true; +} + +template +bool is_partitioned(InIt first, InIt last, Pred pred) +{ + for (; first != last; ++first) + if (!pred(*first)) break; + for (; first != last; ++first) + if (pred(*first)) return false; + return true; +} + +template +std::pair +partition_copy(InIt first, InIt last, + OutIt1 out_true, OutIt2 out_false, Pred pred) +{ + for (; first != last; ++first) { + if (pred(*first)) + *out_true++ = *first; + else + *out_false++ = *first; + } + return std::pair(out_true, out_false); +} + +} // namespace bench_detail + +////////////////////////////////////////////////////////////////////////////// +// Fill helpers +////////////////////////////////////////////////////////////////////////////// + +template +void fill_test_data(C& c, std::size_t n) +{ + typedef typename C::value_type VT; + for (std::size_t i = 0; i < n; ++i) + c.push_back(VT(static_cast(i))); +} + +template +void fill_test_data(bc::nest& c, std::size_t n) +{ + for (std::size_t i = 0; i < n; ++i) + c.insert(T(static_cast(i))); +} + +////////////////////////////////////////////////////////////////////////////// +// Benchmark helpers +////////////////////////////////////////////////////////////////////////////// + +inline double calc_ns_per_elem(nanosecond_type ns, + std::size_t iters, std::size_t elems) +{ + return double(ns) / double(iters * elems); +} + +inline void print_ratio(const char* algo, const char* cname, + double std_ns, double seg_ns) +{ + double ratio = (seg_ns > 0.0) ? std_ns / seg_ns : 0.0; + std::cout << std::left << std::setw(24) << algo + << std::setw(14) << cname + << std::right << std::setw(10) << std::fixed << std::setprecision(2) + << ratio << "x\n"; +} + +////////////////////////////////////////////////////////////////////////////// +// Individual benchmarks +////////////////////////////////////////////////////////////////////////////// + +template +void bench_for_each(C& c, std::size_t iters, const char* cname) +{ + typedef typename C::value_type VT; + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + summer s; + s = std::for_each(c.begin(), c.end(), s); + result = s.sum; + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + summer s; + s = bc::segmented_for_each(c.begin(), c.end(), s); + result = s.sum; + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio("for_each", cname, r1, r2); +} + +template +void bench_copy(C& c, std::size_t iters, const char* cname) +{ + typedef typename C::value_type VT; + std::vector out(c.size()); + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + std::copy(c.begin(), c.end(), out.begin()); + t1.stop(); + } + escape(&out[0]); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_copy(c.begin(), c.end(), out.begin()); + t2.stop(); + } + escape(&out[0]); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio("copy", cname, r1, r2); +} + +template +void bench_copy_if(C& c, std::size_t iters, const char* cname) +{ + typedef typename C::value_type VT; + std::vector out(c.size()); + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + bench_detail::copy_if(c.begin(), c.end(), out.begin(), is_odd()); + t1.stop(); + } + escape(&out[0]); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_copy_if(c.begin(), c.end(), out.begin(), is_odd()); + t2.stop(); + } + escape(&out[0]); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio("copy_if", cname, r1, r2); +} + +template +void bench_fill(C& c, std::size_t iters, const char* cname) +{ + typedef typename C::value_type VT; + VT val(42); + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + std::fill(c.begin(), c.end(), val); + t1.stop(); + } + escape(&val); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_fill(c.begin(), c.end(), val); + t2.stop(); + } + escape(&val); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio("fill", cname, r1, r2); +} + +template +void bench_count(C& c, std::size_t iters, const char* cname, + const typename C::value_type& val, const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + result = static_cast(std::count(c.begin(), c.end(), val)); + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + result = static_cast(bc::segmented_count(c.begin(), c.end(), val)); + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_count_if(C& c, std::size_t iters, const char* cname, + Pred pred, const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + result = static_cast(std::count_if(c.begin(), c.end(), pred)); + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + result = static_cast(bc::segmented_count_if(c.begin(), c.end(), pred)); + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_find(C& c, std::size_t iters, const char* cname, + const typename C::value_type& val, const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + typename C::iterator it = std::find(c.begin(), c.end(), val); + result = (it == c.end()) ? 0 : 1; + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + typename C::iterator it = bc::segmented_find(c.begin(), c.end(), val); + result = (it == c.end()) ? 0 : 1; + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_find_if(C& c, std::size_t iters, const char* cname, + Pred pred, const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + typename C::iterator it = std::find_if(c.begin(), c.end(), pred); + result = (it != c.end()) ? int_value(*it) : -1; + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + typename C::iterator it = bc::segmented_find_if(c.begin(), c.end(), pred); + result = (it != c.end()) ? int_value(*it) : -1; + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_equal(C& c, C& c2, std::size_t iters, const char* cname, + const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + result = std::equal(c.begin(), c.end(), c2.begin()) ? 1 : 0; + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + result = bc::segmented_equal(c.begin(), c.end(), c2.begin()) ? 1 : 0; + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_replace(C& c, std::size_t iters, const char* cname, + const typename C::value_type& old_val, + const typename C::value_type& new_val, const char* label) +{ + typedef typename C::value_type VT; + VT v = *c.begin(); + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + std::replace(c.begin(), c.end(), old_val, new_val); + t1.stop(); + } + escape(&v); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_replace(c.begin(), c.end(), old_val, new_val); + t2.stop(); + } + escape(&v); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_replace_if(C& c, std::size_t iters, const char* cname, + Pred pred, const typename C::value_type& new_val, + const char* label) +{ + typedef typename C::value_type VT; + VT v = *c.begin(); + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + std::replace_if(c.begin(), c.end(), pred, new_val); + t1.stop(); + } + escape(&v); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_replace_if(c.begin(), c.end(), pred, new_val); + t2.stop(); + } + escape(&v); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_transform(C& c, std::size_t iters, const char* cname) +{ + typedef typename C::value_type VT; + std::vector out(c.size()); + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + std::transform(c.begin(), c.end(), out.begin(), add_one()); + t1.stop(); + } + escape(&out[0]); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_transform(c.begin(), c.end(), out.begin(), add_one()); + t2.stop(); + } + escape(&out[0]); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio("transform", cname, r1, r2); +} + +template +void bench_fill_n(C& c, std::size_t iters, const char* cname) +{ + typedef typename C::value_type VT; + VT val(42); + typename C::difference_type n = + static_cast(c.size()); + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + std::fill_n(c.begin(), n, val); + t1.stop(); + } + escape(&val); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_fill_n(c.begin(), n, val); + t2.stop(); + } + escape(&val); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio("fill_n", cname, r1, r2); +} + +template +void bench_copy_n(C& c, std::size_t iters, const char* cname) +{ + typedef typename C::value_type VT; + std::vector out(c.size()); + typename C::difference_type n = + static_cast(c.size()); + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + bench_detail::copy_n(c.begin(), n, out.begin()); + t1.stop(); + } + escape(&out[0]); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_copy_n(c.begin(), n, out.begin()); + t2.stop(); + } + escape(&out[0]); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio("copy_n", cname, r1, r2); +} + +template +void bench_generate(C& c, std::size_t iters, const char* cname) +{ + typedef typename C::value_type VT; + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + std::generate(c.begin(), c.end(), counter()); + result = int_value(*c.begin()); + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_generate(c.begin(), c.end(), counter()); + result = int_value(*c.begin()); + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio("generate", cname, r1, r2); +} + +template +void bench_generate_n(C& c, std::size_t iters, const char* cname) +{ + typedef typename C::value_type VT; + int result = 0; + typename C::difference_type n = + static_cast(c.size()); + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + std::generate_n(c.begin(), n, counter()); + result = int_value(*c.begin()); + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_generate_n(c.begin(), n, counter()); + result = int_value(*c.begin()); + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio("generate_n", cname, r1, r2); +} + +template +void bench_remove(C& c, std::size_t iters, const char* cname, + const typename C::value_type& val, const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + typename C::iterator it = std::remove(c.begin(), c.end(), val); + result = (it == c.end()) ? 1 : 0; + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + typename C::iterator it = bc::segmented_remove(c.begin(), c.end(), val); + result = (it == c.end()) ? 1 : 0; + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_remove_if(C& c, std::size_t iters, const char* cname, + Pred pred, const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + typename C::iterator it = std::remove_if(c.begin(), c.end(), pred); + result = (it == c.end()) ? 1 : 0; + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + typename C::iterator it = bc::segmented_remove_if(c.begin(), c.end(), pred); + result = (it == c.end()) ? 1 : 0; + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_remove_copy(C& c, std::size_t iters, const char* cname, + const typename C::value_type& val, const char* label) +{ + typedef typename C::value_type VT; + std::vector out(c.size()); + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + std::remove_copy(c.begin(), c.end(), out.begin(), val); + t1.stop(); + } + escape(&out[0]); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_remove_copy(c.begin(), c.end(), out.begin(), val); + t2.stop(); + } + escape(&out[0]); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_remove_copy_if(C& c, std::size_t iters, const char* cname, + Pred pred, const char* label) +{ + typedef typename C::value_type VT; + std::vector out(c.size()); + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + std::remove_copy_if(c.begin(), c.end(), out.begin(), pred); + t1.stop(); + } + escape(&out[0]); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_remove_copy_if(c.begin(), c.end(), out.begin(), pred); + t2.stop(); + } + escape(&out[0]); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_reverse(C& c, std::size_t iters, const char* cname) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + std::reverse(c.begin(), c.end()); + result = int_value(*c.begin()); + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_reverse(c.begin(), c.end()); + result = int_value(*c.begin()); + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio("reverse", cname, r1, r2); +} + +template +void bench_reverse_copy(C& c, std::size_t iters, const char* cname) +{ + typedef typename C::value_type VT; + std::vector out(c.size()); + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + std::reverse_copy(c.begin(), c.end(), out.begin()); + t1.stop(); + } + escape(&out[0]); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_reverse_copy(c.begin(), c.end(), out.begin()); + t2.stop(); + } + escape(&out[0]); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio("reverse_copy", cname, r1, r2); +} + +template +void bench_is_sorted(C& c, std::size_t iters, const char* cname, + const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + result = bench_detail::is_sorted(c.begin(), c.end()) ? 1 : 0; + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + result = bc::segmented_is_sorted(c.begin(), c.end()) ? 1 : 0; + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_is_partitioned(C& c, std::size_t iters, const char* cname, + Pred pred, const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + result = bench_detail::is_partitioned(c.begin(), c.end(), pred) ? 1 : 0; + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + result = bc::segmented_is_partitioned(c.begin(), c.end(), pred) ? 1 : 0; + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_swap_ranges(C& c, std::size_t iters, const char* cname) +{ + C c2(c); + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + std::swap_ranges(c.begin(), c.end(), c2.begin()); + result = int_value(*c.begin()); + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_swap_ranges(c.begin(), c.end(), c2.begin()); + result = int_value(*c.begin()); + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio("swap_ranges", cname, r1, r2); +} + +template +void bench_search(C& c, std::size_t iters, const char* cname, + const typename C::value_type* pattern, std::size_t pat_size, + const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + typename C::iterator it = std::search(c.begin(), c.end(), pattern, pattern + pat_size); + result = (it == c.end()) ? 0 : 1; + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + typename C::iterator it = bc::segmented_search(c.begin(), c.end(), pattern, pattern + pat_size); + result = (it == c.end()) ? 0 : 1; + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_search_n(C& c, std::size_t iters, const char* cname, + typename C::difference_type count, + const typename C::value_type& val, const char* label) +{ + int result = 0; + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + typename C::iterator it = std::search_n(c.begin(), c.end(), count, val); + result = (it == c.end()) ? 0 : 1; + t1.stop(); + } + escape(&result); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + typename C::iterator it = bc::segmented_search_n(c.begin(), c.end(), count, val); + result = (it == c.end()) ? 0 : 1; + t2.stop(); + } + escape(&result); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio(label, cname, r1, r2); +} + +template +void bench_partition_copy(C& c, std::size_t iters, const char* cname) +{ + typedef typename C::value_type VT; + std::vector t_out(c.size()); + std::vector f_out(c.size()); + + cpu_timer t1; + for (std::size_t i = 0; i < iters; ++i) { + t1.resume(); + bench_detail::partition_copy(c.begin(), c.end(), + t_out.begin(), f_out.begin(), is_odd()); + t1.stop(); + } + escape(&t_out[0]); + escape(&f_out[0]); + double r1 = calc_ns_per_elem(t1.elapsed().wall, iters, c.size()); + + cpu_timer t2; + for (std::size_t i = 0; i < iters; ++i) { + t2.resume(); + bc::segmented_partition_copy(c.begin(), c.end(), + t_out.begin(), f_out.begin(), is_odd()); + t2.stop(); + } + escape(&t_out[0]); + escape(&f_out[0]); + double r2 = calc_ns_per_elem(t2.elapsed().wall, iters, c.size()); + print_ratio("partition_copy", cname, r1, r2); +} + +////////////////////////////////////////////////////////////////////////////// +// Run all benchmarks for a container type +////////////////////////////////////////////////////////////////////////////// + +template +void run_all(C& c, std::size_t iters, const char* cname) +{ + typedef typename C::value_type VT; + + bench_for_each(c, iters, cname); + bench_copy(c, iters, cname); + bench_copy_if(c, iters, cname); + bench_copy_n(c, iters, cname); + bench_fill(c, iters, cname); + bench_fill_n(c, iters, cname); + bench_generate(c, iters, cname); + bench_generate_n(c, iters, cname); + + bench_count(c, iters, cname, VT(-1), "count(miss)"); + bench_count(c, iters, cname, VT(0), "count(hit)"); + bench_count_if(c, iters, cname, is_odd(), "count_if(hit)"); + bench_count_if(c, iters, cname, is_negative(), "count_if(miss)"); + + bench_find(c, iters, cname, VT(-1), "find(miss)"); + bench_find(c, iters, cname, VT(static_cast(c.size() / 2)), "find(hit)"); + bench_find_if(c, iters, cname, is_odd(), "find_if(hit)"); + bench_find_if(c, iters, cname, is_negative(), "find_if(miss)"); + + { + C c2(c); + bench_equal(c, c2, iters, cname, "equal(hit)"); + typename C::iterator last = c2.end(); + --last; + *last = VT(-1); + bench_equal(c, c2, iters, cname, "equal(miss)"); + } + + { + VT miss_pat[] = {VT(-1), VT(-2), VT(-3)}; + bench_search(c, iters, cname, miss_pat, 3, "search(miss)"); + int half = static_cast(c.size() / 2); + VT hit_pat[] = {VT(half), VT(half + 1), VT(half + 2)}; + bench_search(c, iters, cname, hit_pat, 3, "search(hit)"); + } + bench_search_n(c, iters, cname, 3, VT(-1), "search_n(miss)"); + bench_search_n(c, iters, cname, 1, VT(static_cast(c.size() / 2)), "search_n(hit)"); + + bench_is_sorted(c, iters, cname, "is_sorted(hit)"); + { + C c2(c); + typename C::iterator last = c2.end(); + --last; + *last = VT(0); + bench_is_sorted(c2, iters, cname, "is_sorted(miss)"); + } + + bench_is_partitioned(c, iters, cname, is_negative(), "is_partitioned(hit)"); + { + C c2(c); + typename C::iterator last = c2.end(); + --last; + *last = VT(-1); + bench_is_partitioned(c2, iters, cname, is_negative(), "is_partitioned(miss)"); + } + + bench_remove(c, iters, cname, VT(-1), "remove(miss)"); + bench_remove(c, iters, cname, VT(0), "remove(hit)"); + bench_remove_if(c, iters, cname, is_negative(), "remove_if(miss)"); + bench_remove_if(c, iters, cname, is_odd(), "remove_if(hit)"); + bench_remove_copy(c, iters, cname, VT(-1), "remove_copy(miss)"); + bench_remove_copy(c, iters, cname, VT(0), "remove_copy(hit)"); + bench_remove_copy_if(c, iters, cname, is_negative(), "remove_copy_if(miss)"); + bench_remove_copy_if(c, iters, cname, is_odd(), "remove_copy_if(hit)"); + + bench_replace(c, iters, cname, VT(-1), VT(-2), "replace(miss)"); + bench_replace(c, iters, cname, VT(0), VT(0), "replace(hit)"); + bench_replace_if(c, iters, cname, is_odd(), VT(-2), "replace_if(hit)"); + bench_replace_if(c, iters, cname, is_negative(), VT(-2), "replace_if(miss)"); + + bench_reverse(c, iters, cname); + bench_reverse_copy(c, iters, cname); + bench_swap_ranges(c, iters, cname); + bench_partition_copy(c, iters, cname); + bench_transform(c, iters, cname); +} + +////////////////////////////////////////////////////////////////////////////// +// Run all benchmarks for a given value type +////////////////////////////////////////////////////////////////////////////// + +template +void run_benchmarks() +{ + #ifdef NDEBUG + const std::size_t N = 100000; + const std::size_t iter = 500; + #else + const std::size_t N = 10000; + const std::size_t iter = 10; + #endif + + std::cout << "\n=== Segmented algorithm benchmark [" << typeid(T).name() << "] ===\n" + << "Elements: " << N << " Iterations: " << iter << "\n\n"; + + { + std::cout << "--- bc::deque<" << typeid(T).name() << "> ---\n"; + bc::deque dq; + fill_test_data(dq, N); + run_all(dq, iter, "deque"); + std::cout << "\n"; + } +/* + { + std::cout << "--- bc::nest<" << typeid(T).name() << "> ---\n"; + bc::nest nt; + fill_test_data(nt, N); + run_all(nt, iter, "nest"); + std::cout << "\n"; + }*/ +} + +////////////////////////////////////////////////////////////////////////////// +// Main +////////////////////////////////////////////////////////////////////////////// + +int main() +{ + //run_benchmarks(); + run_benchmarks(); + //run_benchmarks(); + return 0; +}