Skip to content

Commit de71511

Browse files
Abseil Teamderekmauro
authored andcommitted
Export of internal Abseil changes
-- 3794fe8db7a8e5a17945a8d6e198cde1db1fed7d by Chris Kennelly <[email protected]>: Record maximum reserve or rehash argument in hashtable statistics. This makes it possible to identify containers that are large because of reserve calls or ones that could have an opportunity for more precise capacity sizing. PiperOrigin-RevId: 396851064 -- c3d247c08acfd45d8e19cfd8e6e841e16e38e23d by Abseil Team <[email protected]>: Remove extra semi-colon PiperOrigin-RevId: 396823800 GitOrigin-RevId: 3794fe8db7a8e5a17945a8d6e198cde1db1fed7d Change-Id: I9f26407c2dc6b3dff04f6f3e249571dd8ab288c3
1 parent 2f25e6e commit de71511

File tree

6 files changed

+84
-1
lines changed

6 files changed

+84
-1
lines changed

absl/container/internal/hashtablez_sampler.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ void HashtablezInfo::PrepareForSampling() {
6868
hashes_bitwise_or.store(0, std::memory_order_relaxed);
6969
hashes_bitwise_and.store(~size_t{}, std::memory_order_relaxed);
7070
hashes_bitwise_xor.store(0, std::memory_order_relaxed);
71+
max_reserve.store(0, std::memory_order_relaxed);
7172

7273
create_time = absl::Now();
7374
// The inliner makes hardcoded skip_count difficult (especially when combined

absl/container/internal/hashtablez_sampler.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ struct HashtablezInfo : public profiling_internal::Sample<HashtablezInfo> {
8080
std::atomic<size_t> hashes_bitwise_or;
8181
std::atomic<size_t> hashes_bitwise_and;
8282
std::atomic<size_t> hashes_bitwise_xor;
83+
std::atomic<size_t> max_reserve;
8384

8485
// All of the fields below are set by `PrepareForSampling`, they must not be
8586
// mutated in `Record*` functions. They are logically `const` in that sense.
@@ -107,6 +108,18 @@ inline void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length) {
107108
std::memory_order_relaxed);
108109
}
109110

