diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index b9964dac84acd..406b26f86a4c5 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -708,6 +708,7 @@ module std [system] { } module ranges_remove { header "__algorithm/ranges_remove.h" + export std.ranges.subrange // return type } module ranges_replace_copy_if { header "__algorithm/ranges_replace_copy_if.h" @@ -732,7 +733,7 @@ module std [system] { } module ranges_rotate_copy { header "__algorithm/ranges_rotate_copy.h" - export std.algorithm.in_out_result + export std.ranges.subrange // return type } module ranges_rotate { header "__algorithm/ranges_rotate.h" } module ranges_sample { header "__algorithm/ranges_sample.h" } diff --git a/libcxx/test/benchmarks/GenerateInput.h b/libcxx/test/benchmarks/GenerateInput.h index c87fd69162e9d..9be76f55c2774 100644 --- a/libcxx/test/benchmarks/GenerateInput.h +++ b/libcxx/test/benchmarks/GenerateInput.h @@ -204,4 +204,13 @@ struct Generate { } }; +template +T random_different_from(std::initializer_list others) { + T value; + do { + value = Generate::random(); + } while (std::find(others.begin(), others.end(), value) != others.end()); + return value; +} + #endif // BENCHMARK_GENERATE_INPUT_H diff --git a/libcxx/test/benchmarks/algorithms/fill.bench.cpp b/libcxx/test/benchmarks/algorithms/fill.bench.cpp deleted file mode 100644 index 6a48b25b7eb63..0000000000000 --- a/libcxx/test/benchmarks/algorithms/fill.bench.cpp +++ /dev/null @@ -1,51 +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_fill_n_vector_bool(benchmark::State& state) { - std::vector vec1(state.range()); - for (auto _ : state) { - benchmark::DoNotOptimize(vec1); - benchmark::DoNotOptimize(std::fill_n(vec1.begin(), vec1.size(), false)); - } -} -BENCHMARK(bm_fill_n_vector_bool)->DenseRange(1, 8)->Range(16, 1 << 20); - -static void bm_ranges_fill_n_vector_bool(benchmark::State& state) { - std::vector vec1(state.range()); - for (auto _ : state) { - benchmark::DoNotOptimize(vec1); - benchmark::DoNotOptimize(std::ranges::fill_n(vec1.begin(), vec1.size(), false)); - } -} -BENCHMARK(bm_ranges_fill_n_vector_bool)->DenseRange(1, 8)->Range(16, 1 << 20); - -static void bm_fill_vector_bool(benchmark::State& state) { - std::vector vec1(state.range()); - for (auto _ : state) { - benchmark::DoNotOptimize(vec1); - std::fill(vec1.begin(), vec1.end(), false); - } -} -BENCHMARK(bm_fill_vector_bool)->DenseRange(1, 8)->Range(16, 1 << 20); - -static void bm_ranges_fill_vector_bool(benchmark::State& state) { - std::vector vec1(state.range()); - for (auto _ : state) { - benchmark::DoNotOptimize(vec1); - benchmark::DoNotOptimize(std::ranges::fill(vec1, false)); - } -} -BENCHMARK(bm_ranges_fill_vector_bool)->DenseRange(1, 8)->Range(16, 1 << 20); - -BENCHMARK_MAIN(); diff --git a/libcxx/test/benchmarks/algorithms/modifying/fill.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/fill.bench.cpp new file mode 100644 index 0000000000000..9060752259eb9 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/fill.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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" +#include "test_macros.h" + +int main(int argc, char** argv) { + auto std_fill = [](auto first, auto last, auto const& value) { return std::fill(first, last, value); }; + + // {std,ranges}::fill(normal container) + { + auto bm = [](std::string name, auto fill) { + benchmark::RegisterBenchmark( + name, + [fill](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + ValueType x = Generate::random(); + Container c(size, x); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(x); + fill(c.begin(), c.end(), x); + benchmark::DoNotOptimize(c); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::fill(vector)", std_fill); + bm.operator()>("std::fill(deque)", std_fill); + bm.operator()>("std::fill(list)", std_fill); + bm.operator()>("rng::fill(vector)", std::ranges::fill); + bm.operator()>("rng::fill(deque)", std::ranges::fill); + bm.operator()>("rng::fill(list)", std::ranges::fill); + } + + // {std,ranges}::fill(vector) + { + auto bm = [](std::string name, auto fill) { + benchmark::RegisterBenchmark(name, [fill](auto& st) { + std::size_t const size = st.range(0); + bool x = true; + std::vector c(size, x); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(x); + fill(c.begin(), c.end(), x); + benchmark::DoNotOptimize(c); + } + })->Range(64, 1 << 20); + }; + bm("std::fill(vector)", std_fill); +#if TEST_STD_VER >= 23 // vector::iterator is not an output_iterator before C++23 + bm("rng::fill(vector)", std::ranges::fill); +#endif + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/fill_n.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/fill_n.bench.cpp new file mode 100644 index 0000000000000..8ad3e7534b1ef --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/fill_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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" +#include "test_macros.h" + +int main(int argc, char** argv) { + auto std_fill_n = [](auto out, auto n, auto const& value) { return std::fill_n(out, n, value); }; + + // {std,ranges}::fill_n(normal container) + { + auto bm = [](std::string name, auto fill_n) { + benchmark::RegisterBenchmark( + name, + [fill_n](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + ValueType x = Generate::random(); + Container c(size, x); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(x); + fill_n(c.begin(), size, x); + benchmark::DoNotOptimize(c); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::fill_n(vector)", std_fill_n); + bm.operator()>("std::fill_n(deque)", std_fill_n); + bm.operator()>("std::fill_n(list)", std_fill_n); + bm.operator()>("rng::fill_n(vector)", std::ranges::fill_n); + bm.operator()>("rng::fill_n(deque)", std::ranges::fill_n); + bm.operator()>("rng::fill_n(list)", std::ranges::fill_n); + } + + // {std,ranges}::fill_n(vector) + { + auto bm = [](std::string name, auto fill_n) { + benchmark::RegisterBenchmark(name, [fill_n](auto& st) { + std::size_t const size = st.range(0); + bool x = true; + std::vector c(size, x); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(x); + fill_n(c.begin(), size, x); + benchmark::DoNotOptimize(c); + } + })->Range(64, 1 << 20); + }; + bm("std::fill_n(vector)", std_fill_n); +#if TEST_STD_VER >= 23 // vector::iterator is not an output_iterator before C++23 + bm("rng::fill_n(vector)", std::ranges::fill_n); +#endif + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/generate.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/generate.bench.cpp new file mode 100644 index 0000000000000..34354e5af0efb --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/generate.bench.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_generate = [](auto first, auto last, auto f) { return std::generate(first, last, f); }; + + // {std,ranges}::generate + { + auto bm = [](std::string name, auto generate) { + benchmark::RegisterBenchmark( + name, + [generate](auto& st) { + std::size_t const size = st.range(0); + Container c(size); + using ValueType = typename Container::value_type; + ValueType x = Generate::random(); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + generate(c.begin(), c.end(), [&x] { + benchmark::DoNotOptimize(x); + return x; + }); + benchmark::DoNotOptimize(c); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::generate(vector)", std_generate); + bm.operator()>("std::generate(deque)", std_generate); + bm.operator()>("std::generate(list)", std_generate); + bm.operator()>("rng::generate(vector)", std::ranges::generate); + bm.operator()>("rng::generate(deque)", std::ranges::generate); + bm.operator()>("rng::generate(list)", std::ranges::generate); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/generate_n.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/generate_n.bench.cpp new file mode 100644 index 0000000000000..9f8fb1e07524d --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/generate_n.bench.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_generate_n = [](auto out, auto n, auto f) { return std::generate_n(out, n, f); }; + + // {std,ranges}::generate_n + { + auto bm = [](std::string name, auto generate_n) { + benchmark::RegisterBenchmark( + name, + [generate_n](auto& st) { + std::size_t const size = st.range(0); + Container c(size); + using ValueType = typename Container::value_type; + ValueType x = Generate::random(); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + generate_n(c.begin(), size, [&x] { + benchmark::DoNotOptimize(x); + return x; + }); + benchmark::DoNotOptimize(c); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::generate_n(vector)", std_generate_n); + bm.operator()>("std::generate_n(deque)", std_generate_n); + bm.operator()>("std::generate_n(list)", std_generate_n); + bm.operator()>("rng::generate_n(vector)", std::ranges::generate_n); + bm.operator()>("rng::generate_n(deque)", std::ranges::generate_n); + bm.operator()>("rng::generate_n(list)", std::ranges::generate_n); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/move.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/move.bench.cpp new file mode 100644 index 0000000000000..7473dffc123ce --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/move.bench.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" +#include "test_macros.h" + +int main(int argc, char** argv) { + auto std_move = [](auto first, auto last, auto out) { return std::move(first, last, out); }; + + // {std,ranges}::move(normal container) + { + auto bm = [](std::string name, auto move) { + benchmark::RegisterBenchmark(name, [move](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + Container c1(size); + Container c2(size); + std::generate_n(c1.begin(), size, [] { return Generate::random(); }); + + Container* in = &c1; + Container* out = &c2; + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(in); + benchmark::DoNotOptimize(out); + auto result = move(in->begin(), in->end(), out->begin()); + benchmark::DoNotOptimize(result); + std::swap(in, out); + } + })->Range(8, 1 << 20); + }; + bm.operator()>("std::move(vector)", std_move); + bm.operator()>("std::move(deque)", std_move); + bm.operator()>("std::move(list)", std_move); + bm.operator()>("rng::move(vector)", std::ranges::move); + bm.operator()>("rng::move(deque)", std::ranges::move); + bm.operator()>("rng::move(list)", std::ranges::move); + } + + // {std,ranges}::move(vector) + { + auto bm = [](std::string name, auto move) { + benchmark::RegisterBenchmark(name, [move](auto& st) { + std::size_t const size = st.range(0); + std::vector c1(size, true); + std::vector c2(size, false); + + std::vector* in = &c1; + std::vector* out = &c2; + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(in); + benchmark::DoNotOptimize(out); + auto first = Aligned ? in->begin() : in->begin() + 4; + auto result = move(first, in->end(), out->begin()); + benchmark::DoNotOptimize(result); + std::swap(in, out); + } + })->Range(64, 1 << 20); + }; + bm.operator()("std::move(vector) (aligned)", std_move); + bm.operator()("std::move(vector) (unaligned)", std_move); +#if TEST_STD_VER >= 23 // vector::iterator is not an output_iterator before C++23 + bm.operator()("rng::move(vector) (aligned)", std::ranges::move); + bm.operator()("rng::move(vector) (unaligned)", std::ranges::move); +#endif + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/move_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/move_backward.bench.cpp new file mode 100644 index 0000000000000..1cdc880910686 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/move_backward.bench.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" +#include "test_macros.h" + +int main(int argc, char** argv) { + auto std_move_backward = [](auto first, auto last, auto out) { return std::move_backward(first, last, out); }; + + // {std,ranges}::move_backward(normal container) + { + auto bm = [](std::string name, auto move_backward) { + benchmark::RegisterBenchmark(name, [move_backward](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + Container c1(size); + Container c2(size); + std::generate_n(c1.begin(), size, [] { return Generate::random(); }); + + Container* in = &c1; + Container* out = &c2; + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(in); + benchmark::DoNotOptimize(out); + auto result = move_backward(in->begin(), in->end(), out->end()); + benchmark::DoNotOptimize(result); + std::swap(in, out); + } + })->Range(8, 1 << 20); + }; + bm.operator()>("std::move_backward(vector)", std_move_backward); + bm.operator()>("std::move_backward(deque)", std_move_backward); + bm.operator()>("std::move_backward(list)", std_move_backward); + bm.operator()>("rng::move_backward(vector)", std::ranges::move_backward); + bm.operator()>("rng::move_backward(deque)", std::ranges::move_backward); + bm.operator()>("rng::move_backward(list)", std::ranges::move_backward); + } + + // {std,ranges}::move_backward(vector) + { + auto bm = [](std::string name, auto move_backward) { + benchmark::RegisterBenchmark(name, [move_backward](auto& st) { + std::size_t const size = st.range(0); + std::vector c1(size, true); + std::vector c2(size, false); + + std::vector* in = &c1; + std::vector* out = &c2; + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(in); + benchmark::DoNotOptimize(out); + auto last = Aligned ? in->end() : in->end() - 4; + auto result = move_backward(in->begin(), last, out->end()); + benchmark::DoNotOptimize(result); + std::swap(in, out); + } + })->Range(64, 1 << 20); + }; + bm.operator()("std::move_backward(vector) (aligned)", std_move_backward); + bm.operator()("std::move_backward(vector) (unaligned)", std_move_backward); +#if TEST_STD_VER >= 23 // vector::iterator is not an output_iterator before C++23 + bm.operator()("rng::move_backward(vector) (aligned)", std::ranges::move_backward); + bm.operator()("rng::move_backward(vector) (unaligned)", std::ranges::move_backward); +#endif + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/remove.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/remove.bench.cpp new file mode 100644 index 0000000000000..19cd49641e173 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/remove.bench.cpp @@ -0,0 +1,167 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_remove = [](auto first, auto last, auto const& value) { return std::remove(first, last, value); }; + auto std_remove_if = [](auto first, auto last, auto const& value) { + return std::remove_if(first, last, [&](auto element) { + benchmark::DoNotOptimize(element); + return element == value; + }); + }; + auto ranges_remove_if = [](auto first, auto last, auto const& value) { + return std::ranges::remove_if(first, last, [&](auto element) { + benchmark::DoNotOptimize(element); + return element == value; + }); + }; + + // Benchmark {std,ranges}::{remove,remove_if} on a sequence of the form xxxxxxxxxxyyyyyyyyyy + // where we remove the prefix of x's from the sequence. + // + // We perform this benchmark in a batch because we need to restore the + // state of the container after the operation. + { + auto bm = [](std::string name, auto remove) { + benchmark::RegisterBenchmark( + name, + [remove](auto& st) { + std::size_t const size = st.range(0); + constexpr std::size_t BatchSize = 10; + using ValueType = typename Container::value_type; + Container c[BatchSize]; + ValueType x = Generate::random(); + ValueType y = random_different_from({x}); + auto populate = [&](Container& cont) { + auto half = cont.size() / 2; + std::fill_n(std::fill_n(cont.begin(), half, x), half, y); + }; + for (std::size_t i = 0; i != BatchSize; ++i) { + c[i] = Container(size); + populate(c[i]); + } + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + benchmark::DoNotOptimize(c[i]); + benchmark::DoNotOptimize(x); + auto result = remove(c[i].begin(), c[i].end(), x); + benchmark::DoNotOptimize(result); + } + + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + populate(c[i]); + } + st.ResumeTiming(); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + // {std,ranges}::remove + bm.operator()>("std::remove(vector) (prefix)", std_remove); + bm.operator()>("std::remove(deque) (prefix)", std_remove); + bm.operator()>("std::remove(list) (prefix)", std_remove); + bm.operator()>("rng::remove(vector) (prefix)", std::ranges::remove); + bm.operator()>("rng::remove(deque) (prefix)", std::ranges::remove); + bm.operator()>("rng::remove(list) (prefix)", std::ranges::remove); + + // {std,ranges}::remove_if + bm.operator()>("std::remove_if(vector) (prefix)", std_remove_if); + bm.operator()>("std::remove_if(deque) (prefix)", std_remove_if); + bm.operator()>("std::remove_if(list) (prefix)", std_remove_if); + bm.operator()>("rng::remove_if(vector) (prefix)", ranges_remove_if); + bm.operator()>("rng::remove_if(deque) (prefix)", ranges_remove_if); + bm.operator()>("rng::remove_if(list) (prefix)", ranges_remove_if); + } + + // Benchmark {std,ranges}::remove on a sequence of the form xyxyxyxyxyxyxyxyxyxy + // where we remove the x's from the sequence. + // + // We perform this benchmark in a batch because we need to restore the + // state of the container after the operation. + { + auto bm = [](std::string name, auto remove) { + benchmark::RegisterBenchmark( + name, + [remove](auto& st) { + std::size_t const size = st.range(0); + constexpr std::size_t BatchSize = 10; + using ValueType = typename Container::value_type; + Container c[BatchSize]; + ValueType x = Generate::random(); + ValueType y = random_different_from({x}); + auto populate = [&](Container& cont) { + auto out = cont.begin(); + for (std::size_t i = 0; i != cont.size(); ++i) { + *out++ = (i % 2 == 0 ? x : y); + } + }; + for (std::size_t i = 0; i != BatchSize; ++i) { + c[i] = Container(size); + populate(c[i]); + } + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + benchmark::DoNotOptimize(c[i]); + benchmark::DoNotOptimize(x); + auto result = remove(c[i].begin(), c[i].end(), x); + benchmark::DoNotOptimize(result); + } + + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + populate(c[i]); + } + st.ResumeTiming(); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + // {std,ranges}::remove + bm.operator()>("std::remove(vector) (sprinkled)", std_remove); + bm.operator()>("std::remove(deque) (sprinkled)", std_remove); + bm.operator()>("std::remove(list) (sprinkled)", std_remove); + bm.operator()>("rng::remove(vector) (sprinkled)", std::ranges::remove); + bm.operator()>("rng::remove(deque) (sprinkled)", std::ranges::remove); + bm.operator()>("rng::remove(list) (sprinkled)", std::ranges::remove); + + // {std,ranges}::remove_if + bm.operator()>("std::remove_if(vector) (sprinkled)", std_remove_if); + bm.operator()>("std::remove_if(deque) (sprinkled)", std_remove_if); + bm.operator()>("std::remove_if(list) (sprinkled)", std_remove_if); + bm.operator()>("rng::remove_if(vector) (sprinkled)", ranges_remove_if); + bm.operator()>("rng::remove_if(deque) (sprinkled)", ranges_remove_if); + bm.operator()>("rng::remove_if(list) (sprinkled)", ranges_remove_if); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/remove_copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/remove_copy.bench.cpp new file mode 100644 index 0000000000000..582175b8a32cc --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/remove_copy.bench.cpp @@ -0,0 +1,138 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_remove_copy = [](auto first, auto last, auto out, auto const& value) { + return std::remove_copy(first, last, out, value); + }; + auto std_remove_copy_if = [](auto first, auto last, auto out, auto const& value) { + return std::remove_copy_if(first, last, out, [&](auto element) { + benchmark::DoNotOptimize(element); + return element == value; + }); + }; + auto ranges_remove_copy_if = [](auto first, auto last, auto out, auto const& value) { + return std::ranges::remove_copy_if(first, last, out, [&](auto element) { + benchmark::DoNotOptimize(element); + return element == value; + }); + }; + + // Benchmark {std,ranges}::{remove_copy,remove_copy_if} on a sequence of the form xxxxxxxxxxyyyyyyyyyy + // where we remove the prefix of x's from the sequence. + { + auto bm = [](std::string name, auto remove_copy) { + benchmark::RegisterBenchmark( + name, + [remove_copy](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + Container c; + ValueType x = Generate::random(); + ValueType y = random_different_from({x}); + std::fill_n(std::back_inserter(c), size / 2, x); + std::fill_n(std::back_inserter(c), size / 2, y); + + std::vector out(size); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); + benchmark::DoNotOptimize(x); + auto result = remove_copy(c.begin(), c.end(), out.begin(), x); + benchmark::DoNotOptimize(result); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + // {std,ranges}::remove_copy + bm.operator()>("std::remove_copy(vector) (prefix)", std_remove_copy); + bm.operator()>("std::remove_copy(deque) (prefix)", std_remove_copy); + bm.operator()>("std::remove_copy(list) (prefix)", std_remove_copy); + bm.operator()>("rng::remove_copy(vector) (prefix)", std::ranges::remove_copy); + bm.operator()>("rng::remove_copy(deque) (prefix)", std::ranges::remove_copy); + bm.operator()>("rng::remove_copy(list) (prefix)", std::ranges::remove_copy); + + // {std,ranges}::remove_copy_if + bm.operator()>("std::remove_copy_if(vector) (prefix)", std_remove_copy_if); + bm.operator()>("std::remove_copy_if(deque) (prefix)", std_remove_copy_if); + bm.operator()>("std::remove_copy_if(list) (prefix)", std_remove_copy_if); + bm.operator()>("rng::remove_copy_if(vector) (prefix)", ranges_remove_copy_if); + bm.operator()>("rng::remove_copy_if(deque) (prefix)", ranges_remove_copy_if); + bm.operator()>("rng::remove_copy_if(list) (prefix)", ranges_remove_copy_if); + } + + // Benchmark {std,ranges}::{remove_copy,remove_copy_if} on a sequence of the form xyxyxyxyxyxyxyxyxyxy + // where we remove the x's from the sequence. + { + auto bm = [](std::string name, auto remove_copy) { + benchmark::RegisterBenchmark( + name, + [remove_copy](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + Container c; + ValueType x = Generate::random(); + ValueType y = random_different_from({x}); + for (std::size_t i = 0; i != size; ++i) { + c.push_back(i % 2 == 0 ? x : y); + } + + std::vector out(size); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); + benchmark::DoNotOptimize(x); + auto result = remove_copy(c.begin(), c.end(), out.begin(), x); + benchmark::DoNotOptimize(result); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + // {std,ranges}::remove_copy + bm.operator()>("std::remove_copy(vector) (sprinkled)", std_remove_copy); + bm.operator()>("std::remove_copy(deque) (sprinkled)", std_remove_copy); + bm.operator()>("std::remove_copy(list) (sprinkled)", std_remove_copy); + bm.operator()>("rng::remove_copy(vector) (sprinkled)", std::ranges::remove_copy); + bm.operator()>("rng::remove_copy(deque) (sprinkled)", std::ranges::remove_copy); + bm.operator()>("rng::remove_copy(list) (sprinkled)", std::ranges::remove_copy); + + // {std,ranges}::remove_copy_if + bm.operator()>("std::remove_copy_if(vector) (sprinkled)", std_remove_copy_if); + bm.operator()>("std::remove_copy_if(deque) (sprinkled)", std_remove_copy_if); + bm.operator()>("std::remove_copy_if(list) (sprinkled)", std_remove_copy_if); + bm.operator()>("rng::remove_copy_if(vector) (sprinkled)", ranges_remove_copy_if); + bm.operator()>("rng::remove_copy_if(deque) (sprinkled)", ranges_remove_copy_if); + bm.operator()>("rng::remove_copy_if(list) (sprinkled)", ranges_remove_copy_if); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/replace.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/replace.bench.cpp new file mode 100644 index 0000000000000..bdf26acb8d07f --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/replace.bench.cpp @@ -0,0 +1,140 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_replace = [](auto first, auto last, auto old, auto new_) { return std::replace(first, last, old, new_); }; + auto std_replace_if = [](auto first, auto last, auto old, auto new_) { + auto pred = [&](auto element) { + benchmark::DoNotOptimize(element); + return element == old; + }; + return std::replace_if(first, last, pred, new_); + }; + auto ranges_replace_if = [](auto first, auto last, auto old, auto new_) { + auto pred = [&](auto element) { + benchmark::DoNotOptimize(element); + return element == old; + }; + return std::ranges::replace_if(first, last, pred, new_); + }; + + // Create a sequence of the form xxxxxxxxxxyyyyyyyyyy, replace + // into zzzzzzzzzzzyyyyyyyyyy and then back. + // + // This measures the performance of replace() when replacing a large + // contiguous sequence of equal values. + { + auto bm = [](std::string name, auto replace) { + benchmark::RegisterBenchmark( + name, + [replace](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + Container c; + ValueType x = Generate::random(); + ValueType y = random_different_from({x}); + ValueType z = random_different_from({x, y}); + std::fill_n(std::back_inserter(c), size / 2, x); + std::fill_n(std::back_inserter(c), size / 2, y); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(x); + benchmark::DoNotOptimize(z); + replace(c.begin(), c.end(), x, z); + benchmark::DoNotOptimize(c); + std::swap(x, z); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + // {std,ranges}::replace + bm.operator()>("std::replace(vector) (prefix)", std_replace); + bm.operator()>("std::replace(deque) (prefix)", std_replace); + bm.operator()>("std::replace(list) (prefix)", std_replace); + bm.operator()>("rng::replace(vector) (prefix)", std::ranges::replace); + bm.operator()>("rng::replace(deque) (prefix)", std::ranges::replace); + bm.operator()>("rng::replace(list) (prefix)", std::ranges::replace); + + // {std,ranges}::replace_if + bm.operator()>("std::replace_if(vector) (prefix)", std_replace_if); + bm.operator()>("std::replace_if(deque) (prefix)", std_replace_if); + bm.operator()>("std::replace_if(list) (prefix)", std_replace_if); + bm.operator()>("rng::replace_if(vector) (prefix)", ranges_replace_if); + bm.operator()>("rng::replace_if(deque) (prefix)", ranges_replace_if); + bm.operator()>("rng::replace_if(list) (prefix)", ranges_replace_if); + } + + // Sprinkle elements to replace inside the range, like xyxyxyxyxyxyxyxyxyxy. + { + auto bm = [](std::string name, auto replace) { + benchmark::RegisterBenchmark( + name, + [replace](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + Container c; + ValueType x = Generate::random(); + ValueType y = random_different_from({x}); + ValueType z = random_different_from({x, y}); + for (std::size_t i = 0; i != size; ++i) { + c.push_back(i % 2 == 0 ? x : y); + } + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(x); + benchmark::DoNotOptimize(z); + replace(c.begin(), c.end(), x, z); + benchmark::DoNotOptimize(c); + std::swap(x, z); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + // {std,ranges}::replace + bm.operator()>("std::replace(vector) (sprinkled)", std_replace); + bm.operator()>("std::replace(deque) (sprinkled)", std_replace); + bm.operator()>("std::replace(list) (sprinkled)", std_replace); + bm.operator()>("rng::replace(vector) (sprinkled)", std::ranges::replace); + bm.operator()>("rng::replace(deque) (sprinkled)", std::ranges::replace); + bm.operator()>("rng::replace(list) (sprinkled)", std::ranges::replace); + + // {std,ranges}::replace_if + bm.operator()>("std::replace_if(vector) (sprinkled)", std_replace_if); + bm.operator()>("std::replace_if(deque) (sprinkled)", std_replace_if); + bm.operator()>("std::replace_if(list) (sprinkled)", std_replace_if); + bm.operator()>("rng::replace_if(vector) (sprinkled)", ranges_replace_if); + bm.operator()>("rng::replace_if(deque) (sprinkled)", ranges_replace_if); + bm.operator()>("rng::replace_if(list) (sprinkled)", ranges_replace_if); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/reverse.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/reverse.bench.cpp new file mode 100644 index 0000000000000..ded7d5018cdbe --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/reverse.bench.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_reverse = [](auto first, auto last) { return std::reverse(first, last); }; + + // {std,ranges}::reverse(normal container) + { + auto bm = [](std::string name, auto reverse) { + benchmark::RegisterBenchmark(name, [reverse](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + Container c; + std::generate_n(std::back_inserter(c), size, [] { return Generate::random(); }); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + reverse(c.begin(), c.end()); + benchmark::DoNotOptimize(c); + } + })->Range(8, 1 << 15); + }; + bm.operator()>("std::reverse(vector)", std_reverse); + bm.operator()>("std::reverse(deque)", std_reverse); + bm.operator()>("std::reverse(list)", std_reverse); + bm.operator()>("rng::reverse(vector)", std::ranges::reverse); + bm.operator()>("rng::reverse(deque)", std::ranges::reverse); + bm.operator()>("rng::reverse(list)", std::ranges::reverse); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/reverse_copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/reverse_copy.bench.cpp new file mode 100644 index 0000000000000..7e19eb71f059a --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/reverse_copy.bench.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_reverse_copy = [](auto first, auto last, auto out) { return std::reverse_copy(first, last, out); }; + + // {std,ranges}::reverse_copy(normal container) + { + auto bm = [](std::string name, auto reverse_copy) { + benchmark::RegisterBenchmark(name, [reverse_copy](auto& st) { + std::size_t 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) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); + auto result = reverse_copy(c.begin(), c.end(), out.begin()); + benchmark::DoNotOptimize(result); + } + })->Range(8, 1 << 15); + }; + bm.operator()>("std::reverse_copy(vector)", std_reverse_copy); + bm.operator()>("std::reverse_copy(deque)", std_reverse_copy); + bm.operator()>("std::reverse_copy(list)", std_reverse_copy); + bm.operator()>("rng::reverse_copy(vector)", std::ranges::reverse_copy); + bm.operator()>("rng::reverse_copy(deque)", std::ranges::reverse_copy); + bm.operator()>("rng::reverse_copy(list)", std::ranges::reverse_copy); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/rotate.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/rotate.bench.cpp index eb84eb5cdf25c..d9548a3c176d2 100644 --- a/libcxx/test/benchmarks/algorithms/modifying/rotate.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/modifying/rotate.bench.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -45,15 +44,110 @@ int main(int argc, char** argv) { }) ->Arg(32) ->Arg(50) // non power-of-two - ->RangeMultiplier(2) - ->Range(64, 1 << 20); + ->Arg(1024) + ->Arg(8192); }; + bm.operator()>("std::rotate(vector) (by 1/4)", std_rotate, 0.25); + bm.operator()>("std::rotate(deque) (by 1/4)", std_rotate, 0.25); + bm.operator()>("std::rotate(list) (by 1/4)", std_rotate, 0.25); + bm.operator()>("rng::rotate(vector) (by 1/4)", std::ranges::rotate, 0.25); + bm.operator()>("rng::rotate(deque) (by 1/4)", std::ranges::rotate, 0.25); + bm.operator()>("rng::rotate(list) (by 1/4)", std::ranges::rotate, 0.25); + + bm.operator()>("std::rotate(vector) (by 1/3)", std_rotate, 0.33); + bm.operator()>("std::rotate(deque) (by 1/3)", std_rotate, 0.33); + bm.operator()>("std::rotate(list) (by 1/3)", std_rotate, 0.33); + bm.operator()>("rng::rotate(vector) (by 1/3)", std::ranges::rotate, 0.33); + bm.operator()>("rng::rotate(deque) (by 1/3)", std::ranges::rotate, 0.33); + bm.operator()>("rng::rotate(list) (by 1/3)", std::ranges::rotate, 0.33); + + bm.operator()>("std::rotate(vector) (by 1/2)", std_rotate, 0.50); + bm.operator()>("std::rotate(deque) (by 1/2)", std_rotate, 0.50); + bm.operator()>("std::rotate(list) (by 1/2)", std_rotate, 0.50); + bm.operator()>("rng::rotate(vector) (by 1/2)", std::ranges::rotate, 0.50); + bm.operator()>("rng::rotate(deque) (by 1/2)", std::ranges::rotate, 0.50); + bm.operator()>("rng::rotate(list) (by 1/2)", std::ranges::rotate, 0.50); bm.operator()>("std::rotate(vector) (by 1/4)", std_rotate, 0.25); - bm.operator()>("std::rotate(vector) (by 51%)", std_rotate, 0.51); + bm.operator()>("std::rotate(vector) (by 1/3)", std_rotate, 0.33); + bm.operator()>("std::rotate(vector) (by 1/2)", std_rotate, 0.50); + #if TEST_STD_VER >= 23 // vector::iterator is not std::permutable before C++23 bm.operator()>("rng::rotate(vector) (by 1/4)", std::ranges::rotate, 0.25); - bm.operator()>("rng::rotate(vector) (by 51%)", std::ranges::rotate, 0.51); + bm.operator()>("rng::rotate(vector) (by 1/3)", std::ranges::rotate, 0.33); + bm.operator()>("rng::rotate(vector) (by 1/2)", std::ranges::rotate, 0.50); +#endif + } + + // Benchmark {std,ranges}::rotate where we rotate a single element from the beginning to the end of the range. + { + auto bm = [](std::string name, auto rotate) { + benchmark::RegisterBenchmark( + name, + [rotate](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + Container c; + std::generate_n(std::back_inserter(c), size, [] { return Generate::random(); }); + + auto pivot = std::next(c.begin()); + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + auto result = rotate(c.begin(), pivot, c.end()); + benchmark::DoNotOptimize(result); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::rotate(vector) (1 element forward)", std_rotate); + bm.operator()>("std::rotate(deque) (1 element forward)", std_rotate); + bm.operator()>("std::rotate(list) (1 element forward)", std_rotate); + bm.operator()>("rng::rotate(vector) (1 element forward)", std::ranges::rotate); + bm.operator()>("rng::rotate(deque) (1 element forward)", std::ranges::rotate); + bm.operator()>("rng::rotate(list) (1 element forward)", std::ranges::rotate); + + bm.operator()>("std::rotate(vector) (1 element forward)", std_rotate); +#if TEST_STD_VER >= 23 // vector::iterator is not std::permutable before C++23 + bm.operator()>("rng::rotate(vector) (1 element forward)", std::ranges::rotate); +#endif + } + + // Benchmark {std,ranges}::rotate where we rotate a single element from the end to the beginning of the range. + { + auto bm = [](std::string name, auto rotate) { + benchmark::RegisterBenchmark( + name, + [rotate](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + Container c; + std::generate_n(std::back_inserter(c), size, [] { return Generate::random(); }); + + auto pivot = std::next(c.begin(), size - 1); + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + auto result = rotate(c.begin(), pivot, c.end()); + benchmark::DoNotOptimize(result); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::rotate(vector) (1 element backward)", std_rotate); + bm.operator()>("std::rotate(deque) (1 element backward)", std_rotate); + bm.operator()>("std::rotate(list) (1 element backward)", std_rotate); + bm.operator()>("rng::rotate(vector) (1 element backward)", std::ranges::rotate); + bm.operator()>("rng::rotate(deque) (1 element backward)", std::ranges::rotate); + bm.operator()>("rng::rotate(list) (1 element backward)", std::ranges::rotate); + + bm.operator()>("std::rotate(vector) (1 element backward)", std_rotate); +#if TEST_STD_VER >= 23 // vector::iterator is not std::permutable before C++23 + bm.operator()>("rng::rotate(vector) (1 element backward)", std::ranges::rotate); #endif } diff --git a/libcxx/test/benchmarks/algorithms/modifying/rotate_copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/rotate_copy.bench.cpp new file mode 100644 index 0000000000000..4ba9110552807 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/rotate_copy.bench.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_rotate_copy = [](auto first, auto middle, auto last, auto out) { + return std::rotate_copy(first, middle, last, out); + }; + + // {std,ranges}::rotate_copy(normal container) + { + auto bm = [](std::string name, auto rotate_copy) { + benchmark::RegisterBenchmark( + name, + [rotate_copy](auto& st) { + std::size_t 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); + + auto middle = std::next(c.begin(), size / 2); + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); + auto result = rotate_copy(c.begin(), middle, c.end(), out.begin()); + benchmark::DoNotOptimize(result); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::rotate_copy(vector)", std_rotate_copy); + bm.operator()>("std::rotate_copy(deque)", std_rotate_copy); + bm.operator()>("std::rotate_copy(list)", std_rotate_copy); + bm.operator()>("rng::rotate_copy(vector)", std::ranges::rotate_copy); + bm.operator()>("rng::rotate_copy(deque)", std::ranges::rotate_copy); + bm.operator()>("rng::rotate_copy(list)", std::ranges::rotate_copy); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/sample.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/sample.bench.cpp new file mode 100644 index 0000000000000..6cc789f460700 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/sample.bench.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_sample = [](auto first, auto last, auto out, auto n, auto& rng) { + return std::sample(first, last, out, n, rng); + }; + + // {std,ranges}::sample(normal container) + { + auto bm = [](std::string name, auto sample) { + benchmark::RegisterBenchmark( + name, + [sample](auto& st) { + std::size_t 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); + auto const n = size / 4; // sample 1/4 of the range + std::mt19937 rng; + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); + auto result = sample(c.begin(), c.end(), out.begin(), n, rng); + benchmark::DoNotOptimize(result); + } + }) + ->Arg(32) + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::sample(vector)", std_sample); + bm.operator()>("std::sample(deque)", std_sample); + bm.operator()>("std::sample(list)", std_sample); + bm.operator()>("rng::sample(vector)", std::ranges::sample); + bm.operator()>("rng::sample(deque)", std::ranges::sample); + bm.operator()>("rng::sample(list)", std::ranges::sample); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/shift_left.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/shift_left.bench.cpp new file mode 100644 index 0000000000000..b26526484c66a --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/shift_left.bench.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_shift_left = [](auto first, auto last, auto n) { return std::shift_left(first, last, n); }; + + // Benchmark std::shift_left where we shift exactly one element, which is the worst case. + { + auto bm = [](std::string name, auto shift_left) { + benchmark::RegisterBenchmark( + name, + [shift_left](auto& st) { + std::size_t 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::size_t n = 1; + + // To avoid ending up with a fully moved-from range, restore the element that gets + // overwritten by the shift after performing the shift. + auto first_element = c.begin(); + auto last_element = std::next(c.begin(), size - 1); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(n); + ValueType tmp = *first_element; + auto result = shift_left(c.begin(), c.end(), n); + *last_element = std::move(tmp); + benchmark::DoNotOptimize(result); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::shift_left(vector)", std_shift_left); + bm.operator()>("std::shift_left(deque)", std_shift_left); + bm.operator()>("std::shift_left(list)", std_shift_left); + // ranges::shift_left not implemented yet + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/shift_right.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/shift_right.bench.cpp new file mode 100644 index 0000000000000..42946760fc8a3 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/shift_right.bench.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_shift_right = [](auto first, auto last, auto n) { return std::shift_right(first, last, n); }; + + // Benchmark std::shift_right where we shift exactly one element, which is the worst case. + { + auto bm = [](std::string name, auto shift_right) { + benchmark::RegisterBenchmark( + name, + [shift_right](auto& st) { + std::size_t 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::size_t n = 1; + + // To avoid ending up with a fully moved-from range, restore the element that gets + // overwritten by the shift after performing the shift. + auto first_element = c.begin(); + auto last_element = std::next(c.begin(), size - 1); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(n); + ValueType tmp = *last_element; + auto result = shift_right(c.begin(), c.end(), n); + *first_element = std::move(tmp); + benchmark::DoNotOptimize(result); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::shift_right(vector)", std_shift_right); + bm.operator()>("std::shift_right(deque)", std_shift_right); + bm.operator()>("std::shift_right(list)", std_shift_right); + // ranges::shift_right not implemented yet + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/shuffle.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/shuffle.bench.cpp new file mode 100644 index 0000000000000..24f7fb6828977 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/shuffle.bench.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_shuffle = [](auto first, auto last, auto& rng) { return std::shuffle(first, last, rng); }; + + // {std,ranges}::shuffle(normal container) + { + auto bm = [](std::string name, auto shuffle) { + benchmark::RegisterBenchmark( + name, + [shuffle](auto& st) { + std::size_t 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::mt19937 rng; + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + shuffle(c.begin(), c.end(), rng); + benchmark::DoNotOptimize(c); + } + }) + ->Arg(32) + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::shuffle(vector)", std_shuffle); + bm.operator()>("std::shuffle(deque)", std_shuffle); + bm.operator()>("rng::shuffle(vector)", std::ranges::shuffle); + bm.operator()>("rng::shuffle(deque)", std::ranges::shuffle); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/swap_ranges.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/swap_ranges.bench.cpp new file mode 100644 index 0000000000000..e9fb201a57d34 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/swap_ranges.bench.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_swap_ranges = [](auto first1, auto last1, auto first2, auto) { + return std::swap_ranges(first1, last1, first2); + }; + + // {std,ranges}::swap_ranges(normal container) + { + auto bm = [](std::string name, auto swap_ranges) { + benchmark::RegisterBenchmark( + name, + [swap_ranges](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + Container c1, c2; + std::generate_n(std::back_inserter(c1), size, [] { return Generate::random(); }); + std::generate_n(std::back_inserter(c2), size, [] { return Generate::random(); }); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c1); + benchmark::DoNotOptimize(c2); + auto result = swap_ranges(c1.begin(), c1.end(), c2.begin(), c2.end()); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(c1); + benchmark::DoNotOptimize(c2); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::swap_ranges(vector)", std_swap_ranges); + bm.operator()>("std::swap_ranges(deque)", std_swap_ranges); + bm.operator()>("std::swap_ranges(list)", std_swap_ranges); + bm.operator()>("rng::swap_ranges(vector)", std::ranges::swap_ranges); + bm.operator()>("rng::swap_ranges(deque)", std::ranges::swap_ranges); + bm.operator()>("rng::swap_ranges(list)", std::ranges::swap_ranges); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/transform.binary.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/transform.binary.bench.cpp new file mode 100644 index 0000000000000..c4ea7535aefef --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/transform.binary.bench.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_transform = [](auto first1, auto last1, auto first2, auto, auto out, auto f) { + return std::transform(first1, last1, first2, out, f); + }; + + // {std,ranges}::transform(normal container, normal container) + { + auto bm = [](std::string name, auto transform) { + benchmark::RegisterBenchmark( + name, + [transform](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + Container c1, c2; + std::generate_n(std::back_inserter(c1), size, [] { return Generate::random(); }); + std::generate_n(std::back_inserter(c2), size, [] { return Generate::random(); }); + + std::vector out(size); + + auto f = [](auto x, auto y) { + benchmark::DoNotOptimize(x); + benchmark::DoNotOptimize(y); + return x + y; + }; + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c1); + benchmark::DoNotOptimize(c2); + benchmark::DoNotOptimize(out); + auto result = transform(c1.begin(), c1.end(), c2.begin(), c2.end(), out.begin(), f); + benchmark::DoNotOptimize(result); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::transform(vector, vector)", std_transform); + bm.operator()>("std::transform(deque, deque)", std_transform); + bm.operator()>("std::transform(list, list)", std_transform); + bm.operator()>("rng::transform(vector, vector)", std::ranges::transform); + bm.operator()>("rng::transform(deque, deque)", std::ranges::transform); + bm.operator()>("rng::transform(list, list)", std::ranges::transform); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/transform.unary.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/transform.unary.bench.cpp new file mode 100644 index 0000000000000..9ae40cb488085 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/transform.unary.bench.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_transform = [](auto first, auto last, auto out, auto f) { return std::transform(first, last, out, f); }; + + // {std,ranges}::transform(normal container) + { + auto bm = [](std::string name, auto transform) { + benchmark::RegisterBenchmark( + name, + [transform](auto& st) { + std::size_t 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); + + auto f = [](auto element) { + benchmark::DoNotOptimize(element); + return element; + }; + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); + auto result = transform(c.begin(), c.end(), out.begin(), f); + benchmark::DoNotOptimize(result); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + bm.operator()>("std::transform(vector) (identity transform)", std_transform); + bm.operator()>("std::transform(deque) (identity transform)", std_transform); + bm.operator()>("std::transform(list) (identity transform)", std_transform); + bm.operator()>("rng::transform(vector) (identity transform)", std::ranges::transform); + bm.operator()>("rng::transform(deque) (identity transform)", std::ranges::transform); + bm.operator()>("rng::transform(list) (identity transform)", std::ranges::transform); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/unique.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/unique.bench.cpp new file mode 100644 index 0000000000000..c0aee942eef64 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/unique.bench.cpp @@ -0,0 +1,171 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_unique = [](auto first, auto last) { return std::unique(first, last); }; + auto std_unique_pred = [](auto first, auto last) { + return std::unique(first, last, [](auto a, auto b) { + benchmark::DoNotOptimize(a); + benchmark::DoNotOptimize(b); + return a == b; + }); + }; + auto ranges_unique_pred = [](auto first, auto last) { + return std::ranges::unique(first, last, [](auto a, auto b) { + benchmark::DoNotOptimize(a); + benchmark::DoNotOptimize(b); + return a == b; + }); + }; + + // Create a sequence of the form xxxxxxxxxxyyyyyyyyyy and unique the + // adjacent equal elements. + // + // We perform this benchmark in a batch because we need to restore the + // state of the container after the operation. + { + auto bm = [](std::string name, auto unique) { + benchmark::RegisterBenchmark( + name, + [unique](auto& st) { + std::size_t const size = st.range(0); + constexpr std::size_t BatchSize = 10; + using ValueType = typename Container::value_type; + Container c[BatchSize]; + ValueType x = Generate::random(); + ValueType y = random_different_from({x}); + auto populate = [&](Container& cont) { + auto half = cont.size() / 2; + std::fill_n(std::fill_n(cont.begin(), half, x), half, y); + }; + for (std::size_t i = 0; i != BatchSize; ++i) { + c[i] = Container(size); + populate(c[i]); + } + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + benchmark::DoNotOptimize(c[i]); + auto result = unique(c[i].begin(), c[i].end()); + benchmark::DoNotOptimize(result); + } + + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + populate(c[i]); + } + st.ResumeTiming(); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + // {std,ranges}::unique(it, it) + bm.operator()>("std::unique(vector) (contiguous)", std_unique); + bm.operator()>("std::unique(deque) (contiguous)", std_unique); + bm.operator()>("std::unique(list) (contiguous)", std_unique); + bm.operator()>("rng::unique(vector) (contiguous)", std::ranges::unique); + bm.operator()>("rng::unique(deque) (contiguous)", std::ranges::unique); + bm.operator()>("rng::unique(list) (contiguous)", std::ranges::unique); + + // {std,ranges}::unique(it, it, pred) + bm.operator()>("std::unique(vector, pred) (contiguous)", std_unique_pred); + bm.operator()>("std::unique(deque, pred) (contiguous)", std_unique_pred); + bm.operator()>("std::unique(list, pred) (contiguous)", std_unique_pred); + bm.operator()>("rng::unique(vector, pred) (contiguous)", ranges_unique_pred); + bm.operator()>("rng::unique(deque, pred) (contiguous)", ranges_unique_pred); + bm.operator()>("rng::unique(list, pred) (contiguous)", ranges_unique_pred); + } + + // Create a sequence of the form xxyyxxyyxxyyxxyyxxyy and unique + // adjacent equal elements. + // + // We perform this benchmark in a batch because we need to restore the + // state of the container after the operation. + { + auto bm = [](std::string name, auto unique) { + benchmark::RegisterBenchmark( + name, + [unique](auto& st) { + std::size_t const size = st.range(0); + constexpr std::size_t BatchSize = 10; + using ValueType = typename Container::value_type; + Container c[BatchSize]; + ValueType x = Generate::random(); + ValueType y = random_different_from({x}); + auto populate = [&](Container& cont) { + assert(cont.size() % 4 == 0); + auto out = cont.begin(); + for (std::size_t i = 0; i != cont.size(); i += 4) { + *out++ = x; + *out++ = x; + *out++ = y; + *out++ = y; + } + }; + for (std::size_t i = 0; i != BatchSize; ++i) { + c[i] = Container(size); + populate(c[i]); + } + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + benchmark::DoNotOptimize(c[i]); + auto result = unique(c[i].begin(), c[i].end()); + benchmark::DoNotOptimize(result); + } + + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + populate(c[i]); + } + st.ResumeTiming(); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + // {std,ranges}::unique(it, it) + bm.operator()>("std::unique(vector) (sprinkled)", std_unique); + bm.operator()>("std::unique(deque) (sprinkled)", std_unique); + bm.operator()>("std::unique(list) (sprinkled)", std_unique); + bm.operator()>("rng::unique(vector) (sprinkled)", std::ranges::unique); + bm.operator()>("rng::unique(deque) (sprinkled)", std::ranges::unique); + bm.operator()>("rng::unique(list) (sprinkled)", std::ranges::unique); + + // {std,ranges}::unique(it, it, pred) + bm.operator()>("std::unique(vector, pred) (sprinkled)", std_unique_pred); + bm.operator()>("std::unique(deque, pred) (sprinkled)", std_unique_pred); + bm.operator()>("std::unique(list, pred) (sprinkled)", std_unique_pred); + bm.operator()>("rng::unique(vector, pred) (sprinkled)", ranges_unique_pred); + bm.operator()>("rng::unique(deque, pred) (sprinkled)", ranges_unique_pred); + bm.operator()>("rng::unique(list, pred) (sprinkled)", ranges_unique_pred); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/modifying/unique_copy.bench.cpp b/libcxx/test/benchmarks/algorithms/modifying/unique_copy.bench.cpp new file mode 100644 index 0000000000000..45b52dd23b695 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/modifying/unique_copy.bench.cpp @@ -0,0 +1,143 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +int main(int argc, char** argv) { + auto std_unique_copy = [](auto first, auto last, auto out) { return std::unique_copy(first, last, out); }; + auto std_unique_copy_pred = [](auto first, auto last, auto out) { + return std::unique_copy(first, last, out, [](auto a, auto b) { + benchmark::DoNotOptimize(a); + benchmark::DoNotOptimize(b); + return a == b; + }); + }; + auto ranges_unique_copy_pred = [](auto first, auto last, auto out) { + return std::ranges::unique_copy(first, last, out, [](auto a, auto b) { + benchmark::DoNotOptimize(a); + benchmark::DoNotOptimize(b); + return a == b; + }); + }; + + // Create a sequence of the form xxxxxxxxxxyyyyyyyyyy and unique the + // adjacent equal elements. + { + auto bm = [](std::string name, auto unique_copy) { + benchmark::RegisterBenchmark( + name, + [unique_copy](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + Container c(size); + ValueType x = Generate::random(); + ValueType y = random_different_from({x}); + auto half = size / 2; + std::fill_n(std::fill_n(c.begin(), half, x), half, y); + + std::vector out(size); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); + auto result = unique_copy(c.begin(), c.end(), out.begin()); + benchmark::DoNotOptimize(result); + } + }) + ->Arg(32) + ->Arg(1024) + ->Arg(8192); + }; + // {std,ranges}::unique_copy(it, it, out) + bm.operator()>("std::unique_copy(vector) (contiguous)", std_unique_copy); + bm.operator()>("std::unique_copy(deque) (contiguous)", std_unique_copy); + bm.operator()>("std::unique_copy(list) (contiguous)", std_unique_copy); + bm.operator()>("rng::unique_copy(vector) (contiguous)", std::ranges::unique_copy); + bm.operator()>("rng::unique_copy(deque) (contiguous)", std::ranges::unique_copy); + bm.operator()>("rng::unique_copy(list) (contiguous)", std::ranges::unique_copy); + + // {std,ranges}::unique_copy(it, it, out, pred) + bm.operator()>("std::unique_copy(vector, pred) (contiguous)", std_unique_copy_pred); + bm.operator()>("std::unique_copy(deque, pred) (contiguous)", std_unique_copy_pred); + bm.operator()>("std::unique_copy(list, pred) (contiguous)", std_unique_copy_pred); + bm.operator()>("rng::unique_copy(vector, pred) (contiguous)", ranges_unique_copy_pred); + bm.operator()>("rng::unique_copy(deque, pred) (contiguous)", ranges_unique_copy_pred); + bm.operator()>("rng::unique_copy(list, pred) (contiguous)", ranges_unique_copy_pred); + } + + // Create a sequence of the form xxyyxxyyxxyyxxyyxxyy and unique + // adjacent equal elements. + { + auto bm = [](std::string name, auto unique_copy) { + benchmark::RegisterBenchmark( + name, + [unique_copy](auto& st) { + std::size_t const size = st.range(0); + using ValueType = typename Container::value_type; + Container c(size); + ValueType x = Generate::random(); + ValueType y = random_different_from({x}); + auto populate = [&](Container& cont) { + assert(cont.size() % 4 == 0); + auto out = cont.begin(); + for (std::size_t i = 0; i != cont.size(); i += 4) { + *out++ = x; + *out++ = x; + *out++ = y; + *out++ = y; + } + }; + populate(c); + + std::vector out(size); + + for ([[maybe_unused]] auto _ : st) { + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(out); + auto result = unique_copy(c.begin(), c.end(), out.begin()); + benchmark::DoNotOptimize(result); + } + }) + ->Arg(32) + ->Arg(50) // non power-of-two + ->Arg(1024) + ->Arg(8192); + }; + // {std,ranges}::unique_copy(it, it, out) + bm.operator()>("std::unique_copy(vector) (sprinkled)", std_unique_copy); + bm.operator()>("std::unique_copy(deque) (sprinkled)", std_unique_copy); + bm.operator()>("std::unique_copy(list) (sprinkled)", std_unique_copy); + bm.operator()>("rng::unique_copy(vector) (sprinkled)", std::ranges::unique_copy); + bm.operator()>("rng::unique_copy(deque) (sprinkled)", std::ranges::unique_copy); + bm.operator()>("rng::unique_copy(list) (sprinkled)", std::ranges::unique_copy); + + // {std,ranges}::unique_copy(it, it, out, pred) + bm.operator()>("std::unique_copy(vector, pred) (sprinkled)", std_unique_copy_pred); + bm.operator()>("std::unique_copy(deque, pred) (sprinkled)", std_unique_copy_pred); + bm.operator()>("std::unique_copy(list, pred) (sprinkled)", std_unique_copy_pred); + bm.operator()>("rng::unique_copy(vector, pred) (sprinkled)", ranges_unique_copy_pred); + bm.operator()>("rng::unique_copy(deque, pred) (sprinkled)", ranges_unique_copy_pred); + bm.operator()>("rng::unique_copy(list, pred) (sprinkled)", ranges_unique_copy_pred); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/algorithms/move.bench.cpp b/libcxx/test/benchmarks/algorithms/move.bench.cpp deleted file mode 100644 index 73f36f0c129de..0000000000000 --- a/libcxx/test/benchmarks/algorithms/move.bench.cpp +++ /dev/null @@ -1,71 +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 -#include - -template -void bm_ranges_move_vb(benchmark::State& state) { - auto n = state.range(); - std::vector v1(n, true); - std::vector v2(n, false); - benchmark::DoNotOptimize(v1); - benchmark::DoNotOptimize(v2); - std::vector* in = &v1; - std::vector* out = &v2; - for (auto _ : state) { - if constexpr (aligned) { - benchmark::DoNotOptimize(std::ranges::move(*in, std::ranges::begin(*out))); - } else { - benchmark::DoNotOptimize( - std::ranges::move(std::views::counted(in->begin() + 4, n - 4), std::ranges::begin(*out))); - } - std::swap(in, out); - benchmark::DoNotOptimize(in); - benchmark::DoNotOptimize(out); - } -} - -template -void bm_move_vb(benchmark::State& state) { - auto n = state.range(); - std::vector v1(n, true); - std::vector v2(n, false); - benchmark::DoNotOptimize(v1); - benchmark::DoNotOptimize(v2); - std::vector* in = &v1; - std::vector* out = &v2; - for (auto _ : state) { - auto first1 = in->begin(); - auto last1 = in->end(); - auto first2 = out->begin(); - if constexpr (aligned) { - benchmark::DoNotOptimize(std::move(first1, last1, first2)); - } else { - benchmark::DoNotOptimize(std::move(first1 + 4, last1, first2)); - } - std::swap(in, out); - benchmark::DoNotOptimize(in); - benchmark::DoNotOptimize(out); - } -} - -BENCHMARK(bm_ranges_move_vb) - ->Name("bm_ranges_move_vb_aligned") - ->Range(8, 1 << 16) - ->DenseRange(102400, 204800, 4096); -BENCHMARK(bm_ranges_move_vb)->Name("bm_ranges_move_vb_unaligned")->Range(8, 1 << 20); - -BENCHMARK(bm_move_vb)->Name("bm_move_vb_aligned")->Range(8, 1 << 20); -BENCHMARK(bm_move_vb)->Name("bm_move_vb_unaligned")->Range(8, 1 << 20); - -BENCHMARK_MAIN(); diff --git a/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp deleted file mode 100644 index 23d7395198419..0000000000000 --- a/libcxx/test/benchmarks/algorithms/move_backward.bench.cpp +++ /dev/null @@ -1,71 +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 -#include - -template -void bm_ranges_move_backward_vb(benchmark::State& state) { - auto n = state.range(); - std::vector v1(n, true); - std::vector v2(n, false); - benchmark::DoNotOptimize(v1); - benchmark::DoNotOptimize(v2); - std::vector* in = &v1; - std::vector* out = &v2; - for (auto _ : state) { - if constexpr (aligned) { - benchmark::DoNotOptimize(std::ranges::move_backward(*in, std::ranges::end(*out))); - } else { - benchmark::DoNotOptimize( - std::ranges::move_backward(std::views::counted(in->begin(), n - 4), std::ranges::end(*out))); - } - std::swap(in, out); - benchmark::DoNotOptimize(in); - benchmark::DoNotOptimize(out); - } -} - -template -void bm_move_backward_vb(benchmark::State& state) { - auto n = state.range(); - std::vector v1(n, true); - std::vector v2(n, false); - benchmark::DoNotOptimize(v1); - benchmark::DoNotOptimize(v2); - std::vector* in = &v1; - std::vector* out = &v2; - for (auto _ : state) { - auto first1 = in->begin(); - auto last1 = in->end(); - auto last2 = out->end(); - if constexpr (aligned) { - benchmark::DoNotOptimize(std::move_backward(first1, last1, last2)); - } else { - benchmark::DoNotOptimize(std::move_backward(first1, last1 - 4, last2)); - } - std::swap(in, out); - benchmark::DoNotOptimize(in); - benchmark::DoNotOptimize(out); - } -} - -BENCHMARK(bm_ranges_move_backward_vb) - ->Name("bm_ranges_move_backward_vb_aligned") - ->Range(8, 1 << 16) - ->DenseRange(102400, 204800, 4096); -BENCHMARK(bm_ranges_move_backward_vb)->Name("bm_ranges_move_backward_vb_unaligned")->Range(8, 1 << 20); - -BENCHMARK(bm_move_backward_vb)->Name("bm_move_backward_vb_aligned")->Range(8, 1 << 20); -BENCHMARK(bm_move_backward_vb)->Name("bm_move_backward_vb_unaligned")->Range(8, 1 << 20); - -BENCHMARK_MAIN(); diff --git a/libcxx/test/benchmarks/algorithms/reverse.bench.cpp b/libcxx/test/benchmarks/algorithms/reverse.bench.cpp deleted file mode 100644 index 2d8dd819ac24c..0000000000000 --- a/libcxx/test/benchmarks/algorithms/reverse.bench.cpp +++ /dev/null @@ -1,48 +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 -#include - -#include -#include "../GenerateInput.h" - -template -static void bm_reverse(benchmark::State& state) { - std::size_t const n = state.range(); - std::vector vec; - std::generate_n(std::back_inserter(vec), n, [] { return Generate::cheap(); }); - for (auto _ : state) { - std::reverse(vec.begin(), vec.end()); - benchmark::DoNotOptimize(vec); - } -} -BENCHMARK(bm_reverse)->Name("std::reverse(vector)")->DenseRange(1, 8)->Range(16, 1 << 20); -BENCHMARK(bm_reverse)->Name("std::reverse(vector)")->DenseRange(1, 8)->Range(16, 1 << 20); - -template -static void bm_ranges_reverse(benchmark::State& state) { - std::size_t const n = state.range(); - std::vector vec; - std::generate_n(std::back_inserter(vec), n, [] { return Generate::cheap(); }); - for (auto _ : state) { - std::ranges::reverse(vec.begin(), vec.end()); - benchmark::DoNotOptimize(vec); - } -} -BENCHMARK(bm_ranges_reverse)->Name("ranges::reverse(vector)")->DenseRange(1, 8)->Range(16, 1 << 20); -BENCHMARK(bm_ranges_reverse) - ->Name("ranges::reverse(vector)") - ->DenseRange(1, 8) - ->Range(16, 1 << 20); - -BENCHMARK_MAIN();