From 9ae52f4845bc7489de3390c79074b5c73f85a7f6 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Sat, 15 Feb 2025 15:42:31 +0100 Subject: [PATCH 1/6] [libc++] Add benchmarks for copy algorithms This patch adds benchmarks for the copy family of algorithms (copy, copy_n, copy_if, copy_backward). --- .../test/benchmarks/algorithms/copy.bench.cpp | 89 --------------- .../algorithms/copy_backward.bench.cpp | 55 --------- .../algorithms/modifying/copy.bench.cpp | 84 ++++++++++++++ .../modifying/copy_backward.bench.cpp | 86 ++++++++++++++ .../algorithms/modifying/copy_if.bench.cpp | 105 ++++++++++++++++++ .../algorithms/modifying/copy_n.bench.cpp | 83 ++++++++++++++ 6 files changed, 358 insertions(+), 144 deletions(-) delete mode 100644 libcxx/test/benchmarks/algorithms/copy.bench.cpp delete mode 100644 libcxx/test/benchmarks/algorithms/copy_backward.bench.cpp create mode 100644 libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp create mode 100644 libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp create mode 100644 libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp create mode 100644 libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp diff --git a/libcxx/test/benchmarks/algorithms/copy.bench.cpp b/libcxx/test/benchmarks/algorithms/copy.bench.cpp deleted file mode 100644 index b6f0f15eb7703..0000000000000 --- a/libcxx/test/benchmarks/algorithms/copy.bench.cpp +++ /dev/null @@ -1,89 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -#include -#include -#include - -static void bm_ranges_copy_vb(benchmark::State& state, bool aligned) { - auto n = state.range(); - std::vector in(n, true); - std::vector out(aligned ? n : n + 8); - benchmark::DoNotOptimize(&in); - auto dst = aligned ? out.begin() : out.begin() + 4; - for (auto _ : state) { - benchmark::DoNotOptimize(std::ranges::copy(in, dst)); - benchmark::DoNotOptimize(&out); - } -} - -static void bm_ranges_copy_n_vb(benchmark::State& state, bool aligned) { - auto n = state.range(); - std::vector in(n, true); - std::vector out(aligned ? n : n + 8); - benchmark::DoNotOptimize(&in); - auto src = in.begin(); - auto dst = aligned ? out.begin() : out.begin() + 4; - for (auto _ : state) { - benchmark::DoNotOptimize(std::ranges::copy_n(src, n, dst)); - benchmark::DoNotOptimize(&out); - } -} - -static void bm_copy_vb(benchmark::State& state, bool aligned) { - auto n = state.range(); - std::vector in(n, true); - std::vector out(aligned ? n : n + 8); - benchmark::DoNotOptimize(&in); - auto beg = in.begin(); - auto end = in.end(); - auto dst = aligned ? out.begin() : out.begin() + 4; - for (auto _ : state) { - benchmark::DoNotOptimize(std::copy(beg, end, dst)); - benchmark::DoNotOptimize(&out); - } -} - -static void bm_copy_n_vb(benchmark::State& state, bool aligned) { - auto n = state.range(); - std::vector in(n, true); - std::vector out(aligned ? n : n + 8); - benchmark::DoNotOptimize(&in); - auto src = in.begin(); - auto dst = aligned ? out.begin() : out.begin() + 4; - for (auto _ : state) { - benchmark::DoNotOptimize(std::copy_n(src, n, dst)); - benchmark::DoNotOptimize(&out); - } -} - -static void bm_ranges_copy_vb_aligned(benchmark::State& state) { bm_ranges_copy_vb(state, true); } -static void bm_ranges_copy_vb_unaligned(benchmark::State& state) { bm_ranges_copy_vb(state, false); } -static void bm_ranges_copy_n_vb_aligned(benchmark::State& state) { bm_ranges_copy_n_vb(state, true); } -static void bm_ranges_copy_n_vb_unaligned(benchmark::State& state) { bm_ranges_copy_n_vb(state, false); } - -static void bm_copy_vb_aligned(benchmark::State& state) { bm_copy_vb(state, true); } -static void bm_copy_vb_unaligned(benchmark::State& state) { bm_copy_vb(state, false); } -static void bm_copy_n_vb_aligned(benchmark::State& state) { bm_copy_n_vb(state, true); } -static void bm_copy_n_vb_unaligned(benchmark::State& state) { bm_copy_n_vb(state, false); } - -// Test std::ranges::copy for vector::iterator -BENCHMARK(bm_ranges_copy_vb_aligned)->Range(8, 1 << 16)->DenseRange(102400, 204800, 4096); -BENCHMARK(bm_ranges_copy_n_vb_aligned)->Range(8, 1 << 20); -BENCHMARK(bm_ranges_copy_vb_unaligned)->Range(8, 1 << 20); -BENCHMARK(bm_ranges_copy_n_vb_unaligned)->Range(8, 1 << 20); - -// Test std::copy for vector::iterator -BENCHMARK(bm_copy_vb_aligned)->Range(8, 1 << 20); -BENCHMARK(bm_copy_n_vb_aligned)->Range(8, 1 << 20); -BENCHMARK(bm_copy_vb_unaligned)->Range(8, 1 << 20); -BENCHMARK(bm_copy_n_vb_unaligned)->Range(8, 1 << 20); - -BENCHMARK_MAIN(); diff --git a/libcxx/test/benchmarks/algorithms/copy_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/copy_backward.bench.cpp deleted file mode 100644 index c943d9a874b49..0000000000000 --- a/libcxx/test/benchmarks/algorithms/copy_backward.bench.cpp +++ /dev/null @@ -1,55 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -#include -#include -#include - -static void bm_ranges_copy_backward_vb(benchmark::State& state, bool aligned) { - auto n = state.range(); - std::vector in(n, true); - std::vector out(aligned ? n : n + 8); - benchmark::DoNotOptimize(&in); - auto dst = aligned ? out.end() : out.end() - 4; - for (auto _ : state) { - benchmark::DoNotOptimize(std::ranges::copy_backward(in, dst)); - benchmark::DoNotOptimize(&out); - } -} - -static void bm_copy_backward_vb(benchmark::State& state, bool aligned) { - auto n = state.range(); - std::vector in(n, true); - std::vector out(aligned ? n : n + 8); - benchmark::DoNotOptimize(&in); - auto beg = in.begin(); - auto end = in.end(); - auto dst = aligned ? out.end() : out.end() - 4; - for (auto _ : state) { - benchmark::DoNotOptimize(std::copy_backward(beg, end, dst)); - benchmark::DoNotOptimize(&out); - } -} - -static void bm_ranges_copy_backward_vb_aligned(benchmark::State& state) { bm_ranges_copy_backward_vb(state, true); } -static void bm_ranges_copy_backward_vb_unaligned(benchmark::State& state) { bm_ranges_copy_backward_vb(state, false); } - -static void bm_copy_backward_vb_aligned(benchmark::State& state) { bm_copy_backward_vb(state, true); } -static void bm_copy_backward_vb_unaligned(benchmark::State& state) { bm_copy_backward_vb(state, false); } - -// Test std::ranges::copy_backward for vector::iterator -BENCHMARK(bm_ranges_copy_backward_vb_aligned)->Range(8, 1 << 16)->DenseRange(102400, 204800, 4096); -BENCHMARK(bm_ranges_copy_backward_vb_unaligned)->Range(8, 1 << 20); - -// Test std::copy_backward for vector::iterator -BENCHMARK(bm_copy_backward_vb_aligned)->Range(8, 1 << 20); -BENCHMARK(bm_copy_backward_vb_unaligned)->Range(8, 1 << 20); - -BENCHMARK_MAIN(); diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp new file mode 100644 index 0000000000000..dea1e9f5d7c34 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +#include +#include +#include +#include +#include +#include + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +template +void bm_general(std::string operation_name, Operation copy) { + auto bench = [copy](auto& st) { + auto const size = st.range(0); + using ValueType = typename Container::value_type; + Container c; + std::generate_n(std::back_inserter(c), size, [] { return Generate::random(); }); + + std::vector out(size); + + for ([[maybe_unused]] auto _ : st) { + auto result = copy(c.begin(), c.end(), out.begin()); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(out); + benchmark::DoNotOptimize(c); + benchmark::ClobberMemory(); + } + }; + benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); +} + +template +static void bm_vector_bool(std::string operation_name, Operation copy) { + auto bench = [copy](auto& st) { + auto n = st.range(); + std::vector in(n, true); + std::vector out(Aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto first = in.begin(); + auto last = in.end(); + auto dst = Aligned ? out.begin() : out.begin() + 4; + for ([[maybe_unused]] auto _ : st) { + auto result = copy(first, last, dst); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(out); + benchmark::ClobberMemory(); + } + }; + benchmark::RegisterBenchmark(operation_name, bench)->Range(64, 1 << 20); +} + +int main(int argc, char** argv) { + auto std_copy = [](auto first, auto last, auto out) { return std::copy(first, last, out); }; + auto ranges_copy = [](auto first, auto last, auto out) { return std::ranges::copy(first, last, out); }; + + // std::copy + bm_general>("std::copy(vector)", std_copy); + bm_general>("std::copy(deque)", std_copy); + bm_general>("std::copy(list)", std_copy); + bm_vector_bool("std::copy(vector) (aligned)", std_copy); + bm_vector_bool("std::copy(vector) (unaligned)", std_copy); + + // ranges::copy + bm_general>("ranges::copy(vector)", ranges_copy); + bm_general>("ranges::copy(deque)", ranges_copy); + bm_general>("ranges::copy(list)", ranges_copy); + bm_vector_bool("ranges::copy(vector) (aligned)", ranges_copy); + bm_vector_bool("ranges::copy(vector) (unaligned)", ranges_copy); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp new file mode 100644 index 0000000000000..6f9360533db28 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +#include +#include +#include +#include +#include +#include + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +template +void bm_general(std::string operation_name, Operation copy_backward) { + auto bench = [copy_backward](auto& st) { + auto const size = st.range(0); + using ValueType = typename Container::value_type; + Container c; + std::generate_n(std::back_inserter(c), size, [] { return Generate::random(); }); + + std::vector out(size); + + for ([[maybe_unused]] auto _ : st) { + auto result = copy_backward(c.begin(), c.end(), out.end()); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(out); + benchmark::DoNotOptimize(c); + benchmark::ClobberMemory(); + } + }; + benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); +} + +template +static void bm_vector_bool(std::string operation_name, Operation copy_backward) { + auto bench = [copy_backward](auto& st) { + auto n = st.range(); + std::vector in(n, true); + std::vector out(Aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto first = in.begin(); + auto last = in.end(); + auto dst = Aligned ? out.end() : out.end() - 4; + for ([[maybe_unused]] auto _ : st) { + auto result = copy_backward(first, last, dst); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(out); + benchmark::ClobberMemory(); + } + }; + benchmark::RegisterBenchmark(operation_name, bench)->Range(64, 1 << 20); +} + +int main(int argc, char** argv) { + auto std_copy_backward = [](auto first, auto last, auto out) { return std::copy_backward(first, last, out); }; + auto ranges_copy_backward = [](auto first, auto last, auto out) { + return std::ranges::copy_backward(first, last, out); + }; + + // std::copy + bm_general>("std::copy_backward(vector)", std_copy_backward); + bm_general>("std::copy_backward(deque)", std_copy_backward); + bm_general>("std::copy_backward(list)", std_copy_backward); + bm_vector_bool("std::copy_backward(vector) (aligned)", std_copy_backward); + bm_vector_bool("std::copy_backward(vector) (unaligned)", std_copy_backward); + + // ranges::copy + bm_general>("ranges::copy_backward(vector)", ranges_copy_backward); + bm_general>("ranges::copy_backward(deque)", ranges_copy_backward); + bm_general>("ranges::copy_backward(list)", ranges_copy_backward); + bm_vector_bool("ranges::copy_backward(vector) (aligned)", ranges_copy_backward); + bm_vector_bool("ranges::copy_backward(vector) (unaligned)", ranges_copy_backward); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp new file mode 100644 index 0000000000000..8a298c703e4e8 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +#include +#include +#include +#include +#include +#include + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +// Benchmark copying one out of two element, in alternance. This is basically +// the worst case for this algorithm, I don't think there are many optimizations +// that can be applied in this case. +template +void bm_copy_every_other_element(std::string operation_name, Operation copy_if) { + auto bench = [copy_if](auto& st) { + auto const size = st.range(0); + using ValueType = typename Container::value_type; + Container c; + std::generate_n(std::back_inserter(c), size, [] { return Generate::random(); }); + + std::vector out(size); + + for ([[maybe_unused]] auto _ : st) { + bool do_copy = false; + auto pred = [&do_copy](auto& element) { + benchmark::DoNotOptimize(element); + do_copy = !do_copy; + return do_copy; + }; + auto result = copy_if(c.begin(), c.end(), out.begin(), pred); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(out); + benchmark::DoNotOptimize(c); + benchmark::ClobberMemory(); + } + }; + benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); +} + +// Copy the full range. +template +void bm_copy_entire_range(std::string operation_name, Operation copy_if) { + auto bench = [copy_if](auto& st) { + auto const size = st.range(0); + using ValueType = typename Container::value_type; + Container c; + std::generate_n(std::back_inserter(c), size, [] { return Generate::random(); }); + + std::vector out(size); + + for ([[maybe_unused]] auto _ : st) { + auto pred = [](auto& element) { + benchmark::DoNotOptimize(element); + return true; + }; + auto result = copy_if(c.begin(), c.end(), out.begin(), pred); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(out); + benchmark::DoNotOptimize(c); + benchmark::ClobberMemory(); + } + }; + benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); +} + +int main(int argc, char** argv) { + auto std_copy_if = [](auto first, auto last, auto out, auto pred) { return std::copy_if(first, last, out, pred); }; + auto ranges_copy_if = [](auto first, auto last, auto out, auto pred) { + return std::ranges::copy_if(first, last, out, pred); + }; + + // std::copy_if + bm_copy_every_other_element>("std::copy_if(vector) (every other)", std_copy_if); + bm_copy_every_other_element>("std::copy_if(deque) (every other)", std_copy_if); + bm_copy_every_other_element>("std::copy_if(list) (every other)", std_copy_if); + + bm_copy_entire_range>("std::copy_if(vector) (entire range)", std_copy_if); + bm_copy_entire_range>("std::copy_if(deque) (entire range)", std_copy_if); + bm_copy_entire_range>("std::copy_if(list) (entire range)", std_copy_if); + + // ranges::copy + bm_copy_every_other_element>("ranges::copy_if(vector) (every other)", ranges_copy_if); + bm_copy_every_other_element>("ranges::copy_if(deque) (every other)", ranges_copy_if); + bm_copy_every_other_element>("ranges::copy_if(list) (every other)", ranges_copy_if); + + bm_copy_entire_range>("ranges::copy_if(vector) (entire range)", ranges_copy_if); + bm_copy_entire_range>("ranges::copy_if(deque) (entire range)", ranges_copy_if); + bm_copy_entire_range>("ranges::copy_if(list) (entire range)", ranges_copy_if); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp new file mode 100644 index 0000000000000..f4eb98f91df1c --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +#include +#include +#include +#include +#include +#include + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +template +void bm_general(std::string operation_name, Operation copy_n) { + auto bench = [copy_n](auto& st) { + auto const size = st.range(0); + using ValueType = typename Container::value_type; + Container c; + std::generate_n(std::back_inserter(c), size, [] { return Generate::random(); }); + + std::vector out(size); + + for ([[maybe_unused]] auto _ : st) { + auto result = copy_n(c.begin(), size, out.begin()); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(out); + benchmark::DoNotOptimize(c); + benchmark::ClobberMemory(); + } + }; + benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); +} + +template +static void bm_vector_bool(std::string operation_name, Operation copy_n) { + auto bench = [copy_n](auto& st) { + auto n = st.range(); + std::vector in(n, true); + std::vector out(Aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto first = in.begin(); + auto dst = Aligned ? out.begin() : out.begin() + 4; + for ([[maybe_unused]] auto _ : st) { + auto result = copy_n(first, n, dst); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(out); + benchmark::ClobberMemory(); + } + }; + benchmark::RegisterBenchmark(operation_name, bench)->Range(64, 1 << 20); +} + +int main(int argc, char** argv) { + auto std_copy_n = [](auto first, auto n, auto out) { return std::copy_n(first, n, out); }; + auto ranges_copy_n = [](auto first, auto n, auto out) { return std::ranges::copy_n(first, n, out); }; + + // std::copy_n + bm_general>("std::copy_n(vector)", std_copy_n); + bm_general>("std::copy_n(deque)", std_copy_n); + bm_general>("std::copy_n(list)", std_copy_n); + bm_vector_bool("std::copy_n(vector) (aligned)", std_copy_n); + bm_vector_bool("std::copy_n(vector) (unaligned)", std_copy_n); + + // ranges::copy_n + bm_general>("ranges::copy_n(vector)", ranges_copy_n); + bm_general>("ranges::copy_n(deque)", ranges_copy_n); + bm_general>("ranges::copy_n(list)", ranges_copy_n); + bm_vector_bool("ranges::copy_n(vector) (aligned)", ranges_copy_n); + bm_vector_bool("ranges::copy_n(vector) (unaligned)", ranges_copy_n); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} From 76b025a1f79c71b1af5462bc7a0bdee094af8c4b Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Sun, 16 Feb 2025 00:49:16 +0100 Subject: [PATCH 2/6] Guard for lack of output_iterator-nesss --- libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp | 3 +++ .../benchmarks/algorithms/modifying/copy_backward.bench.cpp | 3 +++ libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp | 3 +++ 3 files changed, 9 insertions(+) diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp index dea1e9f5d7c34..a3db7dce1bde5 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp @@ -17,6 +17,7 @@ #include "benchmark/benchmark.h" #include "../../GenerateInput.h" +#include "test_macros.h" template void bm_general(std::string operation_name, Operation copy) { @@ -74,8 +75,10 @@ int main(int argc, char** argv) { bm_general>("ranges::copy(vector)", ranges_copy); bm_general>("ranges::copy(deque)", ranges_copy); bm_general>("ranges::copy(list)", ranges_copy); +#if TEST_STD_VER >= 23 // vector::iterator is not an output_iterator before C++23 bm_vector_bool("ranges::copy(vector) (aligned)", ranges_copy); bm_vector_bool("ranges::copy(vector) (unaligned)", ranges_copy); +#endif benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp index 6f9360533db28..b9adb24ad5964 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp @@ -17,6 +17,7 @@ #include "benchmark/benchmark.h" #include "../../GenerateInput.h" +#include "test_macros.h" template void bm_general(std::string operation_name, Operation copy_backward) { @@ -76,8 +77,10 @@ int main(int argc, char** argv) { bm_general>("ranges::copy_backward(vector)", ranges_copy_backward); bm_general>("ranges::copy_backward(deque)", ranges_copy_backward); bm_general>("ranges::copy_backward(list)", ranges_copy_backward); +#if TEST_STD_VER >= 23 // vector::iterator is not an output_iterator before C++23 bm_vector_bool("ranges::copy_backward(vector) (aligned)", ranges_copy_backward); bm_vector_bool("ranges::copy_backward(vector) (unaligned)", ranges_copy_backward); +#endif benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp index f4eb98f91df1c..c95dd327fc01c 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp @@ -17,6 +17,7 @@ #include "benchmark/benchmark.h" #include "../../GenerateInput.h" +#include "test_macros.h" template void bm_general(std::string operation_name, Operation copy_n) { @@ -73,8 +74,10 @@ int main(int argc, char** argv) { bm_general>("ranges::copy_n(vector)", ranges_copy_n); bm_general>("ranges::copy_n(deque)", ranges_copy_n); bm_general>("ranges::copy_n(list)", ranges_copy_n); +#if TEST_STD_VER >= 23 // vector::iterator is not an output_iterator before C++23 bm_vector_bool("ranges::copy_n(vector) (aligned)", ranges_copy_n); bm_vector_bool("ranges::copy_n(vector) (unaligned)", ranges_copy_n); +#endif benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); From b2122045f0e2d04a09471ca985fb31514155335f Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 18 Feb 2025 15:30:42 -0500 Subject: [PATCH 3/6] Use ranges CPOs directly --- libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp | 2 +- .../benchmarks/algorithms/modifying/copy_backward.bench.cpp | 4 +--- libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp | 4 +--- libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp | 2 +- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp index a3db7dce1bde5..3daebcc0240f6 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp @@ -62,7 +62,7 @@ static void bm_vector_bool(std::string operation_name, Operation copy) { int main(int argc, char** argv) { auto std_copy = [](auto first, auto last, auto out) { return std::copy(first, last, out); }; - auto ranges_copy = [](auto first, auto last, auto out) { return std::ranges::copy(first, last, out); }; + auto ranges_copy = std::ranges::copy; // std::copy bm_general>("std::copy(vector)", std_copy); diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp index b9adb24ad5964..ca5ea7fd279bd 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp @@ -62,9 +62,7 @@ static void bm_vector_bool(std::string operation_name, Operation copy_backward) int main(int argc, char** argv) { auto std_copy_backward = [](auto first, auto last, auto out) { return std::copy_backward(first, last, out); }; - auto ranges_copy_backward = [](auto first, auto last, auto out) { - return std::ranges::copy_backward(first, last, out); - }; + auto ranges_copy_backward = std::ranges::copy_backward; // std::copy bm_general>("std::copy_backward(vector)", std_copy_backward); diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp index 8a298c703e4e8..e9cb9ab08ce1a 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp @@ -76,9 +76,7 @@ void bm_copy_entire_range(std::string operation_name, Operation copy_if) { int main(int argc, char** argv) { auto std_copy_if = [](auto first, auto last, auto out, auto pred) { return std::copy_if(first, last, out, pred); }; - auto ranges_copy_if = [](auto first, auto last, auto out, auto pred) { - return std::ranges::copy_if(first, last, out, pred); - }; + auto ranges_copy_if = std::ranges::copy_if; // std::copy_if bm_copy_every_other_element>("std::copy_if(vector) (every other)", std_copy_if); diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp index c95dd327fc01c..7a047c86369ab 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp @@ -61,7 +61,7 @@ static void bm_vector_bool(std::string operation_name, Operation copy_n) { int main(int argc, char** argv) { auto std_copy_n = [](auto first, auto n, auto out) { return std::copy_n(first, n, out); }; - auto ranges_copy_n = [](auto first, auto n, auto out) { return std::ranges::copy_n(first, n, out); }; + auto ranges_copy_n = std::ranges::copy_n; // std::copy_n bm_general>("std::copy_n(vector)", std_copy_n); From d672c6dc52a1c2e15ac34ff5d617f95211bdf2f9 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 19 Feb 2025 09:36:11 -0500 Subject: [PATCH 4/6] Fix uses of ClobberMemory --- .../algorithms/modifying/copy.bench.cpp | 21 +++++++-------- .../modifying/copy_backward.bench.cpp | 20 +++++++------- .../algorithms/modifying/copy_if.bench.cpp | 27 +++++++++---------- .../algorithms/modifying/copy_n.bench.cpp | 23 ++++++++-------- 4 files changed, 44 insertions(+), 47 deletions(-) diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp index 3daebcc0240f6..2ec09c3c0d056 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp @@ -9,6 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 #include +#include #include #include #include @@ -22,19 +23,18 @@ template void bm_general(std::string operation_name, Operation copy) { auto bench = [copy](auto& st) { - auto const size = st.range(0); - using ValueType = typename Container::value_type; + std::size_t const n = st.range(0); + using ValueType = typename Container::value_type; Container c; - std::generate_n(std::back_inserter(c), size, [] { return Generate::random(); }); + std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); - std::vector out(size); + std::vector out(n); for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); auto result = copy(c.begin(), c.end(), out.begin()); benchmark::DoNotOptimize(result); - benchmark::DoNotOptimize(out); - benchmark::DoNotOptimize(c); - benchmark::ClobberMemory(); } }; benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); @@ -43,18 +43,17 @@ void bm_general(std::string operation_name, Operation copy) { template static void bm_vector_bool(std::string operation_name, Operation copy) { auto bench = [copy](auto& st) { - auto n = st.range(); + std::size_t const n = st.range(0); std::vector in(n, true); std::vector out(Aligned ? n : n + 8); - benchmark::DoNotOptimize(&in); auto first = in.begin(); auto last = in.end(); auto dst = Aligned ? out.begin() : out.begin() + 4; for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(in); + benchmark::DoNotOptimize(out); auto result = copy(first, last, dst); benchmark::DoNotOptimize(result); - benchmark::DoNotOptimize(out); - benchmark::ClobberMemory(); } }; benchmark::RegisterBenchmark(operation_name, bench)->Range(64, 1 << 20); diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp index ca5ea7fd279bd..42265c9e9cd2d 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp @@ -9,6 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 #include +#include #include #include #include @@ -22,19 +23,18 @@ template void bm_general(std::string operation_name, Operation copy_backward) { auto bench = [copy_backward](auto& st) { - auto const size = st.range(0); - using ValueType = typename Container::value_type; + std::size_t const n = st.range(0); + using ValueType = typename Container::value_type; Container c; - std::generate_n(std::back_inserter(c), size, [] { return Generate::random(); }); + std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); - std::vector out(size); + std::vector out(n); for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); auto result = copy_backward(c.begin(), c.end(), out.end()); benchmark::DoNotOptimize(result); - benchmark::DoNotOptimize(out); - benchmark::DoNotOptimize(c); - benchmark::ClobberMemory(); } }; benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); @@ -43,7 +43,7 @@ void bm_general(std::string operation_name, Operation copy_backward) { template static void bm_vector_bool(std::string operation_name, Operation copy_backward) { auto bench = [copy_backward](auto& st) { - auto n = st.range(); + std::size_t const n = st.range(0); std::vector in(n, true); std::vector out(Aligned ? n : n + 8); benchmark::DoNotOptimize(&in); @@ -51,10 +51,10 @@ static void bm_vector_bool(std::string operation_name, Operation copy_backward) auto last = in.end(); auto dst = Aligned ? out.end() : out.end() - 4; for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(in); + benchmark::DoNotOptimize(out); auto result = copy_backward(first, last, dst); benchmark::DoNotOptimize(result); - benchmark::DoNotOptimize(out); - benchmark::ClobberMemory(); } }; benchmark::RegisterBenchmark(operation_name, bench)->Range(64, 1 << 20); diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp index e9cb9ab08ce1a..ac9e42d2d2235 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp @@ -9,6 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 #include +#include #include #include #include @@ -24,12 +25,12 @@ template void bm_copy_every_other_element(std::string operation_name, Operation copy_if) { auto bench = [copy_if](auto& st) { - auto const size = st.range(0); - using ValueType = typename Container::value_type; + std::size_t const n = st.range(0); + using ValueType = typename Container::value_type; Container c; - std::generate_n(std::back_inserter(c), size, [] { return Generate::random(); }); + std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); - std::vector out(size); + std::vector out(n); for ([[maybe_unused]] auto _ : st) { bool do_copy = false; @@ -38,11 +39,10 @@ void bm_copy_every_other_element(std::string operation_name, Operation copy_if) do_copy = !do_copy; return do_copy; }; + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); auto result = copy_if(c.begin(), c.end(), out.begin(), pred); benchmark::DoNotOptimize(result); - benchmark::DoNotOptimize(out); - benchmark::DoNotOptimize(c); - benchmark::ClobberMemory(); } }; benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); @@ -52,23 +52,22 @@ void bm_copy_every_other_element(std::string operation_name, Operation copy_if) template void bm_copy_entire_range(std::string operation_name, Operation copy_if) { auto bench = [copy_if](auto& st) { - auto const size = st.range(0); - using ValueType = typename Container::value_type; + std::size_t const n = st.range(0); + using ValueType = typename Container::value_type; Container c; - std::generate_n(std::back_inserter(c), size, [] { return Generate::random(); }); + std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); - std::vector out(size); + std::vector out(n); for ([[maybe_unused]] auto _ : st) { auto pred = [](auto& element) { benchmark::DoNotOptimize(element); return true; }; + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); auto result = copy_if(c.begin(), c.end(), out.begin(), pred); benchmark::DoNotOptimize(result); - benchmark::DoNotOptimize(out); - benchmark::DoNotOptimize(c); - benchmark::ClobberMemory(); } }; benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp index 7a047c86369ab..ad70b9fb3c7e7 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp @@ -9,6 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 #include +#include #include #include #include @@ -22,19 +23,18 @@ template void bm_general(std::string operation_name, Operation copy_n) { auto bench = [copy_n](auto& st) { - auto const size = st.range(0); - using ValueType = typename Container::value_type; + std::size_t const n = st.range(0); + using ValueType = typename Container::value_type; Container c; - std::generate_n(std::back_inserter(c), size, [] { return Generate::random(); }); + std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); - std::vector out(size); + std::vector out(n); for ([[maybe_unused]] auto _ : st) { - auto result = copy_n(c.begin(), size, out.begin()); - benchmark::DoNotOptimize(result); - benchmark::DoNotOptimize(out); benchmark::DoNotOptimize(c); - benchmark::ClobberMemory(); + benchmark::DoNotOptimize(out); + auto result = copy_n(c.begin(), n, out.begin()); + benchmark::DoNotOptimize(result); } }; benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); @@ -43,17 +43,16 @@ void bm_general(std::string operation_name, Operation copy_n) { template static void bm_vector_bool(std::string operation_name, Operation copy_n) { auto bench = [copy_n](auto& st) { - auto n = st.range(); + std::size_t const n = st.range(0); std::vector in(n, true); std::vector out(Aligned ? n : n + 8); - benchmark::DoNotOptimize(&in); auto first = in.begin(); auto dst = Aligned ? out.begin() : out.begin() + 4; for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(in); + benchmark::DoNotOptimize(out); auto result = copy_n(first, n, dst); benchmark::DoNotOptimize(result); - benchmark::DoNotOptimize(out); - benchmark::ClobberMemory(); } }; benchmark::RegisterBenchmark(operation_name, bench)->Range(64, 1 << 20); From d34de3e0f1c4f8ca40d95e9d8508db64b55d7618 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 19 Feb 2025 10:18:47 -0500 Subject: [PATCH 5/6] Implement consensus with Nikolas --- .../algorithms/modifying/copy.bench.cpp | 101 +++++++------- .../modifying/copy_backward.bench.cpp | 103 +++++++------- .../algorithms/modifying/copy_if.bench.cpp | 130 +++++++++--------- .../algorithms/modifying/copy_n.bench.cpp | 99 +++++++------ 4 files changed, 210 insertions(+), 223 deletions(-) diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp index 2ec09c3c0d056..5c29260f9da37 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp @@ -20,64 +20,61 @@ #include "../../GenerateInput.h" #include "test_macros.h" -template -void bm_general(std::string operation_name, Operation copy) { - auto bench = [copy](auto& st) { - std::size_t const n = st.range(0); - using ValueType = typename Container::value_type; - Container c; - std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); - - std::vector out(n); - - for ([[maybe_unused]] auto _ : st) { - benchmark::DoNotOptimize(c); - benchmark::DoNotOptimize(out); - auto result = copy(c.begin(), c.end(), out.begin()); - benchmark::DoNotOptimize(result); - } - }; - benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); -} +int main(int argc, char** argv) { + auto std_copy = [](auto first, auto last, auto out) { return std::copy(first, last, out); }; -template -static void bm_vector_bool(std::string operation_name, Operation copy) { - auto bench = [copy](auto& st) { - std::size_t const n = st.range(0); - std::vector in(n, true); - std::vector out(Aligned ? n : n + 8); - auto first = in.begin(); - auto last = in.end(); - auto dst = Aligned ? out.begin() : out.begin() + 4; - for ([[maybe_unused]] auto _ : st) { - benchmark::DoNotOptimize(in); - benchmark::DoNotOptimize(out); - auto result = copy(first, last, dst); - benchmark::DoNotOptimize(result); - } - }; - benchmark::RegisterBenchmark(operation_name, bench)->Range(64, 1 << 20); -} + // {std,ranges}::copy(normal container) + { + auto bm = [](std::string name, auto copy) { + benchmark::RegisterBenchmark(name, [copy](auto& st) { + std::size_t const n = st.range(0); + using ValueType = typename Container::value_type; + Container c; + std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); -int main(int argc, char** argv) { - auto std_copy = [](auto first, auto last, auto out) { return std::copy(first, last, out); }; - auto ranges_copy = std::ranges::copy; + std::vector out(n); - // std::copy - bm_general>("std::copy(vector)", std_copy); - bm_general>("std::copy(deque)", std_copy); - bm_general>("std::copy(list)", std_copy); - bm_vector_bool("std::copy(vector) (aligned)", std_copy); - bm_vector_bool("std::copy(vector) (unaligned)", std_copy); + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); + auto result = copy(c.begin(), c.end(), out.begin()); + benchmark::DoNotOptimize(result); + } + })->Range(8, 1 << 20); + }; + bm.operator()>("std::copy(vector)", std_copy); + bm.operator()>("std::copy(deque)", std_copy); + bm.operator()>("std::copy(list)", std_copy); + bm.operator()>("ranges::copy(vector)", std::ranges::copy); + bm.operator()>("ranges::copy(deque)", std::ranges::copy); + bm.operator()>("ranges::copy(list)", std::ranges::copy); + } - // ranges::copy - bm_general>("ranges::copy(vector)", ranges_copy); - bm_general>("ranges::copy(deque)", ranges_copy); - bm_general>("ranges::copy(list)", ranges_copy); + // {std,ranges}::copy(vector) + { + auto bm = [](std::string name, auto copy) { + benchmark::RegisterBenchmark(name, [copy](auto& st) { + std::size_t const n = st.range(0); + std::vector in(n, true); + std::vector out(Aligned ? n : n + 8); + auto first = in.begin(); + auto last = in.end(); + auto dst = Aligned ? out.begin() : out.begin() + 4; + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(in); + benchmark::DoNotOptimize(out); + auto result = copy(first, last, dst); + benchmark::DoNotOptimize(result); + } + })->Range(64, 1 << 20); + }; + bm.operator()("std::copy(vector) (aligned)", std_copy); + bm.operator()("std::copy(vector) (unaligned)", std_copy); #if TEST_STD_VER >= 23 // vector::iterator is not an output_iterator before C++23 - bm_vector_bool("ranges::copy(vector) (aligned)", ranges_copy); - bm_vector_bool("ranges::copy(vector) (unaligned)", ranges_copy); + bm.operator()("ranges::copy(vector) (aligned)", std::ranges::copy); + bm.operator()("ranges::copy(vector) (unaligned)", std::ranges::copy); #endif + } benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp index 42265c9e9cd2d..15122652f28ae 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp @@ -20,65 +20,62 @@ #include "../../GenerateInput.h" #include "test_macros.h" -template -void bm_general(std::string operation_name, Operation copy_backward) { - auto bench = [copy_backward](auto& st) { - std::size_t const n = st.range(0); - using ValueType = typename Container::value_type; - Container c; - std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); - - std::vector out(n); - - for ([[maybe_unused]] auto _ : st) { - benchmark::DoNotOptimize(c); - benchmark::DoNotOptimize(out); - auto result = copy_backward(c.begin(), c.end(), out.end()); - benchmark::DoNotOptimize(result); - } - }; - benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); -} +int main(int argc, char** argv) { + auto std_copy_backward = [](auto first, auto last, auto out) { return std::copy_backward(first, last, out); }; -template -static void bm_vector_bool(std::string operation_name, Operation copy_backward) { - auto bench = [copy_backward](auto& st) { - std::size_t const n = st.range(0); - std::vector in(n, true); - std::vector out(Aligned ? n : n + 8); - benchmark::DoNotOptimize(&in); - auto first = in.begin(); - auto last = in.end(); - auto dst = Aligned ? out.end() : out.end() - 4; - for ([[maybe_unused]] auto _ : st) { - benchmark::DoNotOptimize(in); - benchmark::DoNotOptimize(out); - auto result = copy_backward(first, last, dst); - benchmark::DoNotOptimize(result); - } - }; - benchmark::RegisterBenchmark(operation_name, bench)->Range(64, 1 << 20); -} + // {std,ranges}::copy_n(normal container) + { + auto bm = [](std::string name, auto copy_backward) { + benchmark::RegisterBenchmark(name, [copy_backward](auto& st) { + std::size_t const n = st.range(0); + using ValueType = typename Container::value_type; + Container c; + std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); -int main(int argc, char** argv) { - auto std_copy_backward = [](auto first, auto last, auto out) { return std::copy_backward(first, last, out); }; - auto ranges_copy_backward = std::ranges::copy_backward; + std::vector out(n); - // std::copy - bm_general>("std::copy_backward(vector)", std_copy_backward); - bm_general>("std::copy_backward(deque)", std_copy_backward); - bm_general>("std::copy_backward(list)", std_copy_backward); - bm_vector_bool("std::copy_backward(vector) (aligned)", std_copy_backward); - bm_vector_bool("std::copy_backward(vector) (unaligned)", std_copy_backward); + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); + auto result = copy_backward(c.begin(), c.end(), out.end()); + benchmark::DoNotOptimize(result); + } + })->Range(8, 1 << 20); + }; + bm.operator()>("std::copy_backward(vector)", std_copy_backward); + bm.operator()>("std::copy_backward(deque)", std_copy_backward); + bm.operator()>("std::copy_backward(list)", std_copy_backward); + bm.operator()>("ranges::copy_backward(vector)", std::ranges::copy_backward); + bm.operator()>("ranges::copy_backward(deque)", std::ranges::copy_backward); + bm.operator()>("ranges::copy_backward(list)", std::ranges::copy_backward); + } - // ranges::copy - bm_general>("ranges::copy_backward(vector)", ranges_copy_backward); - bm_general>("ranges::copy_backward(deque)", ranges_copy_backward); - bm_general>("ranges::copy_backward(list)", ranges_copy_backward); + // {std,ranges}::copy_n(vector) + { + auto bm = [](std::string name, auto copy_backward) { + benchmark::RegisterBenchmark(name, [copy_backward](auto& st) { + std::size_t const n = st.range(0); + std::vector in(n, true); + std::vector out(Aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto first = in.begin(); + auto last = in.end(); + auto dst = Aligned ? out.end() : out.end() - 4; + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(in); + benchmark::DoNotOptimize(out); + auto result = copy_backward(first, last, dst); + benchmark::DoNotOptimize(result); + } + })->Range(64, 1 << 20); + }; + bm.operator()("std::copy_backward(vector) (aligned)", std_copy_backward); + bm.operator()("std::copy_backward(vector) (unaligned)", std_copy_backward); #if TEST_STD_VER >= 23 // vector::iterator is not an output_iterator before C++23 - bm_vector_bool("ranges::copy_backward(vector) (aligned)", ranges_copy_backward); - bm_vector_bool("ranges::copy_backward(vector) (unaligned)", ranges_copy_backward); + bm.operator()("ranges::copy_backward(vector) (aligned)", std::ranges::copy_backward); + bm.operator()("ranges::copy_backward(vector) (unaligned)", std::ranges::copy_backward); #endif + } benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp index ac9e42d2d2235..ab6889de52296 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp @@ -19,81 +19,77 @@ #include "benchmark/benchmark.h" #include "../../GenerateInput.h" -// Benchmark copying one out of two element, in alternance. This is basically -// the worst case for this algorithm, I don't think there are many optimizations -// that can be applied in this case. -template -void bm_copy_every_other_element(std::string operation_name, Operation copy_if) { - auto bench = [copy_if](auto& st) { - std::size_t const n = st.range(0); - using ValueType = typename Container::value_type; - Container c; - std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); - - std::vector out(n); - - for ([[maybe_unused]] auto _ : st) { - bool do_copy = false; - auto pred = [&do_copy](auto& element) { - benchmark::DoNotOptimize(element); - do_copy = !do_copy; - return do_copy; - }; - benchmark::DoNotOptimize(c); - benchmark::DoNotOptimize(out); - auto result = copy_if(c.begin(), c.end(), out.begin(), pred); - benchmark::DoNotOptimize(result); - } - }; - benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); -} +int main(int argc, char** argv) { + auto std_copy_if = [](auto first, auto last, auto out, auto pred) { return std::copy_if(first, last, out, pred); }; -// Copy the full range. -template -void bm_copy_entire_range(std::string operation_name, Operation copy_if) { - auto bench = [copy_if](auto& st) { - std::size_t const n = st.range(0); - using ValueType = typename Container::value_type; - Container c; - std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); + // Benchmark {std,ranges}::copy_if where we copy one out of two element, in alternance. + // This is basically the worst case for this algorithm, I don't think there are many + // optimizations that can be applied in this case. + { + auto bm = [](std::string name, auto copy_if) { + benchmark::RegisterBenchmark(name, [copy_if](auto& st) { + std::size_t const n = st.range(0); + using ValueType = typename Container::value_type; + Container c; + std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); - std::vector out(n); + std::vector out(n); - for ([[maybe_unused]] auto _ : st) { - auto pred = [](auto& element) { - benchmark::DoNotOptimize(element); - return true; - }; - benchmark::DoNotOptimize(c); - benchmark::DoNotOptimize(out); - auto result = copy_if(c.begin(), c.end(), out.begin(), pred); - benchmark::DoNotOptimize(result); - } - }; - benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); -} + for ([[maybe_unused]] auto _ : st) { + bool do_copy = false; + auto pred = [&do_copy](auto& element) { + benchmark::DoNotOptimize(element); + do_copy = !do_copy; + return do_copy; + }; + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); + auto result = copy_if(c.begin(), c.end(), out.begin(), pred); + benchmark::DoNotOptimize(result); + } + })->Range(8, 1 << 20); + }; + bm.operator()>("std::copy_if(vector) (every other)", std_copy_if); + bm.operator()>("std::copy_if(deque) (every other)", std_copy_if); + bm.operator()>("std::copy_if(list) (every other)", std_copy_if); -int main(int argc, char** argv) { - auto std_copy_if = [](auto first, auto last, auto out, auto pred) { return std::copy_if(first, last, out, pred); }; - auto ranges_copy_if = std::ranges::copy_if; + bm.operator()>("ranges::copy_if(vector) (every other)", std::ranges::copy_if); + bm.operator()>("ranges::copy_if(deque) (every other)", std::ranges::copy_if); + bm.operator()>("ranges::copy_if(list) (every other)", std::ranges::copy_if); + } - // std::copy_if - bm_copy_every_other_element>("std::copy_if(vector) (every other)", std_copy_if); - bm_copy_every_other_element>("std::copy_if(deque) (every other)", std_copy_if); - bm_copy_every_other_element>("std::copy_if(list) (every other)", std_copy_if); + // Benchmark {std,ranges}::copy_if where we copy the full range. + // Copy the full range. + { + auto bm = [](std::string name, auto copy_if) { + benchmark::RegisterBenchmark(name, [copy_if](auto& st) { + std::size_t const n = st.range(0); + using ValueType = typename Container::value_type; + Container c; + std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); - bm_copy_entire_range>("std::copy_if(vector) (entire range)", std_copy_if); - bm_copy_entire_range>("std::copy_if(deque) (entire range)", std_copy_if); - bm_copy_entire_range>("std::copy_if(list) (entire range)", std_copy_if); + std::vector out(n); - // ranges::copy - bm_copy_every_other_element>("ranges::copy_if(vector) (every other)", ranges_copy_if); - bm_copy_every_other_element>("ranges::copy_if(deque) (every other)", ranges_copy_if); - bm_copy_every_other_element>("ranges::copy_if(list) (every other)", ranges_copy_if); + for ([[maybe_unused]] auto _ : st) { + auto pred = [](auto& element) { + benchmark::DoNotOptimize(element); + return true; + }; + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); + auto result = copy_if(c.begin(), c.end(), out.begin(), pred); + benchmark::DoNotOptimize(result); + } + })->Range(8, 1 << 20); + }; + bm.operator()>("std::copy_if(vector) (entire range)", std_copy_if); + bm.operator()>("std::copy_if(deque) (entire range)", std_copy_if); + bm.operator()>("std::copy_if(list) (entire range)", std_copy_if); - bm_copy_entire_range>("ranges::copy_if(vector) (entire range)", ranges_copy_if); - bm_copy_entire_range>("ranges::copy_if(deque) (entire range)", ranges_copy_if); - bm_copy_entire_range>("ranges::copy_if(list) (entire range)", ranges_copy_if); + bm.operator()>("ranges::copy_if(vector) (entire range)", std::ranges::copy_if); + bm.operator()>("ranges::copy_if(deque) (entire range)", std::ranges::copy_if); + bm.operator()>("ranges::copy_if(list) (entire range)", std::ranges::copy_if); + } benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp index ad70b9fb3c7e7..539308cbbf3e1 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp @@ -20,63 +20,60 @@ #include "../../GenerateInput.h" #include "test_macros.h" -template -void bm_general(std::string operation_name, Operation copy_n) { - auto bench = [copy_n](auto& st) { - std::size_t const n = st.range(0); - using ValueType = typename Container::value_type; - Container c; - std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); - - std::vector out(n); - - for ([[maybe_unused]] auto _ : st) { - benchmark::DoNotOptimize(c); - benchmark::DoNotOptimize(out); - auto result = copy_n(c.begin(), n, out.begin()); - benchmark::DoNotOptimize(result); - } - }; - benchmark::RegisterBenchmark(operation_name, bench)->Range(8, 1 << 20); -} +int main(int argc, char** argv) { + auto std_copy_n = [](auto first, auto n, auto out) { return std::copy_n(first, n, out); }; -template -static void bm_vector_bool(std::string operation_name, Operation copy_n) { - auto bench = [copy_n](auto& st) { - std::size_t const n = st.range(0); - std::vector in(n, true); - std::vector out(Aligned ? n : n + 8); - auto first = in.begin(); - auto dst = Aligned ? out.begin() : out.begin() + 4; - for ([[maybe_unused]] auto _ : st) { - benchmark::DoNotOptimize(in); - benchmark::DoNotOptimize(out); - auto result = copy_n(first, n, dst); - benchmark::DoNotOptimize(result); - } - }; - benchmark::RegisterBenchmark(operation_name, bench)->Range(64, 1 << 20); -} + // {std,ranges}::copy_n(normal container) + { + auto bm = [](std::string name, auto copy_n) { + benchmark::RegisterBenchmark(name, [copy_n](auto& st) { + std::size_t const n = st.range(0); + using ValueType = typename Container::value_type; + Container c; + std::generate_n(std::back_inserter(c), n, [] { return Generate::random(); }); -int main(int argc, char** argv) { - auto std_copy_n = [](auto first, auto n, auto out) { return std::copy_n(first, n, out); }; - auto ranges_copy_n = std::ranges::copy_n; + std::vector out(n); - // std::copy_n - bm_general>("std::copy_n(vector)", std_copy_n); - bm_general>("std::copy_n(deque)", std_copy_n); - bm_general>("std::copy_n(list)", std_copy_n); - bm_vector_bool("std::copy_n(vector) (aligned)", std_copy_n); - bm_vector_bool("std::copy_n(vector) (unaligned)", std_copy_n); + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); + auto result = copy_n(c.begin(), n, out.begin()); + benchmark::DoNotOptimize(result); + } + })->Range(8, 1 << 20); + }; + bm.operator()>("std::copy_n(vector)", std_copy_n); + bm.operator()>("std::copy_n(deque)", std_copy_n); + bm.operator()>("std::copy_n(list)", std_copy_n); + bm.operator()>("ranges::copy_n(vector)", std::ranges::copy_n); + bm.operator()>("ranges::copy_n(deque)", std::ranges::copy_n); + bm.operator()>("ranges::copy_n(list)", std::ranges::copy_n); + } - // ranges::copy_n - bm_general>("ranges::copy_n(vector)", ranges_copy_n); - bm_general>("ranges::copy_n(deque)", ranges_copy_n); - bm_general>("ranges::copy_n(list)", ranges_copy_n); + // {std,ranges}::copy_n(vector) + { + auto bm = [](std::string name, auto copy_n) { + benchmark::RegisterBenchmark(name, [copy_n](auto& st) { + std::size_t const n = st.range(0); + std::vector in(n, true); + std::vector out(Aligned ? n : n + 8); + auto first = in.begin(); + auto dst = Aligned ? out.begin() : out.begin() + 4; + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(in); + benchmark::DoNotOptimize(out); + auto result = copy_n(first, n, dst); + benchmark::DoNotOptimize(result); + } + })->Range(64, 1 << 20); + }; + bm.operator()("std::copy_n(vector) (aligned)", std_copy_n); + bm.operator()("std::copy_n(vector) (unaligned)", std_copy_n); #if TEST_STD_VER >= 23 // vector::iterator is not an output_iterator before C++23 - bm_vector_bool("ranges::copy_n(vector) (aligned)", ranges_copy_n); - bm_vector_bool("ranges::copy_n(vector) (unaligned)", ranges_copy_n); + bm.operator()("ranges::copy_n(vector) (aligned)", std::ranges::copy_n); + bm.operator()("ranges::copy_n(vector) (unaligned)", std::ranges::copy_n); #endif + } benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); From bf612506961952dc1daa405eaa2f0b19a6ca242f Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 19 Feb 2025 13:45:45 -0500 Subject: [PATCH 6/6] Use rng::copy instead of ranges::copy -- that way the results align better with std:: in the tabular output --- .../benchmarks/algorithms/modifying/copy.bench.cpp | 10 +++++----- .../algorithms/modifying/copy_backward.bench.cpp | 10 +++++----- .../algorithms/modifying/copy_if.bench.cpp | 12 ++++++------ .../benchmarks/algorithms/modifying/copy_n.bench.cpp | 10 +++++----- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp index 5c29260f9da37..3549d918478bd 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy.bench.cpp @@ -45,9 +45,9 @@ int main(int argc, char** argv) { bm.operator()>("std::copy(vector)", std_copy); bm.operator()>("std::copy(deque)", std_copy); bm.operator()>("std::copy(list)", std_copy); - bm.operator()>("ranges::copy(vector)", std::ranges::copy); - bm.operator()>("ranges::copy(deque)", std::ranges::copy); - bm.operator()>("ranges::copy(list)", std::ranges::copy); + bm.operator()>("rng::copy(vector)", std::ranges::copy); + bm.operator()>("rng::copy(deque)", std::ranges::copy); + bm.operator()>("rng::copy(list)", std::ranges::copy); } // {std,ranges}::copy(vector) @@ -71,8 +71,8 @@ int main(int argc, char** argv) { bm.operator()("std::copy(vector) (aligned)", std_copy); bm.operator()("std::copy(vector) (unaligned)", std_copy); #if TEST_STD_VER >= 23 // vector::iterator is not an output_iterator before C++23 - bm.operator()("ranges::copy(vector) (aligned)", std::ranges::copy); - bm.operator()("ranges::copy(vector) (unaligned)", std::ranges::copy); + bm.operator()("rng::copy(vector) (aligned)", std::ranges::copy); + bm.operator()("rng::copy(vector) (unaligned)", std::ranges::copy); #endif } diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp index 15122652f28ae..f97a7a84d5e0a 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_backward.bench.cpp @@ -45,9 +45,9 @@ int main(int argc, char** argv) { bm.operator()>("std::copy_backward(vector)", std_copy_backward); bm.operator()>("std::copy_backward(deque)", std_copy_backward); bm.operator()>("std::copy_backward(list)", std_copy_backward); - bm.operator()>("ranges::copy_backward(vector)", std::ranges::copy_backward); - bm.operator()>("ranges::copy_backward(deque)", std::ranges::copy_backward); - bm.operator()>("ranges::copy_backward(list)", std::ranges::copy_backward); + bm.operator()>("rng::copy_backward(vector)", std::ranges::copy_backward); + bm.operator()>("rng::copy_backward(deque)", std::ranges::copy_backward); + bm.operator()>("rng::copy_backward(list)", std::ranges::copy_backward); } // {std,ranges}::copy_n(vector) @@ -72,8 +72,8 @@ int main(int argc, char** argv) { bm.operator()("std::copy_backward(vector) (aligned)", std_copy_backward); bm.operator()("std::copy_backward(vector) (unaligned)", std_copy_backward); #if TEST_STD_VER >= 23 // vector::iterator is not an output_iterator before C++23 - bm.operator()("ranges::copy_backward(vector) (aligned)", std::ranges::copy_backward); - bm.operator()("ranges::copy_backward(vector) (unaligned)", std::ranges::copy_backward); + bm.operator()("rng::copy_backward(vector) (aligned)", std::ranges::copy_backward); + bm.operator()("rng::copy_backward(vector) (unaligned)", std::ranges::copy_backward); #endif } diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp index ab6889de52296..76c653fc7f941 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_if.bench.cpp @@ -53,9 +53,9 @@ int main(int argc, char** argv) { bm.operator()>("std::copy_if(deque) (every other)", std_copy_if); bm.operator()>("std::copy_if(list) (every other)", std_copy_if); - bm.operator()>("ranges::copy_if(vector) (every other)", std::ranges::copy_if); - bm.operator()>("ranges::copy_if(deque) (every other)", std::ranges::copy_if); - bm.operator()>("ranges::copy_if(list) (every other)", std::ranges::copy_if); + bm.operator()>("rng::copy_if(vector) (every other)", std::ranges::copy_if); + bm.operator()>("rng::copy_if(deque) (every other)", std::ranges::copy_if); + bm.operator()>("rng::copy_if(list) (every other)", std::ranges::copy_if); } // Benchmark {std,ranges}::copy_if where we copy the full range. @@ -86,9 +86,9 @@ int main(int argc, char** argv) { bm.operator()>("std::copy_if(deque) (entire range)", std_copy_if); bm.operator()>("std::copy_if(list) (entire range)", std_copy_if); - bm.operator()>("ranges::copy_if(vector) (entire range)", std::ranges::copy_if); - bm.operator()>("ranges::copy_if(deque) (entire range)", std::ranges::copy_if); - bm.operator()>("ranges::copy_if(list) (entire range)", std::ranges::copy_if); + bm.operator()>("rng::copy_if(vector) (entire range)", std::ranges::copy_if); + bm.operator()>("rng::copy_if(deque) (entire range)", std::ranges::copy_if); + bm.operator()>("rng::copy_if(list) (entire range)", std::ranges::copy_if); } benchmark::Initialize(&argc, argv); diff --git a/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp index 539308cbbf3e1..35d3c5c78df13 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/copy_n.bench.cpp @@ -45,9 +45,9 @@ int main(int argc, char** argv) { bm.operator()>("std::copy_n(vector)", std_copy_n); bm.operator()>("std::copy_n(deque)", std_copy_n); bm.operator()>("std::copy_n(list)", std_copy_n); - bm.operator()>("ranges::copy_n(vector)", std::ranges::copy_n); - bm.operator()>("ranges::copy_n(deque)", std::ranges::copy_n); - bm.operator()>("ranges::copy_n(list)", std::ranges::copy_n); + bm.operator()>("rng::copy_n(vector)", std::ranges::copy_n); + bm.operator()>("rng::copy_n(deque)", std::ranges::copy_n); + bm.operator()>("rng::copy_n(list)", std::ranges::copy_n); } // {std,ranges}::copy_n(vector) @@ -70,8 +70,8 @@ int main(int argc, char** argv) { bm.operator()("std::copy_n(vector) (aligned)", std_copy_n); bm.operator()("std::copy_n(vector) (unaligned)", std_copy_n); #if TEST_STD_VER >= 23 // vector::iterator is not an output_iterator before C++23 - bm.operator()("ranges::copy_n(vector) (aligned)", std::ranges::copy_n); - bm.operator()("ranges::copy_n(vector) (unaligned)", std::ranges::copy_n); + bm.operator()("rng::copy_n(vector) (aligned)", std::ranges::copy_n); + bm.operator()("rng::copy_n(vector) (unaligned)", std::ranges::copy_n); #endif }