Skip to content

Commit cc413f8

Browse files
Abseil Teamsuertreus
authored andcommitted
Export of internal Abseil changes
-- 05a099a580753f8e96cee38572e94dcdc079361b by Abseil Team <[email protected]>: Import of CCTZ from GitHub. PiperOrigin-RevId: 405966217 -- c6b81e9ebc183d8389f14ecd091c8bad08cfe0aa by Abseil Team <[email protected]>: Add `inline_element_size` to hashtablez (so that we can compute the weighted load factors properly e.g., in b/187896534). PiperOrigin-RevId: 405917711 -- 3e3673de4e54e4142c54b09e1644dfa3de4bb296 by Abseil Team <[email protected]>: align indent of code comment in mutex.h PiperOrigin-RevId: 405871997 -- 2248301a5b14f8d2be5b2e9088f3528a353ea491 by Derek Mauro <[email protected]>: Internal change PiperOrigin-RevId: 405639236 -- bc7d3c56fdad3dde4b89324af142529f2afe5f1b by Abseil Team <[email protected]>: Import of CCTZ from GitHub. PiperOrigin-RevId: 405508045 -- 66472387276ef02505d99195747be862768bb35b by Laramie Leavitt <[email protected]>: Also use uint8_t golden values in randen_test.cc This makes randen_test, randen_slow_test, and randen_hwaes_test essentially identical, as is the intent. PiperOrigin-RevId: 405484423 GitOrigin-RevId: 05a099a580753f8e96cee38572e94dcdc079361b Change-Id: I3dd5b0cfdb98d6e1ab02266194ba67d15428c2f8
1 parent f70eada commit cc413f8

File tree

17 files changed

+329
-37
lines changed

17 files changed

+329
-37
lines changed

absl/container/BUILD.bazel

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,22 @@ cc_test(
876876
],
877877
)
878878

