[libcxx-commits] [libcxx] [libcxx] Avoid hash key in __hash_table::find() if it is empty. (PR #126837)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu May 8 00:29:49 PDT 2025


https://github.com/xbcnn updated https://github.com/llvm/llvm-project/pull/126837

>From 0f93eba81b388211c80da1eeb2f9ad35a9f75947 Mon Sep 17 00:00:00 2001
From: yangxiaobing <yangxiaobing at jwzg.com>
Date: Tue, 11 Feb 2025 18:16:09 +0800
Subject: [PATCH 1/6] [libcxx] Avoid hash key in __hash_table::find() if no
 buckets yet.

If the hash table has no buckets yet, it's empty and the find will do fast
return end().  Then compute hash key is useless and can be avoided, since
it could be expensive for some key types, such as long string.

This is a small optimization but useful in cases like a checklist (
implemented as unordered_set) that is mostly empty.
---
 libcxx/include/__hash_table | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table
index d7b312f8774fc..a1d06d07f7c8d 100644
--- a/libcxx/include/__hash_table
+++ b/libcxx/include/__hash_table
@@ -1771,9 +1771,9 @@ template <class _Tp, class _Hash, class _Equal, class _Alloc>
 template <class _Key>
 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k) {
-  size_t __hash  = hash_function()(__k);
   size_type __bc = bucket_count();
   if (__bc != 0) {
+    size_t __hash       = hash_function()(__k);
     size_t __chash      = std::__constrain_hash(__hash, __bc);
     __next_pointer __nd = __bucket_list_[__chash];
     if (__nd != nullptr) {
@@ -1792,9 +1792,9 @@ template <class _Tp, class _Hash, class _Equal, class _Alloc>
 template <class _Key>
 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k) const {
-  size_t __hash  = hash_function()(__k);
   size_type __bc = bucket_count();
   if (__bc != 0) {
+    size_t __hash       = hash_function()(__k);
     size_t __chash      = std::__constrain_hash(__hash, __bc);
     __next_pointer __nd = __bucket_list_[__chash];
     if (__nd != nullptr) {

>From a2f7b3c549b63ce9669c025c863980da27481b50 Mon Sep 17 00:00:00 2001
From: yangxiaobing <yangxiaobing at jwzg.com>
Date: Thu, 13 Feb 2025 16:33:13 +0800
Subject: [PATCH 2/6] Add benchmarks.

---
 .../associative/hash_table_find.bench.cpp     | 70 +++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100644 libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp

diff --git a/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp b/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp
new file mode 100644
index 0000000000000..e6f0ae79caef3
--- /dev/null
+++ b/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp
@@ -0,0 +1,70 @@
+#include <unordered_set>
+#include <string>
+#include <random>
+#include <vector>
+
+#include "../../GenerateInput.h"
+#include "benchmark/benchmark.h"
+
+// Generate random strings of at least 32 chars
+struct LongStringGenerator {
+  static std::vector<std::string> cached_strings;
+
+  static void ensure_strings(size_t count) {
+    cached_strings.clear();
+
+    std::mt19937_64 gen(42); // Fixed seed for reproducibility
+    std::uniform_int_distribution<size_t> len_dist(32, 128);
+
+    cached_strings.reserve(count);
+    for (size_t i = 0; i < count; i++) {
+      std::string str(len_dist(gen), 0);
+      for (char& c : str) {
+        c = 'a' + (gen() % 26);
+      }
+      cached_strings.push_back(std::move(str));
+    }
+  }
+
+  const std::string& generate(size_t i) { return cached_strings[i]; }
+};
+
+std::vector<std::string> LongStringGenerator::cached_strings;
+[[maybe_unused]] auto dummy = [] { // Pre-generate 32K strings
+  LongStringGenerator::ensure_strings(1 << 15);
+  return 0;
+}();
+
+template <class Gen>
+static void BM_UnorderedSet_Find_EmptySet(benchmark::State& state, Gen g) {
+  const size_t lookup_count = state.range(0);
+  std::unordered_set<std::string> s; // Empty set
+
+  for (auto _ : state) {
+    for (size_t i = 0; i < lookup_count; i++) {
+      benchmark::DoNotOptimize(s.find(g.generate(i)));
+    }
+  }
+}
+
+template <class Gen>
+static void BM_UnorderedSet_Find(benchmark::State& state, Gen g) {
+  const size_t lookup_count = state.range(0);
+  std::unordered_set<std::string> s{"hello"};  // Non-empty set
+
+  for (auto _ : state) {
+    for (size_t i = 0; i < lookup_count; i++) {
+      benchmark::DoNotOptimize(s.find(g.generate(i)));
+    }
+  }
+}
+
+BENCHMARK_CAPTURE(BM_UnorderedSet_Find_EmptySet, long_string, LongStringGenerator())
+    ->RangeMultiplier(2)
+    ->Range(1 << 10, 1 << 15); // Test from 1K to 32K lookups
+
+BENCHMARK_CAPTURE(BM_UnorderedSet_Find, long_string, LongStringGenerator())
+    ->RangeMultiplier(2)
+    ->Range(1 << 10, 1 << 15); // Test from 1K to 32K lookups
+
+BENCHMARK_MAIN();

>From 96ef4a128145d14e093f878258e5f49f4f7b573d Mon Sep 17 00:00:00 2001
From: yangxiaobing <yangxiaobing at jwzg.com>
Date: Fri, 14 Feb 2025 08:52:59 +0800
Subject: [PATCH 3/6] Fix clang-format issue.

---
 .../benchmarks/containers/associative/hash_table_find.bench.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp b/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp
index e6f0ae79caef3..93fddac02ee6f 100644
--- a/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp
+++ b/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp
@@ -50,7 +50,7 @@ static void BM_UnorderedSet_Find_EmptySet(benchmark::State& state, Gen g) {
 template <class Gen>
 static void BM_UnorderedSet_Find(benchmark::State& state, Gen g) {
   const size_t lookup_count = state.range(0);
-  std::unordered_set<std::string> s{"hello"};  // Non-empty set
+  std::unordered_set<std::string> s{"hello"}; // Non-empty set
 
   for (auto _ : state) {
     for (size_t i = 0; i < lookup_count; i++) {

>From bc3ce69cfa55766f24c7751e33c57874eaf76395 Mon Sep 17 00:00:00 2001
From: yangxiaobing <yangxiaobing at jwzg.com>
Date: Fri, 14 Feb 2025 14:29:16 +0800
Subject: [PATCH 4/6] Add license header and UNSUPPORTED

---
 .../containers/associative/hash_table_find.bench.cpp   | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp b/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp
index 93fddac02ee6f..874d4a44186e7 100644
--- a/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp
+++ b/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp
@@ -1,3 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
 #include <unordered_set>
 #include <string>
 #include <random>

>From 0102da7acc9ec4a8c17825b82b8507cd6a5cbf73 Mon Sep 17 00:00:00 2001
From: yangxiaobing <yangxiaobing at jwzg.com>
Date: Mon, 17 Feb 2025 10:34:36 +0800
Subject: [PATCH 5/6] Add size check to __hash_table::find() and update
 benchmark cases

---
 libcxx/include/__hash_table                   |  4 +--
 .../associative/hash_table_find.bench.cpp     | 33 ++++++++++++++-----
 2 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table
index a1d06d07f7c8d..60f292c86719a 100644
--- a/libcxx/include/__hash_table
+++ b/libcxx/include/__hash_table
@@ -1772,7 +1772,7 @@ template <class _Key>
 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k) {
   size_type __bc = bucket_count();
-  if (__bc != 0) {
+  if (__bc != 0 && size() != 0) {
     size_t __hash       = hash_function()(__k);
     size_t __chash      = std::__constrain_hash(__hash, __bc);
     __next_pointer __nd = __bucket_list_[__chash];
@@ -1793,7 +1793,7 @@ template <class _Key>
 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k) const {
   size_type __bc = bucket_count();
-  if (__bc != 0) {
+  if (__bc != 0 && size() != 0) {
     size_t __hash       = hash_function()(__k);
     size_t __chash      = std::__constrain_hash(__hash, __bc);
     __next_pointer __nd = __bucket_list_[__chash];
diff --git a/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp b/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp
index 874d4a44186e7..5eea4f8a7219f 100644
--- a/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp
+++ b/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03
+// UNSUPPORTED: c++03, c++11, c++14, c++17
 
 #include <unordered_set>
 #include <string>
@@ -46,9 +46,9 @@ std::vector<std::string> LongStringGenerator::cached_strings;
 }();
 
 template <class Gen>
-static void BM_UnorderedSet_Find_EmptySet(benchmark::State& state, Gen g) {
+static void BM_UnorderedSet_Find_EmptyNoBuckets(benchmark::State& state, Gen g) {
   const size_t lookup_count = state.range(0);
-  std::unordered_set<std::string> s; // Empty set
+  std::unordered_set<std::string> s; // Empty and no buckets
 
   for (auto _ : state) {
     for (size_t i = 0; i < lookup_count; i++) {
@@ -58,9 +58,10 @@ static void BM_UnorderedSet_Find_EmptySet(benchmark::State& state, Gen g) {
 }
 
 template <class Gen>
-static void BM_UnorderedSet_Find(benchmark::State& state, Gen g) {
+static void BM_UnorderedSet_Find_EmptyWithBuckets(benchmark::State& state, Gen g) {
   const size_t lookup_count = state.range(0);
-  std::unordered_set<std::string> s{"hello"}; // Non-empty set
+  std::unordered_set<std::string> s;
+  s.reserve(1); // Still empty but reserved buckets
 
   for (auto _ : state) {
     for (size_t i = 0; i < lookup_count; i++) {
@@ -69,12 +70,28 @@ static void BM_UnorderedSet_Find(benchmark::State& state, Gen g) {
   }
 }
 
-BENCHMARK_CAPTURE(BM_UnorderedSet_Find_EmptySet, long_string, LongStringGenerator())
+template <class Gen>
+static void BM_UnorderedSet_Find_NonEmpty(benchmark::State& state, Gen g) {
+  const size_t lookup_count = state.range(0);
+  std::unordered_set<std::string> s{"hello"};
+
+  for (auto _ : state) {
+    for (size_t i = 0; i < lookup_count; i++) {
+      benchmark::DoNotOptimize(s.find(g.generate(i)));
+    }
+  }
+}
+
+BENCHMARK_CAPTURE(BM_UnorderedSet_Find_EmptyNoBuckets, long_string, LongStringGenerator())
     ->RangeMultiplier(2)
     ->Range(1 << 10, 1 << 15); // Test from 1K to 32K lookups
 
-BENCHMARK_CAPTURE(BM_UnorderedSet_Find, long_string, LongStringGenerator())
+BENCHMARK_CAPTURE(BM_UnorderedSet_Find_EmptyWithBuckets, long_string, LongStringGenerator())
     ->RangeMultiplier(2)
-    ->Range(1 << 10, 1 << 15); // Test from 1K to 32K lookups
+    ->Range(1 << 10, 1 << 15);
+
+BENCHMARK_CAPTURE(BM_UnorderedSet_Find_NonEmpty, long_string, LongStringGenerator())
+    ->RangeMultiplier(2)
+    ->Range(1 << 10, 1 << 15);
 
 BENCHMARK_MAIN();

>From 1de7487453450c6f5c559db9af0b80e40cb28d15 Mon Sep 17 00:00:00 2001
From: yangxiaobing <yangxiaobing at jwzg.com>
Date: Thu, 8 May 2025 14:37:17 +0800
Subject: [PATCH 6/6] Move benchmarks for querying on empty containers to the
 generic tests

For expensive key, such as std::unordered_set<std::string>, the benchmark reulst:

1. With the opt:

-------------------------------------------------------------------------------------------------------------------------------------
Benchmark                                                                                           Time             CPU   Iterations
-------------------------------------------------------------------------------------------------------------------------------------
std::unordered_set<int>::ctor(const&)/32                                                         4717 ns         4718 ns       143456
std::unordered_set<int>::ctor(const&)/1024                                                     160766 ns       160764 ns         4384
std::unordered_set<int>::ctor(const&)/8192                                                    1362608 ns      1362523 ns          544
std::unordered_set<int>::ctor(iterator, iterator) (unsorted sequence)/32                         6493 ns         6493 ns       104416
std::unordered_set<int>::ctor(iterator, iterator) (unsorted sequence)/1024                     204541 ns       204539 ns         3456
std::unordered_set<int>::ctor(iterator, iterator) (unsorted sequence)/8192                    1712671 ns      1712620 ns          416
std::unordered_set<int>::ctor(iterator, iterator) (sorted sequence)/32                           6533 ns         6534 ns       107136
std::unordered_set<int>::ctor(iterator, iterator) (sorted sequence)/1024                       202608 ns       202603 ns         3456
std::unordered_set<int>::ctor(iterator, iterator) (sorted sequence)/8192                      1707584 ns      1707476 ns          416
std::unordered_set<int>::operator=(const&)/32                                                    4814 ns         4814 ns       147424
std::unordered_set<int>::operator=(const&)/1024                                                154541 ns       154535 ns         4416
std::unordered_set<int>::operator=(const&)/8192                                               1310847 ns      1310769 ns          416
std::unordered_set<int>::insert(value) (already present)/32                                      57.5 ns         57.5 ns     12193408
std::unordered_set<int>::insert(value) (already present)/1024                                    60.4 ns         60.4 ns     11587808
std::unordered_set<int>::insert(value) (already present)/8192                                    60.7 ns         60.7 ns      9435360
std::unordered_set<int>::insert(value) (new value)/32                                             153 ns          154 ns      4433696
std::unordered_set<int>::insert(value) (new value)/1024                                           164 ns          164 ns      3980992
std::unordered_set<int>::insert(value) (new value)/8192                                           165 ns          165 ns      4045664
std::unordered_set<int>::insert(iterator, iterator) (all new keys)/32                            6416 ns         6419 ns       102879
std::unordered_set<int>::insert(iterator, iterator) (all new keys)/1024                        205733 ns       205748 ns         3425
std::unordered_set<int>::insert(iterator, iterator) (all new keys)/8192                       1583461 ns      1583454 ns          443
std::unordered_set<int>::insert(iterator, iterator) (half new keys)/32                           4363 ns         4370 ns       154592
std::unordered_set<int>::insert(iterator, iterator) (half new keys)/1024                       141932 ns       141921 ns         5014
std::unordered_set<int>::insert(iterator, iterator) (half new keys)/8192                      1096349 ns      1096330 ns          641
std::unordered_set<int>::erase(key) (existent)/32                                                 149 ns          149 ns      4715776
std::unordered_set<int>::erase(key) (existent)/1024                                               153 ns          153 ns      4587936
std::unordered_set<int>::erase(key) (existent)/8192                                               157 ns          157 ns      3200000
std::unordered_set<int>::erase(key) (non-existent)/32                                            48.6 ns         48.6 ns     14433088
std::unordered_set<int>::erase(key) (non-existent)/1024                                          55.4 ns         55.4 ns     14368768
std::unordered_set<int>::erase(key) (non-existent)/8192                                          50.1 ns         50.0 ns     12491488
std::unordered_set<int>::erase(iterator)/32                                                       106 ns          106 ns      6649824
std::unordered_set<int>::erase(iterator)/1024                                                     108 ns          107 ns      6551744
std::unordered_set<int>::erase(iterator)/8192                                                     108 ns          108 ns      6368928
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/32                 1869 ns         1861 ns       373187
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/1024              50300 ns        50256 ns        13894
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/8192             410477 ns       410379 ns         1707
std::unordered_set<int>::clear()/32                                                              1047 ns         1038 ns       672424
std::unordered_set<int>::clear()/1024                                                           24126 ns        24090 ns        29056
std::unordered_set<int>::clear()/8192                                                          188620 ns       188534 ns         3693
std::unordered_set<int>::find(key) (existent)/32                                                 52.2 ns         52.2 ns     13406688
std::unordered_set<int>::find(key) (existent)/1024                                               48.4 ns         48.4 ns     13773728
std::unordered_set<int>::find(key) (existent)/8192                                               55.8 ns         55.8 ns     12571776
std::unordered_set<int>::find(key) (non-existent)/32                                             41.0 ns         41.0 ns     14667808
std::unordered_set<int>::find(key) (non-existent)/1024                                           43.5 ns         43.5 ns     16278688
std::unordered_set<int>::find(key) (non-existent)/8192                                           41.2 ns         41.2 ns     15790752
std::unordered_set<int>::find(key) (expensive-empty)/32                                          14.6 ns         14.6 ns     47838272
std::unordered_set<int>::find(key) (expensive-empty)/1024                                        14.6 ns         14.6 ns     47741568
std::unordered_set<int>::find(key) (expensive-empty)/8192                                        14.7 ns         14.7 ns     47780224
std::unordered_set<int>::count(key) (existent)/32                                                58.4 ns         58.4 ns     12129728
std::unordered_set<int>::count(key) (existent)/1024                                              57.4 ns         57.4 ns     12091968
std::unordered_set<int>::count(key) (existent)/8192                                              61.1 ns         61.1 ns     12053312
std::unordered_set<int>::count(key) (non-existent)/32                                            60.7 ns         60.7 ns     13021152
std::unordered_set<int>::count(key) (non-existent)/1024                                          57.1 ns         57.1 ns     12352160
std::unordered_set<int>::count(key) (non-existent)/8192                                          61.1 ns         61.1 ns     14251424
std::unordered_set<int>::count(key) (expensive-empty)/32                                         19.4 ns         19.4 ns     36120640
std::unordered_set<int>::count(key) (expensive-empty)/1024                                       19.4 ns         19.4 ns     36122336
std::unordered_set<int>::count(key) (expensive-empty)/8192                                       19.4 ns         19.4 ns     35992544
std::unordered_set<int>::contains(key) (existent)/32                                             57.7 ns         57.7 ns     11540576
std::unordered_set<int>::contains(key) (existent)/1024                                           56.1 ns         56.1 ns     11500288
std::unordered_set<int>::contains(key) (existent)/8192                                           60.5 ns         60.5 ns     11040832
std::unordered_set<int>::contains(key) (non-existent)/32                                         58.9 ns         58.9 ns     13091488
std::unordered_set<int>::contains(key) (non-existent)/1024                                       53.0 ns         53.0 ns     12597184
std::unordered_set<int>::contains(key) (non-existent)/8192                                       56.1 ns         56.1 ns     12456960
std::unordered_set<int>::contains(key) (expensive-empty)/32                                      21.4 ns         21.4 ns     32681408
std::unordered_set<int>::contains(key) (expensive-empty)/1024                                    21.4 ns         21.4 ns     32516640
std::unordered_set<int>::contains(key) (expensive-empty)/8192                                    21.4 ns         21.4 ns     32573888
std::unordered_set<std::string>::ctor(const&)/32                                                24879 ns        24880 ns        25856
std::unordered_set<std::string>::ctor(const&)/1024                                             884089 ns       884042 ns          832
std::unordered_set<std::string>::ctor(const&)/8192                                            8585689 ns      8585383 ns           96
std::unordered_set<std::string>::ctor(iterator, iterator) (unsorted sequence)/32                29851 ns        29853 ns        22944
std::unordered_set<std::string>::ctor(iterator, iterator) (unsorted sequence)/1024            1149105 ns      1149052 ns          768
std::unordered_set<std::string>::ctor(iterator, iterator) (unsorted sequence)/8192            9769845 ns      9769243 ns           64
std::unordered_set<std::string>::ctor(iterator, iterator) (sorted sequence)/32                  33674 ns        33678 ns        26624
std::unordered_set<std::string>::ctor(iterator, iterator) (sorted sequence)/1024              1058258 ns      1058235 ns          544
std::unordered_set<std::string>::ctor(iterator, iterator) (sorted sequence)/8192              9624318 ns      9624047 ns           96
std::unordered_set<std::string>::operator=(const&)/32                                           48214 ns        48216 ns        15296
std::unordered_set<std::string>::operator=(const&)/1024                                       1523473 ns      1523422 ns          448
std::unordered_set<std::string>::operator=(const&)/8192                                      13500351 ns     13499850 ns           64
std::unordered_set<std::string>::insert(value) (already present)/32                               324 ns          324 ns      2154816
std::unordered_set<std::string>::insert(value) (already present)/1024                             731 ns          731 ns       964224
std::unordered_set<std::string>::insert(value) (already present)/8192                            1463 ns         1463 ns       460064
std::unordered_set<std::string>::insert(value) (new value)/32                                    1005 ns         1004 ns      1843488
std::unordered_set<std::string>::insert(value) (new value)/1024                                  1299 ns         1191 ns       636960
std::unordered_set<std::string>::insert(value) (new value)/8192                                  1726 ns         1702 ns       320000
std::unordered_set<std::string>::insert(iterator, iterator) (all new keys)/32                   44153 ns        42927 ns        17413
std::unordered_set<std::string>::insert(iterator, iterator) (all new keys)/1024               1476626 ns      1447248 ns          482
std::unordered_set<std::string>::insert(iterator, iterator) (all new keys)/8192              13019197 ns     12896650 ns           55
std::unordered_set<std::string>::insert(iterator, iterator) (half new keys)/32                  40150 ns        40125 ns        16551
std::unordered_set<std::string>::insert(iterator, iterator) (half new keys)/1024              1407984 ns      1341443 ns          497
std::unordered_set<std::string>::insert(iterator, iterator) (half new keys)/8192             12215376 ns     12203965 ns           57
std::unordered_set<std::string>::erase(key) (existent)/32                                        2569 ns         1997 ns       349312
std::unordered_set<std::string>::erase(key) (existent)/1024                                      1970 ns         1927 ns       930304
std::unordered_set<std::string>::erase(key) (existent)/8192                                      1621 ns         1618 ns       529216
std::unordered_set<std::string>::erase(key) (non-existent)/32                                    1174 ns          986 ns       623360
std::unordered_set<std::string>::erase(key) (non-existent)/1024                                  1194 ns         1048 ns       676672
std::unordered_set<std::string>::erase(key) (non-existent)/8192                                   983 ns          962 ns       688000
std::unordered_set<std::string>::erase(iterator)/32                                               213 ns          209 ns      3374560
std::unordered_set<std::string>::erase(iterator)/1024                                             212 ns          207 ns      3474080
std::unordered_set<std::string>::erase(iterator)/8192                                             218 ns          206 ns      3805824
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/32         2854 ns         2804 ns       208147
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/1024      64984 ns        64778 ns        10493
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/8192     695737 ns       695149 ns         1013
std::unordered_set<std::string>::clear()/32                                                      1388 ns         1370 ns       506834
std::unordered_set<std::string>::clear()/1024                                                   46217 ns        46073 ns        15204
std::unordered_set<std::string>::clear()/8192                                                  599831 ns       599498 ns         1180
std::unordered_set<std::string>::find(key) (existent)/32                                          753 ns          753 ns      1039520
std::unordered_set<std::string>::find(key) (existent)/1024                                        662 ns          662 ns       968320
std::unordered_set<std::string>::find(key) (existent)/8192                                        610 ns          610 ns      1020864
std::unordered_set<std::string>::find(key) (non-existent)/32                                      625 ns          625 ns      1117408
std::unordered_set<std::string>::find(key) (non-existent)/1024                                    655 ns          655 ns      1083008
std::unordered_set<std::string>::find(key) (non-existent)/8192                                    650 ns          650 ns      1042560
std::unordered_set<std::string>::find(key) (expensive-empty)/32                                  14.4 ns         14.4 ns     48641472
std::unordered_set<std::string>::find(key) (expensive-empty)/1024                                14.4 ns         14.4 ns     48623392
std::unordered_set<std::string>::find(key) (expensive-empty)/8192                                14.4 ns         14.4 ns     48591616
std::unordered_set<std::string>::count(key) (existent)/32                                         824 ns          824 ns       985760
std::unordered_set<std::string>::count(key) (existent)/1024                                       776 ns          776 ns       929376
std::unordered_set<std::string>::count(key) (existent)/8192                                       703 ns          702 ns       995936
std::unordered_set<std::string>::count(key) (non-existent)/32                                     725 ns          725 ns      1087584
std::unordered_set<std::string>::count(key) (non-existent)/1024                                   709 ns          709 ns       937664
std::unordered_set<std::string>::count(key) (non-existent)/8192                                   625 ns          625 ns      1144000
std::unordered_set<std::string>::count(key) (expensive-empty)/32                                 19.3 ns         19.3 ns     36164832
std::unordered_set<std::string>::count(key) (expensive-empty)/1024                               19.3 ns         19.3 ns     36393312
std::unordered_set<std::string>::count(key) (expensive-empty)/8192                               19.3 ns         19.3 ns     36143328
std::unordered_set<std::string>::contains(key) (existent)/32                                      709 ns          709 ns      1048064
std::unordered_set<std::string>::contains(key) (existent)/1024                                    748 ns          748 ns      1024768
std::unordered_set<std::string>::contains(key) (existent)/8192                                    831 ns          831 ns       895008
std::unordered_set<std::string>::contains(key) (non-existent)/32                                  714 ns          714 ns      1075264
std::unordered_set<std::string>::contains(key) (non-existent)/1024                                504 ns          504 ns      1222240
std::unordered_set<std::string>::contains(key) (non-existent)/8192                                717 ns          717 ns      1022432
std::unordered_set<std::string>::contains(key) (expensive-empty)/32                              22.0 ns         22.0 ns     31752096
std::unordered_set<std::string>::contains(key) (expensive-empty)/1024                            22.0 ns         22.0 ns     31857600
std::unordered_set<std::string>::contains(key) (expensive-empty)/8192                            22.0 ns         22.0 ns     31783040


2. Without the opt:

-------------------------------------------------------------------------------------------------------------------------------------
Benchmark                                                                                           Time             CPU   Iterations
-------------------------------------------------------------------------------------------------------------------------------------
std::unordered_set<int>::ctor(const&)/32                                                         4920 ns         4921 ns       142304
std::unordered_set<int>::ctor(const&)/1024                                                     161004 ns       161004 ns         4384
std::unordered_set<int>::ctor(const&)/8192                                                    1369984 ns      1369913 ns          512
std::unordered_set<int>::ctor(iterator, iterator) (unsorted sequence)/32                         6583 ns         6584 ns       105536
std::unordered_set<int>::ctor(iterator, iterator) (unsorted sequence)/1024                     203335 ns       203328 ns         3488
std::unordered_set<int>::ctor(iterator, iterator) (unsorted sequence)/8192                    1712738 ns      1712659 ns          416
std::unordered_set<int>::ctor(iterator, iterator) (sorted sequence)/32                           6417 ns         6418 ns       105920
std::unordered_set<int>::ctor(iterator, iterator) (sorted sequence)/1024                       204252 ns       204248 ns         3456
std::unordered_set<int>::ctor(iterator, iterator) (sorted sequence)/8192                      1718282 ns      1718226 ns          416
std::unordered_set<int>::operator=(const&)/32                                                    4777 ns         4778 ns       143776
std::unordered_set<int>::operator=(const&)/1024                                                155375 ns       155370 ns         4416
std::unordered_set<int>::operator=(const&)/8192                                               1318345 ns      1318318 ns          416
std::unordered_set<int>::insert(value) (already present)/32                                      57.1 ns         57.1 ns     12182624
std::unordered_set<int>::insert(value) (already present)/1024                                    60.2 ns         60.2 ns     11640704
std::unordered_set<int>::insert(value) (already present)/8192                                    59.3 ns         59.3 ns     11515456
std::unordered_set<int>::insert(value) (new value)/32                                             152 ns          152 ns      4575936
std::unordered_set<int>::insert(value) (new value)/1024                                           161 ns          161 ns      4283488
std::unordered_set<int>::insert(value) (new value)/8192                                           172 ns          172 ns      4288736
std::unordered_set<int>::insert(iterator, iterator) (all new keys)/32                            6430 ns         6434 ns       107732
std::unordered_set<int>::insert(iterator, iterator) (all new keys)/1024                        206167 ns       206184 ns         3429
std::unordered_set<int>::insert(iterator, iterator) (all new keys)/8192                       1587621 ns      1587634 ns          417
std::unordered_set<int>::insert(iterator, iterator) (half new keys)/32                           4588 ns         4587 ns       150781
std::unordered_set<int>::insert(iterator, iterator) (half new keys)/1024                       132835 ns       132832 ns         4951
std::unordered_set<int>::insert(iterator, iterator) (half new keys)/8192                      1095236 ns      1095210 ns          641
std::unordered_set<int>::erase(key) (existent)/32                                                 154 ns          154 ns      4492416
std::unordered_set<int>::erase(key) (existent)/1024                                               160 ns          160 ns      4383520
std::unordered_set<int>::erase(key) (existent)/8192                                               155 ns          155 ns      4363744
std::unordered_set<int>::erase(key) (non-existent)/32                                            57.8 ns         57.8 ns     14141664
std::unordered_set<int>::erase(key) (non-existent)/1024                                          57.4 ns         57.4 ns     14369216
std::unordered_set<int>::erase(key) (non-existent)/8192                                          56.4 ns         56.4 ns     13152576
std::unordered_set<int>::erase(iterator)/32                                                       108 ns          108 ns      6519872
std::unordered_set<int>::erase(iterator)/1024                                                     110 ns          110 ns      6271040
std::unordered_set<int>::erase(iterator)/8192                                                     112 ns          112 ns      6295872
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/32                 1815 ns         1808 ns       363644
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/1024              51034 ns        51007 ns        13752
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/8192             414144 ns       414067 ns         1692
std::unordered_set<int>::clear()/32                                                              1053 ns         1049 ns       660370
std::unordered_set<int>::clear()/1024                                                           24122 ns        24110 ns        29062
std::unordered_set<int>::clear()/8192                                                          189528 ns       189457 ns         3704
std::unordered_set<int>::find(key) (existent)/32                                                 52.0 ns         52.0 ns     12869664
std::unordered_set<int>::find(key) (existent)/1024                                               51.0 ns         51.0 ns     13863392
std::unordered_set<int>::find(key) (existent)/8192                                               52.8 ns         52.8 ns     13966656
std::unordered_set<int>::find(key) (non-existent)/32                                             43.0 ns         43.0 ns     13238752
std::unordered_set<int>::find(key) (non-existent)/1024                                           46.9 ns         46.9 ns     17560800
std::unordered_set<int>::find(key) (non-existent)/8192                                           40.5 ns         40.5 ns     17009920
std::unordered_set<int>::find(key) (expensive-empty)/32                                          16.4 ns         16.4 ns     42983616
std::unordered_set<int>::find(key) (expensive-empty)/1024                                        16.5 ns         16.5 ns     42652352
std::unordered_set<int>::find(key) (expensive-empty)/8192                                        16.3 ns         16.3 ns     42610592
std::unordered_set<int>::count(key) (existent)/32                                                58.6 ns         58.6 ns     11978688
std::unordered_set<int>::count(key) (existent)/1024                                              56.3 ns         56.3 ns     12275488
std::unordered_set<int>::count(key) (existent)/8192                                              61.3 ns         61.3 ns     11718880
std::unordered_set<int>::count(key) (non-existent)/32                                            51.6 ns         51.6 ns     13867456
std::unordered_set<int>::count(key) (non-existent)/1024                                          59.7 ns         59.7 ns     12946400
std::unordered_set<int>::count(key) (non-existent)/8192                                          57.9 ns         57.9 ns     12481344
std::unordered_set<int>::count(key) (expensive-empty)/32                                         21.5 ns         21.5 ns     32519840
std::unordered_set<int>::count(key) (expensive-empty)/1024                                       21.5 ns         21.5 ns     32430592
std::unordered_set<int>::count(key) (expensive-empty)/8192                                       21.5 ns         21.5 ns     32623872
std::unordered_set<int>::contains(key) (existent)/32                                             58.3 ns         58.3 ns     11878944
std::unordered_set<int>::contains(key) (existent)/1024                                           61.1 ns         61.1 ns     11275648
std::unordered_set<int>::contains(key) (existent)/8192                                           59.8 ns         59.8 ns     11298112
std::unordered_set<int>::contains(key) (non-existent)/32                                         52.4 ns         52.4 ns     11874720
std::unordered_set<int>::contains(key) (non-existent)/1024                                       56.1 ns         56.1 ns     11843904
std::unordered_set<int>::contains(key) (non-existent)/8192                                       57.3 ns         57.3 ns     10858048
std::unordered_set<int>::contains(key) (expensive-empty)/32                                      23.1 ns         23.1 ns     30402240
std::unordered_set<int>::contains(key) (expensive-empty)/1024                                    23.1 ns         23.1 ns     30244128
std::unordered_set<int>::contains(key) (expensive-empty)/8192                                    23.1 ns         23.1 ns     30230528
std::unordered_set<std::string>::ctor(const&)/32                                                26497 ns        26497 ns        25280
std::unordered_set<std::string>::ctor(const&)/1024                                             825878 ns       825839 ns          832
std::unordered_set<std::string>::ctor(const&)/8192                                            8670858 ns      8670549 ns           96
std::unordered_set<std::string>::ctor(iterator, iterator) (unsorted sequence)/32                27310 ns        27311 ns        26464
std::unordered_set<std::string>::ctor(iterator, iterator) (unsorted sequence)/1024             946828 ns       946803 ns          768
std::unordered_set<std::string>::ctor(iterator, iterator) (unsorted sequence)/8192            9053635 ns      9053223 ns           96
std::unordered_set<std::string>::ctor(iterator, iterator) (sorted sequence)/32                  27548 ns        27548 ns        23648
std::unordered_set<std::string>::ctor(iterator, iterator) (sorted sequence)/1024               898692 ns       898659 ns          800
std::unordered_set<std::string>::ctor(iterator, iterator) (sorted sequence)/8192              9010872 ns      9010567 ns           96
std::unordered_set<std::string>::operator=(const&)/32                                           47648 ns        47650 ns        14080
std::unordered_set<std::string>::operator=(const&)/1024                                       1475556 ns      1475497 ns          448
std::unordered_set<std::string>::operator=(const&)/8192                                      13089133 ns     13088427 ns           64
std::unordered_set<std::string>::insert(value) (already present)/32                               946 ns          946 ns       796928
std::unordered_set<std::string>::insert(value) (already present)/1024                             729 ns          729 ns      2565824
std::unordered_set<std::string>::insert(value) (already present)/8192                             805 ns          805 ns      2718624
std::unordered_set<std::string>::insert(value) (new value)/32                                    1161 ns         1161 ns      1403360
std::unordered_set<std::string>::insert(value) (new value)/1024                                  1246 ns         1246 ns      1978080
std::unordered_set<std::string>::insert(value) (new value)/8192                                  1110 ns         1110 ns       985376
std::unordered_set<std::string>::insert(iterator, iterator) (all new keys)/32                   30256 ns        30276 ns        25741
std::unordered_set<std::string>::insert(iterator, iterator) (all new keys)/1024                908942 ns       909062 ns          745
std::unordered_set<std::string>::insert(iterator, iterator) (all new keys)/8192               7286785 ns      7286437 ns           96
std::unordered_set<std::string>::insert(iterator, iterator) (half new keys)/32                  26705 ns        26699 ns        26325
std::unordered_set<std::string>::insert(iterator, iterator) (half new keys)/1024               837638 ns       837685 ns          835
std::unordered_set<std::string>::insert(iterator, iterator) (half new keys)/8192              6982924 ns      6982639 ns          100
std::unordered_set<std::string>::erase(key) (existent)/32                                        1082 ns         1082 ns      1315040
std::unordered_set<std::string>::erase(key) (existent)/1024                                       815 ns          815 ns      1036096
std::unordered_set<std::string>::erase(key) (existent)/8192                                      1004 ns         1004 ns       868960
std::unordered_set<std::string>::erase(key) (non-existent)/32                                     632 ns          632 ns      1007424
std::unordered_set<std::string>::erase(key) (non-existent)/1024                                   609 ns          609 ns      1200256
std::unordered_set<std::string>::erase(key) (non-existent)/8192                                   749 ns          749 ns      1040416
std::unordered_set<std::string>::erase(iterator)/32                                               132 ns          131 ns      5600064
std::unordered_set<std::string>::erase(iterator)/1024                                             125 ns          125 ns      5720800
std::unordered_set<std::string>::erase(iterator)/8192                                             130 ns          130 ns      5698336
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/32         2188 ns         2166 ns       329336
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/1024      66079 ns        65889 ns        10574
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/8192     685952 ns       685607 ns         1001
std::unordered_set<std::string>::clear()/32                                                      1388 ns         1372 ns       507157
std::unordered_set<std::string>::clear()/1024                                                   47859 ns        47698 ns        15356
std::unordered_set<std::string>::clear()/8192                                                  573679 ns       573370 ns         1137
std::unordered_set<std::string>::find(key) (existent)/32                                          728 ns          728 ns       955840
std::unordered_set<std::string>::find(key) (existent)/1024                                        682 ns          682 ns       926912
std::unordered_set<std::string>::find(key) (existent)/8192                                        648 ns          648 ns       923872
std::unordered_set<std::string>::find(key) (non-existent)/32                                      646 ns          646 ns       958112
std::unordered_set<std::string>::find(key) (non-existent)/1024                                    702 ns          702 ns      1090208
std::unordered_set<std::string>::find(key) (non-existent)/8192                                    594 ns          594 ns      1150432
std::unordered_set<std::string>::find(key) (expensive-empty)/32                                   313 ns          313 ns      2236000
std::unordered_set<std::string>::find(key) (expensive-empty)/1024                                 313 ns          313 ns      2237376
std::unordered_set<std::string>::find(key) (expensive-empty)/8192                                 313 ns          313 ns      2233696
std::unordered_set<std::string>::count(key) (existent)/32                                         803 ns          803 ns       987712
std::unordered_set<std::string>::count(key) (existent)/1024                                       670 ns          670 ns       919680
std::unordered_set<std::string>::count(key) (existent)/8192                                       668 ns          668 ns       878944
std::unordered_set<std::string>::count(key) (non-existent)/32                                     706 ns          706 ns       966848
std::unordered_set<std::string>::count(key) (non-existent)/1024                                   558 ns          558 ns       979904
std::unordered_set<std::string>::count(key) (non-existent)/8192                                   632 ns          632 ns      1027840
std::unordered_set<std::string>::count(key) (expensive-empty)/32                                  319 ns          319 ns      2196512
std::unordered_set<std::string>::count(key) (expensive-empty)/1024                                318 ns          318 ns      2199328
std::unordered_set<std::string>::count(key) (expensive-empty)/8192                                318 ns          318 ns      2197472
std::unordered_set<std::string>::contains(key) (existent)/32                                      708 ns          708 ns      1037120
std::unordered_set<std::string>::contains(key) (existent)/1024                                    765 ns          765 ns       889856
std::unordered_set<std::string>::contains(key) (existent)/8192                                    740 ns          740 ns       945600
std::unordered_set<std::string>::contains(key) (non-existent)/32                                  730 ns          730 ns      1077984
std::unordered_set<std::string>::contains(key) (non-existent)/1024                                662 ns          662 ns      1001536
std::unordered_set<std::string>::contains(key) (non-existent)/8192                                662 ns          662 ns      1024864
std::unordered_set<std::string>::contains(key) (expensive-empty)/32                               321 ns          321 ns      2182656
std::unordered_set<std::string>::contains(key) (expensive-empty)/1024                             320 ns          320 ns      2188096
std::unordered_set<std::string>::contains(key) (expensive-empty)/8192                             320 ns          320 ns      2188192
---
 .../associative_container_benchmarks.h        | 28 ++++++
 .../associative/hash_table_find.bench.cpp     | 97 -------------------
 .../associative/unordered_map.bench.cpp       |  1 +
 .../associative/unordered_multimap.bench.cpp  |  1 +
 .../associative/unordered_multiset.bench.cpp  |  2 +
 .../associative/unordered_set.bench.cpp       |  2 +
 6 files changed, 34 insertions(+), 97 deletions(-)
 delete mode 100644 libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp

diff --git a/libcxx/test/benchmarks/containers/associative/associative_container_benchmarks.h b/libcxx/test/benchmarks/containers/associative/associative_container_benchmarks.h
index fb4455c4aa9da..2f6115c5698dd 100644
--- a/libcxx/test/benchmarks/containers/associative/associative_container_benchmarks.h
+++ b/libcxx/test/benchmarks/containers/associative/associative_container_benchmarks.h
@@ -47,6 +47,14 @@ void associative_container_benchmarks(std::string container) {
     return std::vector<Key>(keys.begin(), keys.end());
   };
 
+  auto generate_expensive_keys = [=](std::size_t n) {
+    std::vector<Key> keys;
+    for (std::size_t i = 0; i < n; ++i) {
+      keys.push_back(Generate<Key>::expensive());
+    }
+    return keys;
+  };
+
   auto make_value_types = [](std::vector<Key> const& keys) {
     std::vector<Value> kv;
     for (Key const& k : keys)
@@ -480,17 +488,37 @@ void associative_container_benchmarks(std::string container) {
     };
   };
 
+  auto with_expensive_key_empty = [=](auto func) {
+    return [=](auto& st) {
+        const std::size_t size = st.range(0);
+        std::vector<Key> keys = generate_expensive_keys(size);
+        Container c;
+
+        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();
+          }
+        }
+      };
+  };
+
   auto find = [](Container const& c, Key const& key) { return c.find(key); };
   bench("find(key) (existent)", with_existent_key(find));
   bench("find(key) (non-existent)", with_nonexistent_key(find));
+  bench("find(key) (expensive-empty)", with_expensive_key_empty(find));
 
   auto count = [](Container const& c, Key const& key) { return c.count(key); };
   bench("count(key) (existent)", with_existent_key(count));
   bench("count(key) (non-existent)", with_nonexistent_key(count));
+  bench("count(key) (expensive-empty)", with_expensive_key_empty(count));
 
   auto contains = [](Container const& c, Key const& key) { return c.contains(key); };
   bench("contains(key) (existent)", with_existent_key(contains));
   bench("contains(key) (non-existent)", with_nonexistent_key(contains));
+  bench("contains(key) (expensive-empty)", with_expensive_key_empty(contains));
 
   if constexpr (is_ordered_container) {
     auto lower_bound = [](Container const& c, Key const& key) { return c.lower_bound(key); };
diff --git a/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp b/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp
deleted file mode 100644
index 5eea4f8a7219f..0000000000000
--- a/libcxx/test/benchmarks/containers/associative/hash_table_find.bench.cpp
+++ /dev/null
@@ -1,97 +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 <unordered_set>
-#include <string>
-#include <random>
-#include <vector>
-
-#include "../../GenerateInput.h"
-#include "benchmark/benchmark.h"
-
-// Generate random strings of at least 32 chars
-struct LongStringGenerator {
-  static std::vector<std::string> cached_strings;
-
-  static void ensure_strings(size_t count) {
-    cached_strings.clear();
-
-    std::mt19937_64 gen(42); // Fixed seed for reproducibility
-    std::uniform_int_distribution<size_t> len_dist(32, 128);
-
-    cached_strings.reserve(count);
-    for (size_t i = 0; i < count; i++) {
-      std::string str(len_dist(gen), 0);
-      for (char& c : str) {
-        c = 'a' + (gen() % 26);
-      }
-      cached_strings.push_back(std::move(str));
-    }
-  }
-
-  const std::string& generate(size_t i) { return cached_strings[i]; }
-};
-
-std::vector<std::string> LongStringGenerator::cached_strings;
-[[maybe_unused]] auto dummy = [] { // Pre-generate 32K strings
-  LongStringGenerator::ensure_strings(1 << 15);
-  return 0;
-}();
-
-template <class Gen>
-static void BM_UnorderedSet_Find_EmptyNoBuckets(benchmark::State& state, Gen g) {
-  const size_t lookup_count = state.range(0);
-  std::unordered_set<std::string> s; // Empty and no buckets
-
-  for (auto _ : state) {
-    for (size_t i = 0; i < lookup_count; i++) {
-      benchmark::DoNotOptimize(s.find(g.generate(i)));
-    }
-  }
-}
-
-template <class Gen>
-static void BM_UnorderedSet_Find_EmptyWithBuckets(benchmark::State& state, Gen g) {
-  const size_t lookup_count = state.range(0);
-  std::unordered_set<std::string> s;
-  s.reserve(1); // Still empty but reserved buckets
-
-  for (auto _ : state) {
-    for (size_t i = 0; i < lookup_count; i++) {
-      benchmark::DoNotOptimize(s.find(g.generate(i)));
-    }
-  }
-}
-
-template <class Gen>
-static void BM_UnorderedSet_Find_NonEmpty(benchmark::State& state, Gen g) {
-  const size_t lookup_count = state.range(0);
-  std::unordered_set<std::string> s{"hello"};
-
-  for (auto _ : state) {
-    for (size_t i = 0; i < lookup_count; i++) {
-      benchmark::DoNotOptimize(s.find(g.generate(i)));
-    }
-  }
-}
-
-BENCHMARK_CAPTURE(BM_UnorderedSet_Find_EmptyNoBuckets, long_string, LongStringGenerator())
-    ->RangeMultiplier(2)
-    ->Range(1 << 10, 1 << 15); // Test from 1K to 32K lookups
-
-BENCHMARK_CAPTURE(BM_UnorderedSet_Find_EmptyWithBuckets, long_string, LongStringGenerator())
-    ->RangeMultiplier(2)
-    ->Range(1 << 10, 1 << 15);
-
-BENCHMARK_CAPTURE(BM_UnorderedSet_Find_NonEmpty, long_string, LongStringGenerator())
-    ->RangeMultiplier(2)
-    ->Range(1 << 10, 1 << 15);
-
-BENCHMARK_MAIN();
diff --git a/libcxx/test/benchmarks/containers/associative/unordered_map.bench.cpp b/libcxx/test/benchmarks/containers/associative/unordered_map.bench.cpp
index 57adec2d214d4..89fddccb4d531 100644
--- a/libcxx/test/benchmarks/containers/associative/unordered_map.bench.cpp
+++ b/libcxx/test/benchmarks/containers/associative/unordered_map.bench.cpp
@@ -28,6 +28,7 @@ struct support::adapt_operations<std::unordered_map<K, V>> {
 
 int main(int argc, char** argv) {
   support::associative_container_benchmarks<std::unordered_map<int, int>>("std::unordered_map<int, int>");
+  support::associative_container_benchmarks<std::unordered_map<std::string, int>>("std::unordered_map<std::string, int>");
 
   benchmark::Initialize(&argc, argv);
   benchmark::RunSpecifiedBenchmarks();
diff --git a/libcxx/test/benchmarks/containers/associative/unordered_multimap.bench.cpp b/libcxx/test/benchmarks/containers/associative/unordered_multimap.bench.cpp
index 8738ca4bf9f0c..080cf61087ddd 100644
--- a/libcxx/test/benchmarks/containers/associative/unordered_multimap.bench.cpp
+++ b/libcxx/test/benchmarks/containers/associative/unordered_multimap.bench.cpp
@@ -27,6 +27,7 @@ struct support::adapt_operations<std::unordered_multimap<K, V>> {
 
 int main(int argc, char** argv) {
   support::associative_container_benchmarks<std::unordered_multimap<int, int>>("std::unordered_multimap<int, int>");
+  support::associative_container_benchmarks<std::unordered_multimap<std::string, int>>("std::unordered_multimap<std::string, int>");
 
   benchmark::Initialize(&argc, argv);
   benchmark::RunSpecifiedBenchmarks();
diff --git a/libcxx/test/benchmarks/containers/associative/unordered_multiset.bench.cpp b/libcxx/test/benchmarks/containers/associative/unordered_multiset.bench.cpp
index 4888b01bfeba0..c4e1dc4c42651 100644
--- a/libcxx/test/benchmarks/containers/associative/unordered_multiset.bench.cpp
+++ b/libcxx/test/benchmarks/containers/associative/unordered_multiset.bench.cpp
@@ -8,6 +8,7 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 
+#include <string>
 #include <unordered_set>
 
 #include "associative_container_benchmarks.h"
@@ -26,6 +27,7 @@ struct support::adapt_operations<std::unordered_multiset<K>> {
 
 int main(int argc, char** argv) {
   support::associative_container_benchmarks<std::unordered_multiset<int>>("std::unordered_multiset<int>");
+  support::associative_container_benchmarks<std::unordered_multiset<std::string>>("std::unordered_multiset<std::string>");
 
   benchmark::Initialize(&argc, argv);
   benchmark::RunSpecifiedBenchmarks();
diff --git a/libcxx/test/benchmarks/containers/associative/unordered_set.bench.cpp b/libcxx/test/benchmarks/containers/associative/unordered_set.bench.cpp
index 56420bdaadfbf..89443a597e85a 100644
--- a/libcxx/test/benchmarks/containers/associative/unordered_set.bench.cpp
+++ b/libcxx/test/benchmarks/containers/associative/unordered_set.bench.cpp
@@ -8,6 +8,7 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 
+#include <string>
 #include <unordered_set>
 #include <utility>
 
@@ -27,6 +28,7 @@ struct support::adapt_operations<std::unordered_set<K>> {
 
 int main(int argc, char** argv) {
   support::associative_container_benchmarks<std::unordered_set<int>>("std::unordered_set<int>");
+  support::associative_container_benchmarks<std::unordered_set<std::string>>("std::unordered_set<std::string>");
 
   benchmark::Initialize(&argc, argv);
   benchmark::RunSpecifiedBenchmarks();



More information about the libcxx-commits mailing list