[libcxx-commits] [libcxx] [libc++] Add benchmarks for copy algorithms (PR #127328)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Wed Feb 19 07:30:46 PST 2025


================
@@ -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 <algorithm>
+#include <deque>
+#include <iterator>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "../../GenerateInput.h"
+#include "test_macros.h"
+
+template <class Container, class Operation>
+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<ValueType>::random(); });
+
+    std::vector<ValueType> 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 <bool Aligned, class Operation>
+static void bm_vector_bool(std::string operation_name, Operation copy) {
+  auto bench = [copy](auto& st) {
+    auto n = st.range();
+    std::vector<bool> in(n, true);
+    std::vector<bool> 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::vector<int>>("std::copy(vector<int>)", std_copy);
+  bm_general<std::deque<int>>("std::copy(deque<int>)", std_copy);
+  bm_general<std::list<int>>("std::copy(list<int>)", std_copy);
+  bm_vector_bool<true>("std::copy(vector<bool>) (aligned)", std_copy);
+  bm_vector_bool<false>("std::copy(vector<bool>) (unaligned)", std_copy);
+
+  // ranges::copy
+  bm_general<std::vector<int>>("ranges::copy(vector<int>)", ranges_copy);
+  bm_general<std::deque<int>>("ranges::copy(deque<int>)", ranges_copy);
+  bm_general<std::list<int>>("ranges::copy(list<int>)", ranges_copy);
+#if TEST_STD_VER >= 23 // vector<bool>::iterator is not an output_iterator before C++23
+  bm_vector_bool<true>("ranges::copy(vector<bool>) (aligned)", ranges_copy);
+  bm_vector_bool<false>("ranges::copy(vector<bool>) (unaligned)", ranges_copy);
+#endif
+
+  benchmark::Initialize(&argc, argv);
+  benchmark::RunSpecifiedBenchmarks();
+  benchmark::Shutdown();
----------------
ldionne wrote:

Per our 1:1 just now, it looks like we have consensus on the following:

```c++
int main(int argc, char** argv) {
  auto std_copy = [](auto first, auto last, auto out) { return std::copy(first, last, out); };

  // {std,ranges}::copy(normal container)
  auto bm_general = []<class Container>(std::string operation_name, auto copy) {
    benchmark::RegisterBenchmark(operation_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<ValueType>::random(); });

      std::vector<ValueType> 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);
      }
    })->Range(8, 1 << 20);
  };
  bm_general.operator()<std::vector<int>>("std::copy(vector<int>)", std_copy);
  bm_general.operator()<std::deque<int>>("std::copy(deque<int>)", std_copy);
  bm_general.operator()<std::list<int>>("std::copy(list<int>)", std_copy);
  bm_general.operator()<std::vector<int>>("ranges::copy(vector<int>)", std::ranges::copy);
  bm_general.operator()<std::deque<int>>("ranges::copy(deque<int>)", std::ranges::copy);
  bm_general.operator()<std::list<int>>("ranges::copy(list<int>)", std::ranges::copy);

  // {std,ranges}::copy(vector<bool>)
  auto bm_vector_bool = []<bool Aligned>(std::string operation_name, auto copy) {
    benchmark::RegisterBenchmark(operation_name, [copy](auto& st) {
      std::size_t const n = st.range(0);
      std::vector<bool> in(n, true);
      std::vector<bool> 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_vector_bool.operator()<true>("std::copy(vector<bool>) (aligned)", std_copy);
  bm_vector_bool.operator()<false>("std::copy(vector<bool>) (unaligned)", std_copy);
#if TEST_STD_VER >= 23 // vector<bool>::iterator is not an output_iterator before C++23
  bm_vector_bool.operator()<true>("ranges::copy(vector<bool>) (aligned)", std::ranges::copy);
  bm_vector_bool.operator()<false>("ranges::copy(vector<bool>) (unaligned)", std::ranges::copy);
#endif

  benchmark::Initialize(&argc, argv);
  benchmark::RunSpecifiedBenchmarks();
  benchmark::Shutdown();
  return 0;
}
```

https://github.com/llvm/llvm-project/pull/127328


More information about the libcxx-commits mailing list