15 #include "absl/container/internal/hashtablez_sampler.h"
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include "absl/base/attributes.h"
24 #include "absl/base/config.h"
26 #include "absl/synchronization/blocking_counter.h"
27 #include "absl/synchronization/internal/thread_pool.h"
28 #include "absl/synchronization/mutex.h"
29 #include "absl/synchronization/notification.h"
30 #include "absl/time/clock.h"
31 #include "absl/time/time.h"
33 #ifdef ABSL_INTERNAL_HAVE_SSE2
41 namespace container_internal {
42 #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
43 class HashtablezInfoHandlePeer {
45 static bool IsSampled(
const HashtablezInfoHandle& h) {
46 return h.info_ !=
nullptr;
49 static HashtablezInfo*
GetInfo(HashtablezInfoHandle* h) {
return h->info_; }
57 #endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
60 using ::absl::synchronization_internal::ThreadPool;
65 std::vector<size_t> res;
66 s->Iterate([&](
const HashtablezInfo& info) {
67 res.push_back(info.size.load(std::memory_order_acquire));
73 const int64_t test_stride = 123;
74 const size_t test_element_size = 17;
75 auto* info =
s->Register(test_stride, test_element_size);
76 assert(info !=
nullptr);
77 info->size.store(
size);
81 TEST(HashtablezInfoTest, PrepareForSampling) {
83 const int64_t test_stride = 123;
84 const size_t test_element_size = 17;
87 info.PrepareForSampling(test_stride, test_element_size);
93 EXPECT_EQ(info.max_probe_length.load(), 0);
94 EXPECT_EQ(info.total_probe_length.load(), 0);
95 EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
96 EXPECT_EQ(info.hashes_bitwise_and.load(), ~
size_t{});
97 EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
101 EXPECT_EQ(info.inline_element_size, test_element_size);
103 info.capacity.store(1, std::memory_order_relaxed);
104 info.size.store(1, std::memory_order_relaxed);
105 info.num_erases.store(1, std::memory_order_relaxed);
106 info.max_probe_length.store(1, std::memory_order_relaxed);
107 info.total_probe_length.store(1, std::memory_order_relaxed);
108 info.hashes_bitwise_or.store(1, std::memory_order_relaxed);
109 info.hashes_bitwise_and.store(1, std::memory_order_relaxed);
110 info.hashes_bitwise_xor.store(1, std::memory_order_relaxed);
111 info.max_reserve.store(1, std::memory_order_relaxed);
114 info.PrepareForSampling(test_stride * 2, test_element_size);
119 EXPECT_EQ(info.max_probe_length.load(), 0);
120 EXPECT_EQ(info.total_probe_length.load(), 0);
121 EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
122 EXPECT_EQ(info.hashes_bitwise_and.load(), ~
size_t{});
123 EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
126 EXPECT_EQ(info.inline_element_size, test_element_size);
130 TEST(HashtablezInfoTest, RecordStorageChanged) {
133 const int64_t test_stride = 21;
134 const size_t test_element_size = 19;
135 info.PrepareForSampling(test_stride, test_element_size);
144 TEST(HashtablezInfoTest, RecordInsert) {
147 const int64_t test_stride = 25;
148 const size_t test_element_size = 23;
149 info.PrepareForSampling(test_stride, test_element_size);
150 EXPECT_EQ(info.max_probe_length.load(), 0);
152 EXPECT_EQ(info.max_probe_length.load(), 6);
153 EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000FF00);
154 EXPECT_EQ(info.hashes_bitwise_or.load(), 0x0000FF00);
155 EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x0000FF00);
157 EXPECT_EQ(info.max_probe_length.load(), 6);
158 EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000F000);
159 EXPECT_EQ(info.hashes_bitwise_or.load(), 0x000FFF00);
160 EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x000F0F00);
162 EXPECT_EQ(info.max_probe_length.load(), 12);
163 EXPECT_EQ(info.hashes_bitwise_and.load(), 0x00000000);
164 EXPECT_EQ(info.hashes_bitwise_or.load(), 0x00FFFF00);
165 EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x00F00F00);
168 TEST(HashtablezInfoTest, RecordErase) {
169 const int64_t test_stride = 31;
170 const size_t test_element_size = 29;
173 info.PrepareForSampling(test_stride, test_element_size);
181 EXPECT_EQ(info.inline_element_size, test_element_size);
184 TEST(HashtablezInfoTest, RecordRehash) {
185 const int64_t test_stride = 33;
186 const size_t test_element_size = 31;
189 info.PrepareForSampling(test_stride, test_element_size);
195 EXPECT_EQ(info.total_probe_length.load(), 4);
200 EXPECT_EQ(info.total_probe_length.load(), 4);
205 EXPECT_EQ(info.total_probe_length.load(), 3);
208 EXPECT_EQ(info.inline_element_size, test_element_size);
211 TEST(HashtablezInfoTest, RecordReservation) {
214 const int64_t test_stride = 35;
215 const size_t test_element_size = 33;
216 info.PrepareForSampling(test_stride, test_element_size);
229 #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
230 TEST(HashtablezSamplerTest, SmallSampleParameter) {
231 const size_t test_element_size = 31;
235 for (
int i = 0;
i < 1000; ++
i) {
236 SamplingState next_sample = {0, 0};
237 HashtablezInfo* sample =
SampleSlow(next_sample, test_element_size);
239 EXPECT_EQ(next_sample.next_sample, next_sample.sample_stride);
245 TEST(HashtablezSamplerTest, LargeSampleParameter) {
246 const size_t test_element_size = 31;
250 for (
int i = 0;
i < 1000; ++
i) {
251 SamplingState next_sample = {0, 0};
252 HashtablezInfo* sample =
SampleSlow(next_sample, test_element_size);
254 EXPECT_EQ(next_sample.next_sample, next_sample.sample_stride);
261 const size_t test_element_size = 31;
266 double sample_rate = 0.0;
267 for (
int i = 0;
i < 1000000; ++
i) {
268 HashtablezInfoHandle
h =
Sample(test_element_size);
273 sample_rate =
static_cast<double>(num_sampled) /
total;
274 if (0.005 < sample_rate && sample_rate < 0.015)
break;
279 TEST(HashtablezSamplerTest, Handle) {
281 const int64_t test_stride = 41;
282 const size_t test_element_size = 39;
283 HashtablezInfoHandle
h(sampler.Register(test_stride, test_element_size));
285 info->hashes_bitwise_and.store(0x12345678, std::memory_order_relaxed);
288 sampler.Iterate([&](
const HashtablezInfo& h) {
291 EXPECT_EQ(
h.hashes_bitwise_and.load(), 0x12345678);
297 h = HashtablezInfoHandle();
299 sampler.Iterate([&](
const HashtablezInfo& h) {
303 if (
h.hashes_bitwise_and.load() == 0x12345678) {
313 TEST(HashtablezSamplerTest, Registration) {
315 auto* info1 = Register(&sampler, 1);
318 auto* info2 = Register(&sampler, 2);
320 info1->size.store(3);
323 sampler.Unregister(info1);
324 sampler.Unregister(info2);
327 TEST(HashtablezSamplerTest, Unregistration) {
329 std::vector<HashtablezInfo*> infos;
330 for (
size_t i = 0;
i < 3; ++
i) {
331 infos.push_back(Register(&sampler, i));
335 sampler.Unregister(infos[1]);
338 infos.push_back(Register(&sampler, 3));
339 infos.push_back(Register(&sampler, 4));
341 sampler.Unregister(infos[3]);
344 sampler.Unregister(infos[0]);
345 sampler.Unregister(infos[2]);
346 sampler.Unregister(infos[4]);
350 TEST(HashtablezSamplerTest, MultiThreaded) {
355 for (
int i = 0;
i < 10; ++
i) {
356 const int64_t sampling_stride = 11 +
i % 3;
357 const size_t elt_size = 10 +
i % 2;
358 pool.Schedule([&sampler, &
stop, sampling_stride, elt_size]() {
359 std::random_device rd;
360 std::mt19937
gen(rd());
362 std::vector<HashtablezInfo*> infoz;
363 while (!
stop.HasBeenNotified()) {
365 infoz.push_back(sampler.Register(sampling_stride, elt_size));
367 switch (std::uniform_int_distribution<>(0, 2)(
gen)) {
369 infoz.push_back(sampler.Register(sampling_stride, elt_size));
374 std::uniform_int_distribution<>(0, infoz.size() - 1)(
gen);
375 HashtablezInfo* info = infoz[
p];
376 infoz[
p] = infoz.back();
378 EXPECT_EQ(info->weight, sampling_stride);
379 sampler.Unregister(info);
384 sampler.Iterate([&](
const HashtablezInfo& info) {
400 TEST(HashtablezSamplerTest, Callback) {
403 auto* info1 = Register(&sampler, 1);
404 auto* info2 = Register(&sampler, 2);
406 static const HashtablezInfo* expected;
408 auto callback = [](
const HashtablezInfo& info) {
417 sampler.Unregister(info1);
422 sampler.Unregister(info2);