Skip to content

Commit d1b311d

Browse files
authored
[libc++] Split std::hash benchmark out of std::unordered_set benchmark (#114448)
As a drive-by, remove unused functor inside the unordered_set benchmark. That benchmark still isn't very exhaustive, but that can be addressed separately.
1 parent 5cb7305 commit d1b311d

File tree

3 files changed

+81
-37
lines changed

3 files changed

+81
-37
lines changed

libcxx/test/benchmarks/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ set(BENCHMARK_TESTS
157157
formatter_float.bench.cpp
158158
formatter_int.bench.cpp
159159
function.bench.cpp
160+
hash.bench.cpp
160161
join_view.bench.cpp
161162
lexicographical_compare_three_way.bench.cpp
162163
map.bench.cpp

libcxx/test/benchmarks/hash.bench.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03
10+
11+
#include <cstdint>
12+
#include <cstddef>
13+
#include <functional>
14+
15+
#include "benchmark/benchmark.h"
16+
17+
#include "GenerateInput.h"
18+
#include "test_macros.h"
19+
20+
constexpr std::size_t TestNumInputs = 1024;
21+
22+
template <class _Size>
23+
inline TEST_ALWAYS_INLINE _Size loadword(const void* __p) {
24+
_Size __r;
25+
std::memcpy(&__r, __p, sizeof(__r));
26+
return __r;
27+
}
28+
29+
inline TEST_ALWAYS_INLINE std::size_t hash_len_16(std::size_t __u, std::size_t __v) {
30+
const std::size_t __mul = 0x9ddfea08eb382d69ULL;
31+
std::size_t __a = (__u ^ __v) * __mul;
32+
__a ^= (__a >> 47);
33+
std::size_t __b = (__v ^ __a) * __mul;
34+
__b ^= (__b >> 47);
35+
__b *= __mul;
36+
return __b;
37+
}
38+
39+
template <std::size_t _Len>
40+
inline TEST_ALWAYS_INLINE std::size_t hash_len_0_to_8(const char* __s) {
41+
static_assert(_Len == 4 || _Len == 8, "");
42+
const uint64_t __a = loadword<uint32_t>(__s);
43+
const uint64_t __b = loadword<uint32_t>(__s + _Len - 4);
44+
return hash_len_16(_Len + (__a << 3), __b);
45+
}
46+
47+
struct UInt32Hash {
48+
UInt32Hash() = default;
49+
inline TEST_ALWAYS_INLINE std::size_t operator()(uint32_t data) const {
50+
return hash_len_0_to_8<4>(reinterpret_cast<const char*>(&data));
51+
}
52+
};
53+
54+
template <class HashFn, class GenInputs>
55+
void BM_Hash(benchmark::State& st, HashFn fn, GenInputs gen) {
56+
auto in = gen(st.range(0));
57+
const auto end = in.data() + in.size();
58+
std::size_t last_hash = 0;
59+
benchmark::DoNotOptimize(&last_hash);
60+
while (st.KeepRunning()) {
61+
for (auto it = in.data(); it != end; ++it) {
62+
benchmark::DoNotOptimize(last_hash += fn(*it));
63+
}
64+
benchmark::ClobberMemory();
65+
}
66+
}
67+
68+
BENCHMARK_CAPTURE(BM_Hash, uint32_random_std_hash, std::hash<uint32_t>{}, getRandomIntegerInputs<uint32_t>)
69+
->Arg(TestNumInputs);
70+
71+
BENCHMARK_CAPTURE(BM_Hash, uint32_random_custom_hash, UInt32Hash{}, getRandomIntegerInputs<uint32_t>)
72+
->Arg(TestNumInputs);
73+
74+
BENCHMARK_CAPTURE(BM_Hash, uint32_top_std_hash, std::hash<uint32_t>{}, getSortedTopBitsIntegerInputs<uint32_t>)
75+
->Arg(TestNumInputs);
76+
77+
BENCHMARK_CAPTURE(BM_Hash, uint32_top_custom_hash, UInt32Hash{}, getSortedTopBitsIntegerInputs<uint32_t>)
78+
->Arg(TestNumInputs);
79+
80+
BENCHMARK_MAIN();

libcxx/test/benchmarks/unordered_set_operations.bench.cpp

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,6 @@ struct UInt32Hash2 {
9595
}
9696
};
9797

98-
struct UInt64Hash2 {
99-
UInt64Hash2() = default;
100-
inline TEST_ALWAYS_INLINE std::size_t operator()(uint64_t data) const {
101-
return hash_len_0_to_8<8>(reinterpret_cast<const char*>(&data));
102-
}
103-
};
104-
10598
// The sole purpose of this comparator is to be used in BM_Rehash, where
10699
// we need something slow enough to be easily noticable in benchmark results.
107100
// The default implementation of operator== for strings seems to be a little
@@ -123,36 +116,6 @@ struct SlowStringEq {
123116
}
124117
};
125118

126-
//----------------------------------------------------------------------------//
127-
// BM_Hash
128-
// ---------------------------------------------------------------------------//
129-
130-
template <class HashFn, class GenInputs>
131-
void BM_Hash(benchmark::State& st, HashFn fn, GenInputs gen) {
132-
auto in = gen(st.range(0));
133-
const auto end = in.data() + in.size();
134-
std::size_t last_hash = 0;
135-
benchmark::DoNotOptimize(&last_hash);
136-
while (st.KeepRunning()) {
137-
for (auto it = in.data(); it != end; ++it) {
138-
benchmark::DoNotOptimize(last_hash += fn(*it));
139-
}
140-
benchmark::ClobberMemory();
141-
}
142-
}
143-
144-
BENCHMARK_CAPTURE(BM_Hash, uint32_random_std_hash, std::hash<uint32_t>{}, getRandomIntegerInputs<uint32_t>)
145-
->Arg(TestNumInputs);
146-
147-
BENCHMARK_CAPTURE(BM_Hash, uint32_random_custom_hash, UInt32Hash{}, getRandomIntegerInputs<uint32_t>)
148-
->Arg(TestNumInputs);
149-
150-
BENCHMARK_CAPTURE(BM_Hash, uint32_top_std_hash, std::hash<uint32_t>{}, getSortedTopBitsIntegerInputs<uint32_t>)
151-
->Arg(TestNumInputs);
152-
153-
BENCHMARK_CAPTURE(BM_Hash, uint32_top_custom_hash, UInt32Hash{}, getSortedTopBitsIntegerInputs<uint32_t>)
154-
->Arg(TestNumInputs);
155-
156119
//----------------------------------------------------------------------------//
157120
// BM_InsertValue
158121
// ---------------------------------------------------------------------------//

0 commit comments

Comments
 (0)