879+
cc_test(
880+
name = "sample_element_size_test",
881+
srcs = ["sample_element_size_test.cc"],
882+
copts = ABSL_TEST_COPTS,
883+
linkopts = ABSL_DEFAULT_LINKOPTS,
884+
tags = NOTEST_TAGS_NONMOBILE,
885+
visibility = ["//visibility:private"],
886+
deps = [
887+
":flat_hash_map",
888+
":flat_hash_set",
889+
":node_hash_map",
890+
":node_hash_set",
891+
"@com_google_googletest//:gtest_main",
892+
],
893+
)
894+
879895
cc_library(
880896
name = "btree",
881897
srcs = [

absl/container/CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,3 +894,18 @@ absl_cc_test(
894894
absl::unordered_map_modifiers_test
895895
GTest::gmock_main
896896
)
897+
898+
absl_cc_test(
899+
NAME
900+
sample_element_size_test
901+
SRCS
902+
"sample_element_size_test.cc"
903+
COPTS
904+
${ABSL_TEST_COPTS}
905+
DEPS
906+
absl::flat_hash_map
907+
absl::flat_hash_set
908+
absl::node_hash_map
909+
absl::node_hash_set
910+
GTest::gmock_main
911+
)

absl/container/internal/hashtablez_sampler.cc

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ HashtablezSampler& GlobalHashtablezSampler() {
5555
return *sampler;
5656
}
5757

58+
// TODO(bradleybear): The comments at this constructors declaration say that the
59+
// fields are not initialized, but this definition does initialize the fields.
60+
// Something needs to be cleaned up.
5861
HashtablezInfo::HashtablezInfo() { PrepareForSampling(); }
5962
HashtablezInfo::~HashtablezInfo() = default;
6063

@@ -98,10 +101,12 @@ static bool ShouldForceSampling() {
98101
return state == kForce;
99102
}
100103

101-
HashtablezInfo* SampleSlow(int64_t* next_sample) {
104+
HashtablezInfo* SampleSlow(int64_t* next_sample, size_t inline_element_size) {
102105
if (ABSL_PREDICT_FALSE(ShouldForceSampling())) {
103106
*next_sample = 1;
104-
return GlobalHashtablezSampler().Register();
107+
HashtablezInfo* result = GlobalHashtablezSampler().Register();
108+
result->inline_element_size = inline_element_size;
109+
return result;
105110
}
106111

107112
#if !defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
@@ -123,10 +128,12 @@ HashtablezInfo* SampleSlow(int64_t* next_sample) {
123128
// that case.
124129
if (first) {
125130
if (ABSL_PREDICT_TRUE(--*next_sample > 0)) return nullptr;
126-
return SampleSlow(next_sample);
131+
return SampleSlow(next_sample, inline_element_size);
127132
}
128133

129-
return GlobalHashtablezSampler().Register();
134+
HashtablezInfo* result = GlobalHashtablezSampler().Register();
135+
result->inline_element_size = inline_element_size;
136+
return result;
130137
#endif
131138
}
132139

absl/container/internal/hashtablez_sampler.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ struct HashtablezInfo : public profiling_internal::Sample<HashtablezInfo> {
9191
absl::Time create_time;
9292
int32_t depth;
9393
void* stack[kMaxStackDepth];
94+
size_t inline_element_size;
9495
};
9596

9697
inline void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length) {
@@ -143,7 +144,7 @@ inline void RecordEraseSlow(HashtablezInfo* info) {
143144
std::memory_order_relaxed);
144145
}
145146

146-
HashtablezInfo* SampleSlow(int64_t* next_sample);
147+
HashtablezInfo* SampleSlow(int64_t* next_sample, size_t inline_element_size);
147148
void UnsampleSlow(HashtablezInfo* info);
148149

149150
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
@@ -238,12 +239,14 @@ extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample;
238239

239240
// Returns an RAII sampling handle that manages registration and unregistation
240241
// with the global sampler.
241-
inline HashtablezInfoHandle Sample() {
242+
inline HashtablezInfoHandle Sample(
243+
size_t inline_element_size ABSL_ATTRIBUTE_UNUSED) {
242244
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
243245
if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) {
244246
return HashtablezInfoHandle(nullptr);
245247
}
246-
return HashtablezInfoHandle(SampleSlow(&global_next_sample));
248+
return HashtablezInfoHandle(
249+
SampleSlow(&global_next_sample, inline_element_size));
247250
#else
248251
return HashtablezInfoHandle(nullptr);
249252
#endif // !ABSL_PER_THREAD_TLS

absl/container/internal/hashtablez_sampler_test.cc

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,12 @@ HashtablezInfo* Register(HashtablezSampler* s, size_t size) {
7878

7979
TEST(HashtablezInfoTest, PrepareForSampling) {
8080
absl::Time test_start = absl::Now();
81+
const size_t test_element_size = 17;
8182
HashtablezInfo info;
8283
absl::MutexLock l(&info.init_mu);
8384
info.PrepareForSampling();
8485

86+
info.inline_element_size = test_element_size;
8587
EXPECT_EQ(info.capacity.load(), 0);
8688
EXPECT_EQ(info.size.load(), 0);
8789
EXPECT_EQ(info.num_erases.load(), 0);
@@ -93,6 +95,7 @@ TEST(HashtablezInfoTest, PrepareForSampling) {
9395
EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
9496
EXPECT_EQ(info.max_reserve.load(), 0);
9597
EXPECT_GE(info.create_time, test_start);
98+
EXPECT_EQ(info.inline_element_size, test_element_size);
9699

97100
info.capacity.store(1, std::memory_order_relaxed);
98101
info.size.store(1, std::memory_order_relaxed);
@@ -116,6 +119,7 @@ TEST(HashtablezInfoTest, PrepareForSampling) {
116119
EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
117120
EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
118121
EXPECT_EQ(info.max_reserve.load(), 0);
122+
EXPECT_EQ(info.inline_element_size, test_element_size);
119123
EXPECT_GE(info.create_time, test_start);
120124
}
121125

@@ -154,22 +158,27 @@ TEST(HashtablezInfoTest, RecordInsert) {
154158
}
155159

156160
TEST(HashtablezInfoTest, RecordErase) {
161+
const size_t test_element_size = 29;
157162
HashtablezInfo info;
158163
absl::MutexLock l(&info.init_mu);
159164
info.PrepareForSampling();
165+
info.inline_element_size = test_element_size;
160166
EXPECT_EQ(info.num_erases.load(), 0);
161167
EXPECT_EQ(info.size.load(), 0);
162168
RecordInsertSlow(&info, 0x0000FF00, 6 * kProbeLength);
163169
EXPECT_EQ(info.size.load(), 1);
164170
RecordEraseSlow(&info);
165171
EXPECT_EQ(info.size.load(), 0);
166172
EXPECT_EQ(info.num_erases.load(), 1);
173+
EXPECT_EQ(info.inline_element_size, test_element_size);
167174
}
168175

169176
TEST(HashtablezInfoTest, RecordRehash) {
177+
const size_t test_element_size = 31;
170178
HashtablezInfo info;
171179
absl::MutexLock l(&info.init_mu);
172180
info.PrepareForSampling();
181+
info.inline_element_size = test_element_size;
173182
RecordInsertSlow(&info, 0x1, 0);
174183
RecordInsertSlow(&info, 0x2, kProbeLength);
175184
RecordInsertSlow(&info, 0x4, kProbeLength);
@@ -188,6 +197,7 @@ TEST(HashtablezInfoTest, RecordRehash) {
188197
EXPECT_EQ(info.total_probe_length.load(), 3);
189198
EXPECT_EQ(info.num_erases.load(), 0);
190199
EXPECT_EQ(info.num_rehashes.load(), 1);
200+
EXPECT_EQ(info.inline_element_size, test_element_size);
191201
}
192202

193203
TEST(HashtablezInfoTest, RecordReservation) {
@@ -208,39 +218,42 @@ TEST(HashtablezInfoTest, RecordReservation) {
208218

209219
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
210220
TEST(HashtablezSamplerTest, SmallSampleParameter) {
221+
const size_t test_element_size = 31;
211222
SetHashtablezEnabled(true);
212223
SetHashtablezSampleParameter(100);
213224

214225
for (int i = 0; i < 1000; ++i) {
215226
int64_t next_sample = 0;
216-
HashtablezInfo* sample = SampleSlow(&next_sample);
227+
HashtablezInfo* sample = SampleSlow(&next_sample, test_element_size);
217228
EXPECT_GT(next_sample, 0);
218229
EXPECT_NE(sample, nullptr);
219230
UnsampleSlow(sample);
220231
}
221232
}
222233

223234
TEST(HashtablezSamplerTest, LargeSampleParameter) {
235+
const size_t test_element_size = 31;
224236
SetHashtablezEnabled(true);
225237
SetHashtablezSampleParameter(std::numeric_limits<int32_t>::max());
226238

227239
for (int i = 0; i < 1000; ++i) {
228240
int64_t next_sample = 0;
229-
HashtablezInfo* sample = SampleSlow(&next_sample);
241+
HashtablezInfo* sample = SampleSlow(&next_sample, test_element_size);
230242
EXPECT_GT(next_sample, 0);
231243
EXPECT_NE(sample, nullptr);
232244
UnsampleSlow(sample);
233245
}
234246
}
235247

236248
TEST(HashtablezSamplerTest, Sample) {
249+
const size_t test_element_size = 31;
237250
SetHashtablezEnabled(true);
238251
SetHashtablezSampleParameter(100);
239252
int64_t num_sampled = 0;
240253
int64_t total = 0;
241254
double sample_rate = 0.0;
242255
for (int i = 0; i < 1000000; ++i) {
243-
HashtablezInfoHandle h = Sample();
256+
HashtablezInfoHandle h = Sample(test_element_size);
244257
++total;
245258
if (HashtablezInfoHandlePeer::IsSampled(h)) {
246259
++num_sampled;

absl/container/internal/raw_hash_set.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1643,7 +1643,7 @@ class raw_hash_set {
16431643
// bound more carefully.
16441644
if (std::is_same<SlotAlloc, std::allocator<slot_type>>::value &&
16451645
slots_ == nullptr) {
1646-
infoz() = Sample();
1646+
infoz() = Sample(sizeof(slot_type));
16471647
}
16481648

16491649
char* mem = static_cast<char*>(Allocate<alignof(slot_type)>(

absl/container/internal/raw_hash_set_test.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2075,6 +2075,7 @@ TEST(RawHashSamplerTest, Sample) {
20752075
std::memory_order_relaxed)]++;
20762076
reservations[info.max_reserve.load(std::memory_order_relaxed)]++;
20772077
}
2078+
EXPECT_EQ(info.inline_element_size, sizeof(int64_t));
20782079
++end_size;
20792080
});
20802081

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright 2018 The Abseil Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "gmock/gmock.h"
16+
#include "gtest/gtest.h"
17+
#include "absl/container/flat_hash_map.h"
18+
#include "absl/container/flat_hash_set.h"
19+
#include "absl/container/node_hash_map.h"
20+
#include "absl/container/node_hash_set.h"
21+
22+
namespace absl {
23+
ABSL_NAMESPACE_BEGIN
24+
namespace container_internal {
25+
namespace {
26+
27+
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
28+
// Create some tables of type `Table`, then look at all the new
29+
// `HashtablezInfo`s to make sure that the `inline_element_size ==
30+
// expected_element_size`. The `inline_element_size` is the amount of memory
31+
// allocated for each slot of a hash table, that is `sizeof(slot_type)`. Add
32+
// the new `HashtablezInfo`s to `preexisting_info`. Store all the new tables
33+
// into `tables`.
34+
template <class Table>
35+
void TestInlineElementSize(
36+
HashtablezSampler& sampler,
37+
// clang-tidy gives a false positive on this declaration. This unordered
38+
// set cannot be flat_hash_set, however, since that would introduce a mutex
39+
// deadlock.
40+
std::unordered_set<const HashtablezInfo*>& preexisting_info, // NOLINT
41+
std::vector<Table>& tables, const typename Table::value_type& elt,
42+
size_t expected_element_size) {
43+
for (int i = 0; i < 10; ++i) {
44+
// We create a new table and must store it somewhere so that when we store
45+
// a pointer to the resulting `HashtablezInfo` into `preexisting_info`
46+
// that we aren't storing a dangling pointer.
47+
tables.emplace_back();
48+
// We must insert an element to get a hashtablez to instantiate.
49+
tables.back().insert(elt);
50+
}
51+
size_t new_count = 0;
52+
sampler.Iterate([&](const HashtablezInfo& info) {
53+
if (preexisting_info.insert(&info).second) {
54+
EXPECT_EQ(info.inline_element_size, expected_element_size);
55+
++new_count;
56+
}
57+
});
58+
// Make sure we actually did get a new hashtablez.
59+
EXPECT_GT(new_count, 0);
60+
}
61+
62+
struct bigstruct {
63+
char a[1000];
64+
friend bool operator==(const bigstruct& x, const bigstruct& y) {
65+
return memcmp(x.a, y.a, sizeof(x.a)) == 0;
66+
}
67+
template <typename H>
68+
friend H AbslHashValue(H h, const bigstruct& c) {
69+
return H::combine_contiguous(std::move(h), c.a, sizeof(c.a));
70+
}
71+
};
72+
#endif
73+
74+
TEST(FlatHashMap, SampleElementSize) {
75+
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
76+
// Enable sampling even if the prod default is off.
77+
SetHashtablezEnabled(true);
78+
SetHashtablezSampleParameter(1);
79+
80+
auto& sampler = GlobalHashtablezSampler();
81+
std::vector<flat_hash_map<int, bigstruct>> flat_map_tables;
82+
std::vector<flat_hash_set<bigstruct>> flat_set_tables;
83+
std::vector<node_hash_map<int, bigstruct>> node_map_tables;
84+
std::vector<node_hash_set<bigstruct>> node_set_tables;
85+
86+
// It takes thousands of new tables after changing the sampling parameters
87+
// before you actually get some instrumentation. And if you must actually
88+
// put something into those tables.
89+
for (int i = 0; i < 10000; ++i) {
90+
flat_map_tables.emplace_back();
91+
flat_map_tables.back()[i] = bigstruct{};
92+
}
93+
94+
// clang-tidy gives a false positive on this declaration. This unordered set
95+
// cannot be a flat_hash_set, however, since that would introduce a mutex
96+
// deadlock.
97+
std::unordered_set<const HashtablezInfo*> preexisting_info; // NOLINT
98+
sampler.Iterate(
99+
[&](const HashtablezInfo& info) { preexisting_info.insert(&info); });
100+
TestInlineElementSize(sampler, preexisting_info, flat_map_tables,
101+
{0, bigstruct{}}, sizeof(int) + sizeof(bigstruct));
102+
TestInlineElementSize(sampler, preexisting_info, node_map_tables,
103+
{0, bigstruct{}}, sizeof(void*));
104+
TestInlineElementSize(sampler, preexisting_info, flat_set_tables, //
105+
bigstruct{}, sizeof(bigstruct));
106+
TestInlineElementSize(sampler, preexisting_info, node_set_tables, //
107+
bigstruct{}, sizeof(void*));
108+
#endif
109+
}
110+
111+
} // namespace
112+
} // namespace container_internal
113+
ABSL_NAMESPACE_END
114+
} // namespace absl

0 commit comments

Comments
 (0)