[libcxx-commits] [libcxx] 7ba7d76 - [libc++] Make the associative container query benchmarks more representative (#183036)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Mar 13 06:48:12 PDT 2026


Author: Nikolas Klauser
Date: 2026-03-13T09:48:07-04:00
New Revision: 7ba7d76c8614b0a8d8220816b3c8c83c2510b3c9

URL: https://github.com/llvm/llvm-project/commit/7ba7d76c8614b0a8d8220816b3c8c83c2510b3c9
DIFF: https://github.com/llvm/llvm-project/commit/7ba7d76c8614b0a8d8220816b3c8c83c2510b3c9.diff

LOG: [libc++] Make the associative container query benchmarks more representative (#183036)

Currently the query benchmarks are training the branch predictor
incredibly well, which isn't representative of the real world. This
change causes the branch misses to go from <1% to ~50% with the current
implementation of `__tree::__find_end`.

This patch also removes the `non-existent` benchmarks, since it'd be
non-trivial to write a representative benchmark for that case, and the
benchmark would be relatively low value. We're already searching to leaf
nodes ~50% of the time (since half the nodes are leaves) with the
current benchmark. So we'd only additionally cover a relatively trivial
failure branch that is only taken once per function call. The loop is
already covered through benchmarking with keys existing in the
container.

Added: 
    

Modified: 
    libcxx/test/benchmarks/containers/associative/associative_container_benchmarks.h

Removed: 
    


################################################################################
diff  --git a/libcxx/test/benchmarks/containers/associative/associative_container_benchmarks.h b/libcxx/test/benchmarks/containers/associative/associative_container_benchmarks.h
index cc7b6f4d23a9a..a55f187d2ac80 100644
--- a/libcxx/test/benchmarks/containers/associative/associative_container_benchmarks.h
+++ b/libcxx/test/benchmarks/containers/associative/associative_container_benchmarks.h
@@ -687,74 +687,32 @@ void associative_container_benchmarks(std::string container) {
   /////////////////////////
   // Query
   /////////////////////////
-  auto with_existent_key = [=](auto func) {
+  auto query_bench = [=](auto func) {
     return [=](auto& st) {
       const std::size_t size = st.range(0);
       std::vector<Value> in  = make_value_types(generate_unique_keys(size));
-      // Pick any `BatchSize` number of elements
-      std::vector<Key> keys;
-      for (std::size_t i = 0; i < in.size(); i += (in.size() / BatchSize)) {
-        keys.push_back(get_key(in.at(i)));
-      }
       Container c(in.begin(), in.end());
 
-      while (st.KeepRunningBatch(BatchSize)) {
-        for (std::size_t i = 0; i != keys.size(); ++i) { // possible empty keys when Arg(0)
-          auto result = func(c, keys[i]);
-          benchmark::DoNotOptimize(c);
-          benchmark::DoNotOptimize(result);
-          benchmark::ClobberMemory();
-        }
-      }
-    };
-  };
-
-  auto with_nonexistent_key = [=](auto func) {
-    return [=](auto& st) {
-      const std::size_t size = st.range(0);
-      std::vector<Value> in  = make_value_types(generate_unique_keys(size + BatchSize));
-      std::vector<Key> keys;
-      for (std::size_t i = 0; i != BatchSize; ++i) {
-        keys.push_back(get_key(in.back()));
-        in.pop_back();
-      }
-      Container c(in.begin(), in.end());
-
-      while (st.KeepRunningBatch(BatchSize)) {
-        for (std::size_t i = 0; i != BatchSize; ++i) {
-          auto result = func(c, keys[i]);
-          benchmark::DoNotOptimize(c);
-          benchmark::DoNotOptimize(result);
-          benchmark::ClobberMemory();
-        }
+      for (auto _ : st) {
+        auto result = func(c, get_key(in[getRandomEngine()() % in.size()]));
+        benchmark::DoNotOptimize(c);
+        benchmark::DoNotOptimize(result);
+        benchmark::ClobberMemory();
       }
     };
   };
 
-  auto find = [](Container const& c, Key const& key) { return c.find(key); };
-  bench_non_empty("find(key) (existent)", with_existent_key(find));
-  bench("find(key) (non-existent)", with_nonexistent_key(find));
-
-  auto count = [](Container const& c, Key const& key) { return c.count(key); };
-  bench_non_empty("count(key) (existent)", with_existent_key(count));
-  bench("count(key) (non-existent)", with_nonexistent_key(count));
-
-  auto contains = [](Container const& c, Key const& key) { return c.contains(key); };
-  bench_non_empty("contains(key) (existent)", with_existent_key(contains));
-  bench("contains(key) (non-existent)", with_nonexistent_key(contains));
+  bench_non_empty("find(key)", query_bench([](Container const& c, Key const& key) { return c.find(key); }));
+  bench_non_empty("count(key)", query_bench([](Container const& c, Key const& key) { return c.count(key); }));
+  bench_non_empty("contains(key)", query_bench([](Container const& c, Key const& key) { return c.contains(key); }));
 
   if constexpr (is_ordered_container) {
-    auto lower_bound = [](Container const& c, Key const& key) { return c.lower_bound(key); };
-    bench_non_empty("lower_bound(key) (existent)", with_existent_key(lower_bound));
-    bench("lower_bound(key) (non-existent)", with_nonexistent_key(lower_bound));
-
-    auto upper_bound = [](Container const& c, Key const& key) { return c.upper_bound(key); };
-    bench_non_empty("upper_bound(key) (existent)", with_existent_key(upper_bound));
-    bench("upper_bound(key) (non-existent)", with_nonexistent_key(upper_bound));
-
-    auto equal_range = [](Container const& c, Key const& key) { return c.equal_range(key); };
-    bench_non_empty("equal_range(key) (existent)", with_existent_key(equal_range));
-    bench("equal_range(key) (non-existent)", with_nonexistent_key(equal_range));
+    bench_non_empty(
+        "lower_bound(key)", query_bench([](Container const& c, Key const& key) { return c.lower_bound(key); }));
+    bench_non_empty(
+        "upper_bound(key)", query_bench([](Container const& c, Key const& key) { return c.upper_bound(key); }));
+    bench_non_empty(
+        "equal_range(key)", query_bench([](Container const& c, Key const& key) { return c.equal_range(key); }));
   }
 }
 


        


More information about the libcxx-commits mailing list