111+
inline void RecordReservationSlow(HashtablezInfo* info,
112+
size_t target_capacity) {
113+
info->max_reserve.store(
114+
(std::max)(info->max_reserve.load(std::memory_order_relaxed),
115+
target_capacity),
116+
std::memory_order_relaxed);
117+
}
118+
119+
inline void RecordClearedReservationSlow(HashtablezInfo* info) {
120+
info->max_reserve.store(0, std::memory_order_relaxed);
121+
}
122+
110123
inline void RecordStorageChangedSlow(HashtablezInfo* info, size_t size,
111124
size_t capacity) {
112125
info->size.store(size, std::memory_order_relaxed);
@@ -170,6 +183,16 @@ class HashtablezInfoHandle {
170183
RecordRehashSlow(info_, total_probe_length);
171184
}
172185

186+
inline void RecordReservation(size_t target_capacity) {
187+
if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
188+
RecordReservationSlow(info_, target_capacity);
189+
}
190+
191+
inline void RecordClearedReservation() {
192+
if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
193+
RecordClearedReservationSlow(info_);
194+
}
195+
173196
inline void RecordInsert(size_t hash, size_t distance_from_desired) {
174197
if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
175198
RecordInsertSlow(info_, hash, distance_from_desired);
@@ -199,6 +222,8 @@ class HashtablezInfoHandle {
199222

200223
inline void RecordStorageChanged(size_t /*size*/, size_t /*capacity*/) {}
201224
inline void RecordRehash(size_t /*total_probe_length*/) {}
225+
inline void RecordReservation(size_t /*target_capacity*/) {}
226+
inline void RecordClearedReservation() {}
202227
inline void RecordInsert(size_t /*hash*/, size_t /*distance_from_desired*/) {}
203228
inline void RecordErase() {}
204229

absl/container/internal/hashtablez_sampler_test.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ TEST(HashtablezInfoTest, PrepareForSampling) {
9191
EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
9292
EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
9393
EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
94+
EXPECT_EQ(info.max_reserve.load(), 0);
9495
EXPECT_GE(info.create_time, test_start);
9596

9697
info.capacity.store(1, std::memory_order_relaxed);
@@ -101,6 +102,7 @@ TEST(HashtablezInfoTest, PrepareForSampling) {
101102
info.hashes_bitwise_or.store(1, std::memory_order_relaxed);
102103
info.hashes_bitwise_and.store(1, std::memory_order_relaxed);
103104
info.hashes_bitwise_xor.store(1, std::memory_order_relaxed);
105+
info.max_reserve.store(1, std::memory_order_relaxed);
104106
info.create_time = test_start - absl::Hours(20);
105107

106108
info.PrepareForSampling();
@@ -113,6 +115,7 @@ TEST(HashtablezInfoTest, PrepareForSampling) {
113115
EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
114116
EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
115117
EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
118+
EXPECT_EQ(info.max_reserve.load(), 0);
116119
EXPECT_GE(info.create_time, test_start);
117120
}
118121

@@ -187,6 +190,22 @@ TEST(HashtablezInfoTest, RecordRehash) {
187190
EXPECT_EQ(info.num_rehashes.load(), 1);
188191
}
189192

193+
TEST(HashtablezInfoTest, RecordReservation) {
194+
HashtablezInfo info;
195+
absl::MutexLock l(&info.init_mu);
196+
info.PrepareForSampling();
197+
RecordReservationSlow(&info, 3);
198+
EXPECT_EQ(info.max_reserve.load(), 3);
199+
200+
RecordReservationSlow(&info, 2);
201+
// High watermark does not change
202+
EXPECT_EQ(info.max_reserve.load(), 3);
203+
204+
RecordReservationSlow(&info, 10);
205+
// High watermark does change
206+
EXPECT_EQ(info.max_reserve.load(), 10);
207+
}
208+
190209
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
191210
TEST(HashtablezSamplerTest, SmallSampleParameter) {
192211
SetHashtablezEnabled(true);

absl/container/internal/raw_hash_set.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,8 @@ class raw_hash_set {
10691069
// past that we simply deallocate the array.
10701070
if (capacity_ > 127) {
10711071
destroy_slots();
1072+
1073+
infoz().RecordClearedReservation();
10721074
} else if (capacity_) {
10731075
for (size_t i = 0; i != capacity_; ++i) {
10741076
if (IsFull(ctrl_[i])) {
@@ -1382,21 +1384,31 @@ class raw_hash_set {
13821384
if (n == 0 && size_ == 0) {
13831385
destroy_slots();
13841386
infoz().RecordStorageChanged(0, 0);
1387+
infoz().RecordClearedReservation();
13851388
return;
13861389
}
1390+
13871391
// bitor is a faster way of doing `max` here. We will round up to the next
13881392
// power-of-2-minus-1, so bitor is good enough.
13891393
auto m = NormalizeCapacity(n | GrowthToLowerboundCapacity(size()));
13901394
// n == 0 unconditionally rehashes as per the standard.
13911395
if (n == 0 || m > capacity_) {
13921396
resize(m);
1397+
1398+
// This is after resize, to ensure that we have completed the allocation
1399+
// and have potentially sampled the hashtable.
1400+
infoz().RecordReservation(n);
13931401
}
13941402
}
13951403

13961404
void reserve(size_t n) {
13971405
if (n > size() + growth_left()) {
13981406
size_t m = GrowthToLowerboundCapacity(n);
13991407
resize(NormalizeCapacity(m));
1408+
1409+
// This is after resize, to ensure that we have completed the allocation
1410+
// and have potentially sampled the hashtable.
1411+
infoz().RecordReservation(n);
14001412
}
14011413
}
14021414

@@ -1638,6 +1650,7 @@ class raw_hash_set {
16381650
PolicyTraits::destroy(&alloc_ref(), slots_ + i);
16391651
}
16401652
}
1653+
16411654
// Unpoison before returning the memory to the allocator.
16421655
SanitizerUnpoisonMemoryRegion(slots_, sizeof(slot_type) * capacity_);
16431656
Deallocate<alignof(slot_type)>(

absl/container/internal/raw_hash_set_test.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,15 +2049,31 @@ TEST(RawHashSamplerTest, Sample) {
20492049
std::vector<IntTable> tables;
20502050
for (int i = 0; i < 1000000; ++i) {
20512051
tables.emplace_back();
2052+
2053+
const bool do_reserve = (i % 10 > 5);
2054+
const bool do_rehash = !do_reserve && (i % 10 > 0);
2055+
2056+
if (do_reserve) {
2057+
// Don't reserve on all tables.
2058+
tables.back().reserve(10 * (i % 10));
2059+
}
2060+
20522061
tables.back().insert(1);
20532062
tables.back().insert(i % 5);
2063+
2064+
if (do_rehash) {
2065+
// Rehash some other tables.
2066+
tables.back().rehash(10 * (i % 10));
2067+
}
20542068
}
20552069
size_t end_size = 0;
20562070
std::unordered_map<size_t, int> observed_checksums;
2071+
std::unordered_map<ssize_t, int> reservations;
20572072
end_size += sampler.Iterate([&](const HashtablezInfo& info) {
20582073
if (preexisting_info.count(&info) == 0) {
20592074
observed_checksums[info.hashes_bitwise_xor.load(
20602075
std::memory_order_relaxed)]++;
2076+
reservations[info.max_reserve.load(std::memory_order_relaxed)]++;
20612077
}
20622078
++end_size;
20632079
});
@@ -2068,6 +2084,15 @@ TEST(RawHashSamplerTest, Sample) {
20682084
for (const auto& [_, count] : observed_checksums) {
20692085
EXPECT_NEAR((100 * count) / static_cast<double>(tables.size()), 0.2, 0.05);
20702086
}
2087+
2088+
EXPECT_EQ(reservations.size(), 10);
2089+
for (const auto& [reservation, count] : reservations) {
2090+
EXPECT_GE(reservation, 0);
2091+
EXPECT_LT(reservation, 100);
2092+
2093+
EXPECT_NEAR((100 * count) / static_cast<double>(tables.size()), 0.1, 0.05)
2094+
<< reservation;
2095+
}
20712096
}
20722097
#endif // ABSL_INTERNAL_HASHTABLEZ_SAMPLE
20732098

absl/strings/internal/cord_rep_btree_reader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ inline size_t CordRepBtreeReader::length() const {
166166
inline absl::string_view CordRepBtreeReader::Init(CordRepBtree* tree) {
167167
assert(tree != nullptr);
168168
const CordRep* edge = navigator_.InitFirst(tree);
169-
remaining_ = tree->length - edge->length;;
169+
remaining_ = tree->length - edge->length;
170170
return CordRepBtree::EdgeData(edge);
171171
}
172172

0 commit comments

Comments
 (0)