[libcxx-commits] [libcxx] [libc++] Optimize ranges::copy for random_access_iterator inputs and vector<bool> iterator outputs (PR #120134)
Peng Liu via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jun 26 05:51:36 PDT 2025
================
@@ -448,6 +449,173 @@ void sequence_container_benchmarks(std::string container) {
}
});
}
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ // Additional benchmarks for vector<bool> iterator-pair and range-based operations
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+
+ static constexpr bool is_vector_bool = requires {
+ typename Container::allocator_type;
+ } && std::same_as<std::remove_cvref_t<Container>, std::vector<bool, typename Container::allocator_type>>;
+
+ if constexpr (is_vector_bool) {
+ auto bench_vb = [&](std::string operation, auto f) {
+ benchmark::RegisterBenchmark(container + "::" + operation, f)->Arg(1024)->Arg(1 << 16)->Arg(1 << 20);
+ };
+
+ { // iterator-pair ctor
+ auto bm = [&generators, &bench_vb, &tostr]<template <class> class Iter>(std::string iter) {
+ for (auto gen : generators)
+ bench_vb("ctor(" + iter + ", " + iter + ")" + tostr(gen), [gen](auto& st) {
+ auto const size = st.range(0);
+ std::vector<int> in;
+ std::generate_n(std::back_inserter(in), size, gen);
+ benchmark::DoNotOptimize(in);
+ const auto begin = Iter(in.begin());
+ const auto end = Iter(in.end());
+ benchmark::DoNotOptimize(in);
+
+ for ([[maybe_unused]] auto _ : st) {
+ Container c(begin, end); // we assume the destructor doesn't dominate the benchmark
+ DoNotOptimizeData(c);
+ }
+ });
+ };
+ bm.template operator()<random_access_iterator>("ra_iter");
+ }
+ { // iterator-pair assignment
+ auto bm = [&generators, &bench_vb, &tostr]<template <class> class Iter>(std::string iter) {
+ for (auto gen : generators)
+ bench_vb("assign(" + iter + ", " + iter + ")" + tostr(gen), [gen](auto& st) {
+ auto const size = st.range(0);
+ std::vector<int> in1, in2;
+ std::generate_n(std::back_inserter(in1), size, gen);
+ std::generate_n(std::back_inserter(in2), size, gen);
+ DoNotOptimizeData(in1);
+ DoNotOptimizeData(in2);
+
+ Container c(in1.begin(), in1.end());
+ bool toggle = true;
+ for ([[maybe_unused]] auto _ : st) {
+ auto& in = toggle ? in2 : in1;
+ c.assign(Iter(in.begin()), Iter(in.end()));
+ toggle = !toggle;
+ DoNotOptimizeData(c);
+ }
+ });
+ };
+ bm.template operator()<random_access_iterator>("ra_iter");
+ }
+ { // Iterator-pair insertion
+ auto bm = [&generators, &bench_vb, &tostr]<template <class> class Iter>(std::string iter) {
+ for (auto gen : generators)
+ bench_vb("insert(begin, " + iter + ", " + iter + ")" + tostr(gen), [gen](auto& st) {
+ auto const size = st.range(0);
+ std::vector<int> in;
+ Container c;
+ std::generate_n(std::back_inserter(in), size, gen);
+ std::generate_n(std::back_inserter(c), size, gen);
+ DoNotOptimizeData(in);
+ DoNotOptimizeData(c);
+
+ for ([[maybe_unused]] auto _ : st) {
+ c.insert(c.begin(), Iter(in.begin()), Iter(in.end()));
+ c.erase(c.begin() + size, c.end()); // avoid growing indefinitely
+ DoNotOptimizeData(c);
+ }
+ });
+ };
+ bm.template operator()<random_access_iterator>("ra_iter");
+ }
+
+#if defined(__cpp_lib_containers_ranges) && __cpp_lib_containers_ranges >= 202202L
+ { // Range-ctor
+ auto bm = [&generators, &bench_vb, &tostr]<template <class, class> class Range>(std::string range) {
+ for (auto gen : generators)
+ bench_vb("ctor(" + range + ")" + tostr(gen), [gen](auto& st) {
+ auto const size = st.range(0);
+ std::vector<int> in;
+ std::generate_n(std::back_inserter(in), size, gen);
+ Range rg(std::ranges::begin(in), std::ranges::end(in));
+ benchmark::DoNotOptimize(in);
+
+ for ([[maybe_unused]] auto _ : st) {
+ Container c(std::from_range, rg); // we assume the destructor doesn't dominate the benchmark
+ DoNotOptimizeData(c);
+ }
+ });
+ };
+ bm.template operator()<random_access_range_wrapper>("ra_range");
+ }
+ { // Range-assignment
+ auto bm = [&generators, &bench_vb, &tostr]<template <class, class> class Range>(std::string range) {
+ for (auto gen : generators)
+ bench_vb("assign_range(" + range + ")" + tostr(gen), [gen](auto& st) {
+ auto const size = st.range(0);
+ std::vector<int> in1, in2;
+ std::generate_n(std::back_inserter(in1), size, gen);
+ std::generate_n(std::back_inserter(in2), size, gen);
+ Range rg1(std::ranges::begin(in1), std::ranges::end(in1));
+ Range rg2(std::ranges::begin(in2), std::ranges::end(in2));
+ DoNotOptimizeData(in1);
+ DoNotOptimizeData(in2);
+
+ Container c(std::from_range, rg1);
+ bool toggle = true;
+ for ([[maybe_unused]] auto _ : st) {
+ auto& in = toggle ? rg2 : rg1;
+ c.assign_range(in);
+ toggle = !toggle;
+ DoNotOptimizeData(c);
+ }
+ });
+ };
+ bm.template operator()<random_access_range_wrapper>("ra_range");
+ }
+ { // Range-insertion
+ auto bm = [&generators, &bench_vb, &tostr]<template <class, class> class Range>(std::string range) {
+ for (auto gen : generators)
+ bench_vb("insert_range(" + range + ")" + tostr(gen), [gen](auto& st) {
+ auto const size = st.range(0);
+ std::vector<int> in;
+ Container c;
+ std::generate_n(std::back_inserter(in), size, gen);
+ std::generate_n(std::back_inserter(c), size, gen);
+ Range rg(std::ranges::begin(in), std::ranges::end(in));
+ DoNotOptimizeData(in);
+ DoNotOptimizeData(c);
+
+ for ([[maybe_unused]] auto _ : st) {
+ c.insert_range(c.begin(), in);
----------------
winner245 wrote:
Done.
https://github.com/llvm/llvm-project/pull/120134
More information about the libcxx-commits
mailing list