[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