xref: /aosp_15_r20/external/abseil-cpp/absl/hash/hash_benchmark.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
1*9356374aSAndroid Build Coastguard Worker // Copyright 2018 The Abseil Authors.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker //      https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker 
15*9356374aSAndroid Build Coastguard Worker #include <algorithm>
16*9356374aSAndroid Build Coastguard Worker #include <cassert>
17*9356374aSAndroid Build Coastguard Worker #include <cstddef>
18*9356374aSAndroid Build Coastguard Worker #include <cstdint>
19*9356374aSAndroid Build Coastguard Worker #include <cstring>
20*9356374aSAndroid Build Coastguard Worker #include <string>
21*9356374aSAndroid Build Coastguard Worker #include <tuple>
22*9356374aSAndroid Build Coastguard Worker #include <type_traits>
23*9356374aSAndroid Build Coastguard Worker #include <typeindex>
24*9356374aSAndroid Build Coastguard Worker #include <utility>
25*9356374aSAndroid Build Coastguard Worker #include <vector>
26*9356374aSAndroid Build Coastguard Worker 
27*9356374aSAndroid Build Coastguard Worker #include "absl/base/attributes.h"
28*9356374aSAndroid Build Coastguard Worker #include "absl/container/flat_hash_set.h"
29*9356374aSAndroid Build Coastguard Worker #include "absl/hash/hash.h"
30*9356374aSAndroid Build Coastguard Worker #include "absl/random/random.h"
31*9356374aSAndroid Build Coastguard Worker #include "absl/strings/cord.h"
32*9356374aSAndroid Build Coastguard Worker #include "absl/strings/cord_test_helpers.h"
33*9356374aSAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
34*9356374aSAndroid Build Coastguard Worker #include "benchmark/benchmark.h"
35*9356374aSAndroid Build Coastguard Worker 
36*9356374aSAndroid Build Coastguard Worker namespace {
37*9356374aSAndroid Build Coastguard Worker 
38*9356374aSAndroid Build Coastguard Worker using absl::Hash;
39*9356374aSAndroid Build Coastguard Worker 
40*9356374aSAndroid Build Coastguard Worker template <template <typename> class H, typename T>
RunBenchmark(benchmark::State & state,T value)41*9356374aSAndroid Build Coastguard Worker void RunBenchmark(benchmark::State& state, T value) {
42*9356374aSAndroid Build Coastguard Worker   H<T> h;
43*9356374aSAndroid Build Coastguard Worker   for (auto _ : state) {
44*9356374aSAndroid Build Coastguard Worker     benchmark::DoNotOptimize(value);
45*9356374aSAndroid Build Coastguard Worker     benchmark::DoNotOptimize(h(value));
46*9356374aSAndroid Build Coastguard Worker   }
47*9356374aSAndroid Build Coastguard Worker }
48*9356374aSAndroid Build Coastguard Worker 
49*9356374aSAndroid Build Coastguard Worker }  // namespace
50*9356374aSAndroid Build Coastguard Worker 
51*9356374aSAndroid Build Coastguard Worker template <typename T>
52*9356374aSAndroid Build Coastguard Worker using AbslHash = absl::Hash<T>;
53*9356374aSAndroid Build Coastguard Worker 
54*9356374aSAndroid Build Coastguard Worker class TypeErasedInterface {
55*9356374aSAndroid Build Coastguard Worker  public:
56*9356374aSAndroid Build Coastguard Worker   virtual ~TypeErasedInterface() = default;
57*9356374aSAndroid Build Coastguard Worker 
58*9356374aSAndroid Build Coastguard Worker   template <typename H>
AbslHashValue(H state,const TypeErasedInterface & wrapper)59*9356374aSAndroid Build Coastguard Worker   friend H AbslHashValue(H state, const TypeErasedInterface& wrapper) {
60*9356374aSAndroid Build Coastguard Worker     state = H::combine(std::move(state), std::type_index(typeid(wrapper)));
61*9356374aSAndroid Build Coastguard Worker     wrapper.HashValue(absl::HashState::Create(&state));
62*9356374aSAndroid Build Coastguard Worker     return state;
63*9356374aSAndroid Build Coastguard Worker   }
64*9356374aSAndroid Build Coastguard Worker 
65*9356374aSAndroid Build Coastguard Worker  private:
66*9356374aSAndroid Build Coastguard Worker   virtual void HashValue(absl::HashState state) const = 0;
67*9356374aSAndroid Build Coastguard Worker };
68*9356374aSAndroid Build Coastguard Worker 
69*9356374aSAndroid Build Coastguard Worker template <typename T>
70*9356374aSAndroid Build Coastguard Worker struct TypeErasedAbslHash {
71*9356374aSAndroid Build Coastguard Worker   class Wrapper : public TypeErasedInterface {
72*9356374aSAndroid Build Coastguard Worker    public:
Wrapper(const T & value)73*9356374aSAndroid Build Coastguard Worker     explicit Wrapper(const T& value) : value_(value) {}
74*9356374aSAndroid Build Coastguard Worker 
75*9356374aSAndroid Build Coastguard Worker    private:
HashValue(absl::HashState state) const76*9356374aSAndroid Build Coastguard Worker     void HashValue(absl::HashState state) const override {
77*9356374aSAndroid Build Coastguard Worker       absl::HashState::combine(std::move(state), value_);
78*9356374aSAndroid Build Coastguard Worker     }
79*9356374aSAndroid Build Coastguard Worker 
80*9356374aSAndroid Build Coastguard Worker     const T& value_;
81*9356374aSAndroid Build Coastguard Worker   };
82*9356374aSAndroid Build Coastguard Worker 
operator ()TypeErasedAbslHash83*9356374aSAndroid Build Coastguard Worker   size_t operator()(const T& value) {
84*9356374aSAndroid Build Coastguard Worker     return absl::Hash<Wrapper>{}(Wrapper(value));
85*9356374aSAndroid Build Coastguard Worker   }
86*9356374aSAndroid Build Coastguard Worker };
87*9356374aSAndroid Build Coastguard Worker 
FlatCord(size_t size)88*9356374aSAndroid Build Coastguard Worker absl::Cord FlatCord(size_t size) {
89*9356374aSAndroid Build Coastguard Worker   absl::Cord result(std::string(size, 'a'));
90*9356374aSAndroid Build Coastguard Worker   result.Flatten();
91*9356374aSAndroid Build Coastguard Worker   return result;
92*9356374aSAndroid Build Coastguard Worker }
93*9356374aSAndroid Build Coastguard Worker 
FragmentedCord(size_t size)94*9356374aSAndroid Build Coastguard Worker absl::Cord FragmentedCord(size_t size) {
95*9356374aSAndroid Build Coastguard Worker   const size_t orig_size = size;
96*9356374aSAndroid Build Coastguard Worker   std::vector<std::string> chunks;
97*9356374aSAndroid Build Coastguard Worker   size_t chunk_size = std::max<size_t>(1, size / 10);
98*9356374aSAndroid Build Coastguard Worker   while (size > chunk_size) {
99*9356374aSAndroid Build Coastguard Worker     chunks.push_back(std::string(chunk_size, 'a'));
100*9356374aSAndroid Build Coastguard Worker     size -= chunk_size;
101*9356374aSAndroid Build Coastguard Worker   }
102*9356374aSAndroid Build Coastguard Worker   if (size > 0) {
103*9356374aSAndroid Build Coastguard Worker     chunks.push_back(std::string(size, 'a'));
104*9356374aSAndroid Build Coastguard Worker   }
105*9356374aSAndroid Build Coastguard Worker   absl::Cord result = absl::MakeFragmentedCord(chunks);
106*9356374aSAndroid Build Coastguard Worker   (void) orig_size;
107*9356374aSAndroid Build Coastguard Worker   assert(result.size() == orig_size);
108*9356374aSAndroid Build Coastguard Worker   return result;
109*9356374aSAndroid Build Coastguard Worker }
110*9356374aSAndroid Build Coastguard Worker 
111*9356374aSAndroid Build Coastguard Worker template <typename T>
Vector(size_t count)112*9356374aSAndroid Build Coastguard Worker std::vector<T> Vector(size_t count) {
113*9356374aSAndroid Build Coastguard Worker   std::vector<T> result;
114*9356374aSAndroid Build Coastguard Worker   for (size_t v = 0; v < count; ++v) {
115*9356374aSAndroid Build Coastguard Worker     result.push_back(v);
116*9356374aSAndroid Build Coastguard Worker   }
117*9356374aSAndroid Build Coastguard Worker   return result;
118*9356374aSAndroid Build Coastguard Worker }
119*9356374aSAndroid Build Coastguard Worker 
120*9356374aSAndroid Build Coastguard Worker // Bogus type that replicates an unorderd_set's bit mixing, but with
121*9356374aSAndroid Build Coastguard Worker // vector-speed iteration. This is intended to measure the overhead of unordered
122*9356374aSAndroid Build Coastguard Worker // hashing without counting the speed of unordered_set iteration.
123*9356374aSAndroid Build Coastguard Worker template <typename T>
124*9356374aSAndroid Build Coastguard Worker struct FastUnorderedSet {
FastUnorderedSetFastUnorderedSet125*9356374aSAndroid Build Coastguard Worker   explicit FastUnorderedSet(size_t count) {
126*9356374aSAndroid Build Coastguard Worker     for (size_t v = 0; v < count; ++v) {
127*9356374aSAndroid Build Coastguard Worker       values.push_back(v);
128*9356374aSAndroid Build Coastguard Worker     }
129*9356374aSAndroid Build Coastguard Worker   }
130*9356374aSAndroid Build Coastguard Worker   std::vector<T> values;
131*9356374aSAndroid Build Coastguard Worker 
132*9356374aSAndroid Build Coastguard Worker   template <typename H>
AbslHashValue(H h,const FastUnorderedSet & fus)133*9356374aSAndroid Build Coastguard Worker   friend H AbslHashValue(H h, const FastUnorderedSet& fus) {
134*9356374aSAndroid Build Coastguard Worker     return H::combine(H::combine_unordered(std::move(h), fus.values.begin(),
135*9356374aSAndroid Build Coastguard Worker                                            fus.values.end()),
136*9356374aSAndroid Build Coastguard Worker                       fus.values.size());
137*9356374aSAndroid Build Coastguard Worker   }
138*9356374aSAndroid Build Coastguard Worker };
139*9356374aSAndroid Build Coastguard Worker 
140*9356374aSAndroid Build Coastguard Worker template <typename T>
FlatHashSet(size_t count)141*9356374aSAndroid Build Coastguard Worker absl::flat_hash_set<T> FlatHashSet(size_t count) {
142*9356374aSAndroid Build Coastguard Worker   absl::flat_hash_set<T> result;
143*9356374aSAndroid Build Coastguard Worker   for (size_t v = 0; v < count; ++v) {
144*9356374aSAndroid Build Coastguard Worker     result.insert(v);
145*9356374aSAndroid Build Coastguard Worker   }
146*9356374aSAndroid Build Coastguard Worker   return result;
147*9356374aSAndroid Build Coastguard Worker }
148*9356374aSAndroid Build Coastguard Worker 
149*9356374aSAndroid Build Coastguard Worker // Generates a benchmark and a codegen method for the provided types.  The
150*9356374aSAndroid Build Coastguard Worker // codegen method provides a well known entrypoint for dumping assembly.
151*9356374aSAndroid Build Coastguard Worker #define MAKE_BENCHMARK(hash, name, ...)                          \
152*9356374aSAndroid Build Coastguard Worker   namespace {                                                    \
153*9356374aSAndroid Build Coastguard Worker   void BM_##hash##_##name(benchmark::State& state) {             \
154*9356374aSAndroid Build Coastguard Worker     RunBenchmark<hash>(state, __VA_ARGS__);                      \
155*9356374aSAndroid Build Coastguard Worker   }                                                              \
156*9356374aSAndroid Build Coastguard Worker   BENCHMARK(BM_##hash##_##name);                                 \
157*9356374aSAndroid Build Coastguard Worker   }                                                              \
158*9356374aSAndroid Build Coastguard Worker   size_t Codegen##hash##name(const decltype(__VA_ARGS__)& arg);  \
159*9356374aSAndroid Build Coastguard Worker   size_t Codegen##hash##name(const decltype(__VA_ARGS__)& arg) { \
160*9356374aSAndroid Build Coastguard Worker     return hash<decltype(__VA_ARGS__)>{}(arg);                   \
161*9356374aSAndroid Build Coastguard Worker   }                                                              \
162*9356374aSAndroid Build Coastguard Worker   bool absl_hash_test_odr_use##hash##name =                      \
163*9356374aSAndroid Build Coastguard Worker       (benchmark::DoNotOptimize(&Codegen##hash##name), false)
164*9356374aSAndroid Build Coastguard Worker 
165*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, Int32, int32_t{});
166*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, Int64, int64_t{});
167*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, Double, 1.2);
168*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, DoubleZero, 0.0);
169*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, PairInt32Int32, std::pair<int32_t, int32_t>{});
170*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, PairInt64Int64, std::pair<int64_t, int64_t>{});
171*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, TupleInt32BoolInt64,
172*9356374aSAndroid Build Coastguard Worker                std::tuple<int32_t, bool, int64_t>{});
173*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, String_0, std::string());
174*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, String_10, std::string(10, 'a'));
175*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, String_30, std::string(30, 'a'));
176*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, String_90, std::string(90, 'a'));
177*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, String_200, std::string(200, 'a'));
178*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, String_5000, std::string(5000, 'a'));
179*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, Cord_Flat_0, absl::Cord());
180*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, Cord_Flat_10, FlatCord(10));
181*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, Cord_Flat_30, FlatCord(30));
182*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, Cord_Flat_90, FlatCord(90));
183*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, Cord_Flat_200, FlatCord(200));
184*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, Cord_Flat_5000, FlatCord(5000));
185*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, Cord_Fragmented_200, FragmentedCord(200));
186*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, Cord_Fragmented_5000, FragmentedCord(5000));
187*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, VectorInt64_10, Vector<int64_t>(10));
188*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, VectorInt64_100, Vector<int64_t>(100));
189*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, VectorInt64_1000, Vector<int64_t>(1000));
190*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, VectorDouble_10, Vector<double>(10));
191*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, VectorDouble_100, Vector<double>(100));
192*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, VectorDouble_1000, Vector<double>(1000));
193*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, FlatHashSetInt64_10, FlatHashSet<int64_t>(10));
194*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, FlatHashSetInt64_100, FlatHashSet<int64_t>(100));
195*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, FlatHashSetInt64_1000, FlatHashSet<int64_t>(1000));
196*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, FlatHashSetDouble_10, FlatHashSet<double>(10));
197*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, FlatHashSetDouble_100, FlatHashSet<double>(100));
198*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, FlatHashSetDouble_1000, FlatHashSet<double>(1000));
199*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, FastUnorderedSetInt64_1000,
200*9356374aSAndroid Build Coastguard Worker                FastUnorderedSet<int64_t>(1000));
201*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, FastUnorderedSetDouble_1000,
202*9356374aSAndroid Build Coastguard Worker                FastUnorderedSet<double>(1000));
203*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, PairStringString_0,
204*9356374aSAndroid Build Coastguard Worker                std::make_pair(std::string(), std::string()));
205*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, PairStringString_10,
206*9356374aSAndroid Build Coastguard Worker                std::make_pair(std::string(10, 'a'), std::string(10, 'b')));
207*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, PairStringString_30,
208*9356374aSAndroid Build Coastguard Worker                std::make_pair(std::string(30, 'a'), std::string(30, 'b')));
209*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, PairStringString_90,
210*9356374aSAndroid Build Coastguard Worker                std::make_pair(std::string(90, 'a'), std::string(90, 'b')));
211*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, PairStringString_200,
212*9356374aSAndroid Build Coastguard Worker                std::make_pair(std::string(200, 'a'), std::string(200, 'b')));
213*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(AbslHash, PairStringString_5000,
214*9356374aSAndroid Build Coastguard Worker                std::make_pair(std::string(5000, 'a'), std::string(5000, 'b')));
215*9356374aSAndroid Build Coastguard Worker 
216*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, Int32, int32_t{});
217*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, Int64, int64_t{});
218*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, PairInt32Int32,
219*9356374aSAndroid Build Coastguard Worker                std::pair<int32_t, int32_t>{});
220*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, PairInt64Int64,
221*9356374aSAndroid Build Coastguard Worker                std::pair<int64_t, int64_t>{});
222*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, TupleInt32BoolInt64,
223*9356374aSAndroid Build Coastguard Worker                std::tuple<int32_t, bool, int64_t>{});
224*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, String_0, std::string());
225*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, String_10, std::string(10, 'a'));
226*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, String_30, std::string(30, 'a'));
227*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, String_90, std::string(90, 'a'));
228*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, String_200, std::string(200, 'a'));
229*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, String_5000, std::string(5000, 'a'));
230*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, VectorDouble_10,
231*9356374aSAndroid Build Coastguard Worker                std::vector<double>(10, 1.1));
232*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, VectorDouble_100,
233*9356374aSAndroid Build Coastguard Worker                std::vector<double>(100, 1.1));
234*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, VectorDouble_1000,
235*9356374aSAndroid Build Coastguard Worker                std::vector<double>(1000, 1.1));
236*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, FlatHashSetInt64_10,
237*9356374aSAndroid Build Coastguard Worker                FlatHashSet<int64_t>(10));
238*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, FlatHashSetInt64_100,
239*9356374aSAndroid Build Coastguard Worker                FlatHashSet<int64_t>(100));
240*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, FlatHashSetInt64_1000,
241*9356374aSAndroid Build Coastguard Worker                FlatHashSet<int64_t>(1000));
242*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, FlatHashSetDouble_10,
243*9356374aSAndroid Build Coastguard Worker                FlatHashSet<double>(10));
244*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, FlatHashSetDouble_100,
245*9356374aSAndroid Build Coastguard Worker                FlatHashSet<double>(100));
246*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, FlatHashSetDouble_1000,
247*9356374aSAndroid Build Coastguard Worker                FlatHashSet<double>(1000));
248*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, FastUnorderedSetInt64_1000,
249*9356374aSAndroid Build Coastguard Worker                FastUnorderedSet<int64_t>(1000));
250*9356374aSAndroid Build Coastguard Worker MAKE_BENCHMARK(TypeErasedAbslHash, FastUnorderedSetDouble_1000,
251*9356374aSAndroid Build Coastguard Worker                FastUnorderedSet<double>(1000));
252*9356374aSAndroid Build Coastguard Worker 
253*9356374aSAndroid Build Coastguard Worker // The latency benchmark attempts to model the speed of the hash function in
254*9356374aSAndroid Build Coastguard Worker // production. When a hash function is used for hashtable lookups it is rarely
255*9356374aSAndroid Build Coastguard Worker // used to hash N items in a tight loop nor on constant sized strings. Instead,
256*9356374aSAndroid Build Coastguard Worker // after hashing there is a potential equality test plus a (usually) large
257*9356374aSAndroid Build Coastguard Worker // amount of user code. To simulate this effectively we introduce a data
258*9356374aSAndroid Build Coastguard Worker // dependency between elements we hash by using the hash of the Nth element as
259*9356374aSAndroid Build Coastguard Worker // the selector of the N+1th element to hash. This isolates the hash function
260*9356374aSAndroid Build Coastguard Worker // code much like in production. As a bonus we use the hash to generate strings
261*9356374aSAndroid Build Coastguard Worker // of size [1,N] (instead of fixed N) to disable perfect branch predictions in
262*9356374aSAndroid Build Coastguard Worker // hash function implementations.
263*9356374aSAndroid Build Coastguard Worker namespace {
264*9356374aSAndroid Build Coastguard Worker // 16kb fits in L1 cache of most CPUs we care about. Keeping memory latency low
265*9356374aSAndroid Build Coastguard Worker // will allow us to attribute most time to CPU which means more accurate
266*9356374aSAndroid Build Coastguard Worker // measurements.
267*9356374aSAndroid Build Coastguard Worker static constexpr size_t kEntropySize = 16 << 10;
268*9356374aSAndroid Build Coastguard Worker static char entropy[kEntropySize + 1024];
__anon57d33b3c0302null269*9356374aSAndroid Build Coastguard Worker ABSL_ATTRIBUTE_UNUSED static const bool kInitialized = [] {
270*9356374aSAndroid Build Coastguard Worker   absl::BitGen gen;
271*9356374aSAndroid Build Coastguard Worker   static_assert(sizeof(entropy) % sizeof(uint64_t) == 0, "");
272*9356374aSAndroid Build Coastguard Worker   for (int i = 0; i != sizeof(entropy); i += sizeof(uint64_t)) {
273*9356374aSAndroid Build Coastguard Worker     auto rand = absl::Uniform<uint64_t>(gen);
274*9356374aSAndroid Build Coastguard Worker     memcpy(&entropy[i], &rand, sizeof(uint64_t));
275*9356374aSAndroid Build Coastguard Worker   }
276*9356374aSAndroid Build Coastguard Worker   return true;
277*9356374aSAndroid Build Coastguard Worker }();
278*9356374aSAndroid Build Coastguard Worker }  // namespace
279*9356374aSAndroid Build Coastguard Worker 
280*9356374aSAndroid Build Coastguard Worker template <class T>
281*9356374aSAndroid Build Coastguard Worker struct PodRand {
282*9356374aSAndroid Build Coastguard Worker   static_assert(std::is_pod<T>::value, "");
283*9356374aSAndroid Build Coastguard Worker   static_assert(kEntropySize + sizeof(T) < sizeof(entropy), "");
284*9356374aSAndroid Build Coastguard Worker 
GetPodRand285*9356374aSAndroid Build Coastguard Worker   T Get(size_t i) const {
286*9356374aSAndroid Build Coastguard Worker     T v;
287*9356374aSAndroid Build Coastguard Worker     memcpy(&v, &entropy[i % kEntropySize], sizeof(T));
288*9356374aSAndroid Build Coastguard Worker     return v;
289*9356374aSAndroid Build Coastguard Worker   }
290*9356374aSAndroid Build Coastguard Worker };
291*9356374aSAndroid Build Coastguard Worker 
292*9356374aSAndroid Build Coastguard Worker template <size_t N>
293*9356374aSAndroid Build Coastguard Worker struct StringRand {
294*9356374aSAndroid Build Coastguard Worker   static_assert(kEntropySize + N < sizeof(entropy), "");
295*9356374aSAndroid Build Coastguard Worker 
GetStringRand296*9356374aSAndroid Build Coastguard Worker   absl::string_view Get(size_t i) const {
297*9356374aSAndroid Build Coastguard Worker     // This has a small bias towards small numbers. Because max N is ~200 this
298*9356374aSAndroid Build Coastguard Worker     // is very small and prefer to be very fast instead of absolutely accurate.
299*9356374aSAndroid Build Coastguard Worker     // Also we pass N = 2^K+1 so that mod reduces to a bitand.
300*9356374aSAndroid Build Coastguard Worker     size_t s = (i % (N - 1)) + 1;
301*9356374aSAndroid Build Coastguard Worker     return {&entropy[i % kEntropySize], s};
302*9356374aSAndroid Build Coastguard Worker   }
303*9356374aSAndroid Build Coastguard Worker };
304*9356374aSAndroid Build Coastguard Worker 
305*9356374aSAndroid Build Coastguard Worker #define MAKE_LATENCY_BENCHMARK(hash, name, ...)              \
306*9356374aSAndroid Build Coastguard Worker   namespace {                                                \
307*9356374aSAndroid Build Coastguard Worker   void BM_latency_##hash##_##name(benchmark::State& state) { \
308*9356374aSAndroid Build Coastguard Worker     __VA_ARGS__ r;                                           \
309*9356374aSAndroid Build Coastguard Worker     hash<decltype(r.Get(0))> h;                              \
310*9356374aSAndroid Build Coastguard Worker     size_t i = 871401241;                                    \
311*9356374aSAndroid Build Coastguard Worker     for (auto _ : state) {                                   \
312*9356374aSAndroid Build Coastguard Worker       benchmark::DoNotOptimize(i = h(r.Get(i)));             \
313*9356374aSAndroid Build Coastguard Worker     }                                                        \
314*9356374aSAndroid Build Coastguard Worker   }                                                          \
315*9356374aSAndroid Build Coastguard Worker   BENCHMARK(BM_latency_##hash##_##name);                     \
316*9356374aSAndroid Build Coastguard Worker   }  // namespace
317*9356374aSAndroid Build Coastguard Worker 
318*9356374aSAndroid Build Coastguard Worker MAKE_LATENCY_BENCHMARK(AbslHash, Int32, PodRand<int32_t>)
319*9356374aSAndroid Build Coastguard Worker MAKE_LATENCY_BENCHMARK(AbslHash, Int64, PodRand<int64_t>)
320*9356374aSAndroid Build Coastguard Worker MAKE_LATENCY_BENCHMARK(AbslHash, String9, StringRand<9>)
321*9356374aSAndroid Build Coastguard Worker MAKE_LATENCY_BENCHMARK(AbslHash, String33, StringRand<33>)
322*9356374aSAndroid Build Coastguard Worker MAKE_LATENCY_BENCHMARK(AbslHash, String65, StringRand<65>)
323*9356374aSAndroid Build Coastguard Worker MAKE_LATENCY_BENCHMARK(AbslHash, String257, StringRand<257>)
324