[libcxx-commits] [libcxx] [libc++] Rewrite the std::lower_bound benchmark to be more efficient and add an upper_bound benchmark (PR #177180)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jan 26 08:48:17 PST 2026
https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/177180
>From 4f700cf8b3b361126f0bf714f2e0ea07b6afd81d Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Wed, 21 Jan 2026 15:41:43 +0100
Subject: [PATCH 1/2] [libc++] Rewrite the std::lower_bound benchmark to be
more efficient and add an upper_bound benchmark
---
.../algorithms/lower_bound.bench.cpp | 42 ---------
.../nonmodifying/lower_upper_bound.bench.cpp | 86 +++++++++++++++++++
2 files changed, 86 insertions(+), 42 deletions(-)
delete mode 100644 libcxx/test/benchmarks/algorithms/lower_bound.bench.cpp
create mode 100644 libcxx/test/benchmarks/algorithms/nonmodifying/lower_upper_bound.bench.cpp
diff --git a/libcxx/test/benchmarks/algorithms/lower_bound.bench.cpp b/libcxx/test/benchmarks/algorithms/lower_bound.bench.cpp
deleted file mode 100644
index 31fb3597241fc..0000000000000
--- a/libcxx/test/benchmarks/algorithms/lower_bound.bench.cpp
+++ /dev/null
@@ -1,42 +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
-
-#include <algorithm>
-#include <numeric>
-#include <random>
-#include <vector>
-
-#include "common.h"
-
-namespace {
-template <class ValueType>
-struct LowerBound {
- size_t Quantity;
-
- mutable std::mt19937_64 rng{std::random_device{}()};
-
- void run(benchmark::State& state) const {
- runOpOnCopies<ValueType>(state, Quantity, Order::Ascending, BatchSize::CountBatch, [&](auto& Copy) {
- auto result = std::lower_bound(Copy.begin(), Copy.end(), Copy[rng() % Copy.size()]);
- benchmark::DoNotOptimize(result);
- });
- }
-
- std::string name() const { return "BM_LowerBound" + ValueType::name() + "_" + std::to_string(Quantity); }
-};
-} // namespace
-
-int main(int argc, char** argv) {
- benchmark::Initialize(&argc, argv);
- if (benchmark::ReportUnrecognizedArguments(argc, argv))
- return 1;
- makeCartesianProductBenchmark<LowerBound, AllValueTypes>(Quantities);
- benchmark::RunSpecifiedBenchmarks();
-}
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/lower_upper_bound.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/lower_upper_bound.bench.cpp
new file mode 100644
index 0000000000000..e36916f5904fb
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/lower_upper_bound.bench.cpp
@@ -0,0 +1,86 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <forward_list>
+#include <list>
+#include <numeric>
+#include <random>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "../../GenerateInput.h"
+
+int main(int argc, char** argv) {
+ {
+ auto bm = []<class Container>(benchmark::State& state) static {
+ std::mt19937_64 rng{123456};
+
+ using value_type = typename Container::value_type;
+
+ std::vector<value_type> vec;
+ for (int64_t i = 0; i != state.range(); ++i)
+ vec.emplace_back(Generate<typename Container::value_type>::random());
+ std::sort(vec.begin(), vec.end());
+
+ Container c(vec.begin(), vec.end());
+
+ for (auto _ : state) {
+ auto result = std::lower_bound(c.begin(), c.end(), vec[rng() % vec.size()]);
+ benchmark::DoNotOptimize(result);
+ benchmark::DoNotOptimize(vec);
+ }
+ };
+
+ auto register_benchmark = [&]<class Container>(std::type_identity<Container>, std::string name) {
+ benchmark::RegisterBenchmark(name, bm.template operator()<Container>)->Arg(8)->Arg(100)->Arg(8192);
+ };
+
+ register_benchmark(std::type_identity<std::vector<int>>{}, "std::lower_bound(std::vector<int>)");
+ register_benchmark(std::type_identity<std::deque<int>>{}, "std::lower_bound(std::deque<int>)");
+ register_benchmark(std::type_identity<std::list<int>>{}, "std::lower_bound(std::list<int>)");
+ register_benchmark(std::type_identity<std::forward_list<int>>{}, "std::lower_bound(std::forward_list<int>)");
+ }
+ {
+ auto bm = []<class Container>(benchmark::State& state) static {
+ std::mt19937_64 rng{123456};
+
+ using value_type = typename Container::value_type;
+
+ std::vector<value_type> vec;
+ for (int64_t i = 0; i != state.range(); ++i)
+ vec.emplace_back(Generate<typename Container::value_type>::random());
+ std::sort(vec.begin(), vec.end());
+
+ Container c(vec.begin(), vec.end());
+
+ for (auto _ : state) {
+ auto result = std::upper_bound(c.begin(), c.end(), vec[rng() % vec.size()]);
+ benchmark::DoNotOptimize(result);
+ benchmark::DoNotOptimize(vec);
+ }
+ };
+
+ auto register_benchmark = [&]<class Container>(std::type_identity<Container>, std::string name) {
+ benchmark::RegisterBenchmark(name, bm.template operator()<Container>)->Arg(8)->Arg(100)->Arg(8192);
+ };
+
+ register_benchmark(std::type_identity<std::vector<int>>{}, "std::upper_bound(std::vector<int>)");
+ register_benchmark(std::type_identity<std::deque<int>>{}, "std::upper_bound(std::deque<int>)");
+ register_benchmark(std::type_identity<std::list<int>>{}, "std::upper_bound(std::list<int>)");
+ register_benchmark(std::type_identity<std::forward_list<int>>{}, "std::upper_bound(std::forward_list<int>)");
+ }
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
>From eb42de68569cca03dce5a04296db1a3224b087f3 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 26 Jan 2026 11:48:09 -0500
Subject: [PATCH 2/2] Apply suggestions from code review
---
.../algorithms/nonmodifying/lower_upper_bound.bench.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/test/benchmarks/algorithms/nonmodifying/lower_upper_bound.bench.cpp b/libcxx/test/benchmarks/algorithms/nonmodifying/lower_upper_bound.bench.cpp
index e36916f5904fb..eeb6b880ee6fb 100644
--- a/libcxx/test/benchmarks/algorithms/nonmodifying/lower_upper_bound.bench.cpp
+++ b/libcxx/test/benchmarks/algorithms/nonmodifying/lower_upper_bound.bench.cpp
@@ -21,7 +21,7 @@
int main(int argc, char** argv) {
{
- auto bm = []<class Container>(benchmark::State& state) static {
+ auto bm = []<class Container>(benchmark::State& state) {
std::mt19937_64 rng{123456};
using value_type = typename Container::value_type;
@@ -50,7 +50,7 @@ int main(int argc, char** argv) {
register_benchmark(std::type_identity<std::forward_list<int>>{}, "std::lower_bound(std::forward_list<int>)");
}
{
- auto bm = []<class Container>(benchmark::State& state) static {
+ auto bm = []<class Container>(benchmark::State& state) {
std::mt19937_64 rng{123456};
using value_type = typename Container::value_type;
More information about the libcxx-commits
mailing list