[libcxx-commits] [libcxx] [libc++] added benchmarks for `string::append()` (PR #213990)

Pavel Novikov via libcxx-commits libcxx-commits at lists.llvm.org
Fri Aug 7 02:35:07 PDT 2026


https://github.com/toughengineer updated https://github.com/llvm/llvm-project/pull/213990

>From 90f4e8a1d12578e6127b82d78dc4342bc8de73be Mon Sep 17 00:00:00 2001
From: Pavel Novikov <dev-ape at yandex.ru>
Date: Tue, 4 Aug 2026 19:00:35 +0300
Subject: [PATCH 1/3] [libc++] added benchmarks for `string::append()`

---
 .../benchmarks/containers/string.bench.cpp    | 55 +++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/libcxx/test/benchmarks/containers/string.bench.cpp b/libcxx/test/benchmarks/containers/string.bench.cpp
index 26e2f62ad57fe..62ef95d6a6d0f 100644
--- a/libcxx/test/benchmarks/containers/string.bench.cpp
+++ b/libcxx/test/benchmarks/containers/string.bench.cpp
@@ -43,6 +43,25 @@ void bench(std::string name, Func func, Mod modifier = {}) {
 #endif
 }
 
+template <typename Iterator>
+struct unoptimizable_forward_iterator : Iterator {
+  using iterator_category = std::forward_iterator_tag;
+
+  unoptimizable_forward_iterator(Iterator i) : Iterator{i} {}
+
+  _LIBCPP_NOINLINE unoptimizable_forward_iterator& operator++() {
+    ++static_cast<Iterator&>(*this);
+    return *this;
+  }
+  unoptimizable_forward_iterator operator++(int) {
+    auto it = *this;
+    this->operator++();
+    return it;
+  }
+};
+template <typename Iterator>
+unoptimizable_forward_iterator(Iterator) -> unoptimizable_forward_iterator<Iterator>;
+
 int main(int argc, char** argv) {
   // [string.cons]
   bench("std::basic_string::ctor()", []<class CharT>(std::type_identity<CharT>, benchmark::State& state) {
@@ -498,6 +517,42 @@ int main(int argc, char** argv) {
           [](auto bm) { bm->Arg(large_size); }); // for naming
   }
 
+  {
+    static auto bench_impl =
+        []<size_t size, bool opaque, class CharT>(
+            std::integral_constant<size_t, size>,
+            std::bool_constant<opaque>,
+            std::type_identity<CharT>,
+            benchmark::State& state) {
+          std::basic_string<CharT> src(size, 'a');
+          std::basic_string<CharT> string = src;
+          for (auto _ : state) {
+            benchmark::DoNotOptimize(string);
+            string.clear();
+            if constexpr (opaque)
+              benchmark::DoNotOptimize(src);
+            benchmark::DoNotOptimize(
+                string.append(unoptimizable_forward_iterator(src.begin()), unoptimizable_forward_iterator(src.end())));
+          }
+        };
+
+    bench("std::basic_string::append(ForwardIt, ForwardIt) (opaque)",
+          std::bind_front(bench_impl, std::integral_constant<size_t, small_size>{}, std::true_type{}),
+          [](auto bm) { bm->Arg(small_size); }); // for naming
+
+    bench("std::basic_string::append(ForwardIt, ForwardIt) (opaque)",
+          std::bind_front(bench_impl, std::integral_constant<size_t, large_size>{}, std::true_type{}),
+          [](auto bm) { bm->Arg(large_size); }); // for naming
+
+    bench("std::basic_string::append(ForwardIt, ForwardIt) (transparent)",
+          std::bind_front(bench_impl, std::integral_constant<size_t, small_size>{}, std::false_type{}),
+          [](auto bm) { bm->Arg(small_size); }); // for naming
+
+    bench("std::basic_string::append(ForwardIt, ForwardIt) (transparent)",
+          std::bind_front(bench_impl, std::integral_constant<size_t, large_size>{}, std::false_type{}),
+          [](auto bm) { bm->Arg(large_size); }); // for naming
+  }
+
   benchmark::Initialize(&argc, argv);
   benchmark::RunSpecifiedBenchmarks();
   benchmark::Shutdown();

>From 4019a376dc5d34c960fd22b64a02857dc0f10113 Mon Sep 17 00:00:00 2001
From: Pavel Novikov <dev-ape at yandex.ru>
Date: Fri, 7 Aug 2026 12:32:47 +0300
Subject: [PATCH 2/3] [libc++] properly rewrote
 `unoptimizable_forward_iterator`

---
 .../benchmarks/containers/string.bench.cpp    | 40 +++++++++++++------
 1 file changed, 27 insertions(+), 13 deletions(-)

diff --git a/libcxx/test/benchmarks/containers/string.bench.cpp b/libcxx/test/benchmarks/containers/string.bench.cpp
index 62ef95d6a6d0f..37e7a8003fe7d 100644
--- a/libcxx/test/benchmarks/containers/string.bench.cpp
+++ b/libcxx/test/benchmarks/containers/string.bench.cpp
@@ -11,8 +11,9 @@
 #include <algorithm>
 #include <array>
 #include <functional>
+#include <iterator>
 #include <string>
-#include <vector>
+#include <type_traits>
 
 #include "benchmark/benchmark.h"
 #include "make_string.h"
@@ -43,24 +44,37 @@ void bench(std::string name, Func func, Mod modifier = {}) {
 #endif
 }
 
-template <typename Iterator>
-struct unoptimizable_forward_iterator : Iterator {
+template <typename It>
+struct unoptimizable_forward_iterator { // legacy forward iterator that inhibits iteration optimization
+  static_assert(std::is_base_of_v<std::forward_iterator_tag, typename std::iterator_traits<It>::iterator_category>);
+
   using iterator_category = std::forward_iterator_tag;
+  using value_type        = typename std::iterator_traits<It>::value_type;
+  using difference_type   = typename std::iterator_traits<It>::difference_type;
+  using pointer           = typename std::iterator_traits<It>::pointer;
+  using reference         = typename std::iterator_traits<It>::reference;
+
+  unoptimizable_forward_iterator() = default;
+  explicit unoptimizable_forward_iterator(It it) : it_(it) {}
 
-  unoptimizable_forward_iterator(Iterator i) : Iterator{i} {}
+  reference operator*() const { return *it_; }
+  It operator->() const { return it_; }
 
-  _LIBCPP_NOINLINE unoptimizable_forward_iterator& operator++() {
-    ++static_cast<Iterator&>(*this);
+  TEST_NOINLINE unoptimizable_forward_iterator& operator++() {
+    ++it_;
     return *this;
   }
-  unoptimizable_forward_iterator operator++(int) {
-    auto it = *this;
-    this->operator++();
-    return it;
-  }
+  unoptimizable_forward_iterator operator++(int) { return {it_++}; }
+
+  friend bool operator==(const unoptimizable_forward_iterator&, const unoptimizable_forward_iterator&) = default;
+
+  friend It base(const unoptimizable_forward_iterator& i) { return i.it_; }
+
+private:
+  It it_;
 };
-template <typename Iterator>
-unoptimizable_forward_iterator(Iterator) -> unoptimizable_forward_iterator<Iterator>;
+template <typename It>
+unoptimizable_forward_iterator(It) -> unoptimizable_forward_iterator<It>;
 
 int main(int argc, char** argv) {
   // [string.cons]

>From caf2e9a826c96bb1930de2680714bedaec4ea29b Mon Sep 17 00:00:00 2001
From: Pavel Novikov <dev-ape at yandex.ru>
Date: Fri, 7 Aug 2026 12:33:02 +0300
Subject: [PATCH 3/3] [libc++] removed redundant opaqueness from `append()`
 benchmark

---
 .../benchmarks/containers/string.bench.cpp    | 25 +++++--------------
 1 file changed, 6 insertions(+), 19 deletions(-)

diff --git a/libcxx/test/benchmarks/containers/string.bench.cpp b/libcxx/test/benchmarks/containers/string.bench.cpp
index 37e7a8003fe7d..da468ff96a1e3 100644
--- a/libcxx/test/benchmarks/containers/string.bench.cpp
+++ b/libcxx/test/benchmarks/containers/string.bench.cpp
@@ -533,37 +533,24 @@ int main(int argc, char** argv) {
 
   {
     static auto bench_impl =
-        []<size_t size, bool opaque, class CharT>(
-            std::integral_constant<size_t, size>,
-            std::bool_constant<opaque>,
-            std::type_identity<CharT>,
-            benchmark::State& state) {
+        []<size_t size, class CharT>(
+            std::integral_constant<size_t, size>, std::type_identity<CharT>, benchmark::State& state) {
           std::basic_string<CharT> src(size, 'a');
           std::basic_string<CharT> string = src;
           for (auto _ : state) {
             benchmark::DoNotOptimize(string);
             string.clear();
-            if constexpr (opaque)
-              benchmark::DoNotOptimize(src);
             benchmark::DoNotOptimize(
                 string.append(unoptimizable_forward_iterator(src.begin()), unoptimizable_forward_iterator(src.end())));
           }
         };
 
-    bench("std::basic_string::append(ForwardIt, ForwardIt) (opaque)",
-          std::bind_front(bench_impl, std::integral_constant<size_t, small_size>{}, std::true_type{}),
+    bench("std::basic_string::append(ForwardIt, ForwardIt)",
+          std::bind_front(bench_impl, std::integral_constant<size_t, small_size>{}),
           [](auto bm) { bm->Arg(small_size); }); // for naming
 
-    bench("std::basic_string::append(ForwardIt, ForwardIt) (opaque)",
-          std::bind_front(bench_impl, std::integral_constant<size_t, large_size>{}, std::true_type{}),
-          [](auto bm) { bm->Arg(large_size); }); // for naming
-
-    bench("std::basic_string::append(ForwardIt, ForwardIt) (transparent)",
-          std::bind_front(bench_impl, std::integral_constant<size_t, small_size>{}, std::false_type{}),
-          [](auto bm) { bm->Arg(small_size); }); // for naming
-
-    bench("std::basic_string::append(ForwardIt, ForwardIt) (transparent)",
-          std::bind_front(bench_impl, std::integral_constant<size_t, large_size>{}, std::false_type{}),
+    bench("std::basic_string::append(ForwardIt, ForwardIt)",
+          std::bind_front(bench_impl, std::integral_constant<size_t, large_size>{}),
           [](auto bm) { bm->Arg(large_size); }); // for naming
   }
 



More information about the libcxx-commits mailing list