Skip to content

Commit 2c83d70

Browse files
goldvitalycopybara-github
authored andcommitted
Reduce maximum load factor to 27/32 (from 28/32).
Affect large tables starting from capacity 63. And change the max load of elements ( capacity 63: -1, 127: -3, 255: -7, 511: -15). PiperOrigin-RevId: 797244582 Change-Id: I8b97730e34137cc399af54df577ac30cc31671a4
1 parent f363711 commit 2c83d70

File tree

2 files changed

+46
-27
lines changed

2 files changed

+46
-27
lines changed

absl/container/internal/raw_hash_set.h

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,30 +1175,32 @@ constexpr size_t NormalizeCapacity(size_t n) {
11751175
}
11761176

11771177
// General notes on capacity/growth methods below:
1178-
// - We use 7/8th as maximum load factor. For 16-wide groups, that gives an
1179-
// average of two empty slots per group.
1180-
// - For (capacity+1) >= Group::kWidth, growth is 7/8*capacity.
1178+
// - We use 27/32 as maximum load factor. For 16-wide groups, that gives an
1179+
// average of 2.5 empty slots per group.
11811180
// - For (capacity+1) < Group::kWidth, growth == capacity. In this case, we
11821181
// never need to probe (the whole table fits in one group) so we don't need a
11831182
// load factor less than 1.
1183+
// - For (capacity+1) == Group::kWidth, growth is capacity - 1 since we need
1184+
// at least one empty slot for probing algorithm.
1185+
// - For (capacity+1) > Group::kWidth, growth is 27/32*capacity.
11841186

11851187
// Given `capacity`, applies the load factor; i.e., it returns the maximum
11861188
// number of values we should put into the table before a resizing rehash.
11871189
constexpr size_t CapacityToGrowth(size_t capacity) {
11881190
ABSL_SWISSTABLE_ASSERT(IsValidCapacity(capacity));
1189-
// `capacity*7/8`
1191+
// `capacity*27/32`
11901192
if (Group::kWidth == 8 && capacity == 7) {
1191-
// x-x/8 does not work when x==7.
1193+
// formula does not work when x==7.
11921194
return 6;
11931195
}
1194-
return capacity - capacity / 8;
1196+
return capacity - capacity / 8 - capacity / 32;
11951197
}
11961198

11971199
// Given `size`, "unapplies" the load factor to find how large the capacity
11981200
// should be to stay within the load factor.
11991201
//
12001202
// For size == 0, returns 0.
1201-
// For other values, returns the same as `NormalizeCapacity(size*8/7)`.
1203+
// For other values, returns the same as `NormalizeCapacity(size*32/27)`.
12021204
constexpr size_t SizeToCapacity(size_t size) {
12031205
if (size == 0) {
12041206
return 0;
@@ -1207,18 +1209,10 @@ constexpr size_t SizeToCapacity(size_t size) {
12071209
// Shifting right `~size_t{}` by `leading_zeros` yields
12081210
// NormalizeCapacity(size).
12091211
int leading_zeros = absl::countl_zero(size);
1210-
constexpr size_t kLast3Bits = size_t{7} << (sizeof(size_t) * 8 - 3);
1211-
// max_size_for_next_capacity = max_load_factor * next_capacity
1212-
// = (7/8) * (~size_t{} >> leading_zeros)
1213-
// = (7/8*~size_t{}) >> leading_zeros
1214-
// = kLast3Bits >> leading_zeros
1215-
size_t max_size_for_next_capacity = kLast3Bits >> leading_zeros;
1212+
size_t next_capacity = ~size_t{} >> leading_zeros;
1213+
size_t max_size_for_next_capacity = CapacityToGrowth(next_capacity);
12161214
// Decrease shift if size is too big for the minimum capacity.
12171215
leading_zeros -= static_cast<int>(size > max_size_for_next_capacity);
1218-
if constexpr (Group::kWidth == 8) {
1219-
// Formula doesn't work when size==7 for 8-wide groups.
1220-
leading_zeros -= (size == 7);
1221-
}
12221216
return (~size_t{}) >> leading_zeros;
12231217
}
12241218

absl/container/internal/raw_hash_set_test.cc

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -276,38 +276,63 @@ TEST(Util, NormalizeCapacity) {
276276
EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 2));
277277
}
278278

279-
TEST(Util, GrowthAndCapacity) {
280-
// Verify that GrowthToCapacity gives the minimum capacity that has enough
281-
// growth.
279+
TEST(Util, SizeToCapacitySmallValues) {
282280
EXPECT_EQ(SizeToCapacity(0), 0);
283281
EXPECT_EQ(SizeToCapacity(1), 1);
284282
EXPECT_EQ(SizeToCapacity(2), 3);
285283
EXPECT_EQ(SizeToCapacity(3), 3);
284+
EXPECT_EQ(SizeToCapacity(4), 7);
285+
EXPECT_EQ(SizeToCapacity(5), 7);
286+
EXPECT_EQ(SizeToCapacity(6), 7);
287+
if (Group::kWidth == 16) {
288+
EXPECT_EQ(SizeToCapacity(7), 7);
289+
EXPECT_EQ(SizeToCapacity(14), 15);
290+
} else {
291+
EXPECT_EQ(SizeToCapacity(7), 15);
292+
}
293+
}
294+
295+
TEST(Util, CapacityToGrowthSmallValues) {
296+
EXPECT_EQ(CapacityToGrowth(1), 1);
297+
EXPECT_EQ(CapacityToGrowth(3), 3);
298+
if (Group::kWidth == 16) {
299+
EXPECT_EQ(CapacityToGrowth(7), 7);
300+
} else {
301+
EXPECT_EQ(CapacityToGrowth(7), 6);
302+
}
303+
EXPECT_EQ(CapacityToGrowth(15), 14);
304+
EXPECT_EQ(CapacityToGrowth(31), 28);
305+
EXPECT_EQ(CapacityToGrowth(63), 55);
306+
}
307+
308+
TEST(Util, GrowthAndCapacity) {
309+
// Verify that GrowthToCapacity gives the minimum capacity that has enough
310+
// growth.
286311
for (size_t growth = 1; growth < 10000; ++growth) {
287312
SCOPED_TRACE(growth);
288313
size_t capacity = SizeToCapacity(growth);
289314
ASSERT_TRUE(IsValidCapacity(capacity));
290315
// The capacity is large enough for `growth`.
291-
EXPECT_THAT(CapacityToGrowth(capacity), Ge(growth));
316+
ASSERT_THAT(CapacityToGrowth(capacity), Ge(growth));
292317
// For (capacity+1) < kWidth, growth should equal capacity.
293318
if (capacity + 1 < Group::kWidth) {
294-
EXPECT_THAT(CapacityToGrowth(capacity), Eq(capacity));
319+
ASSERT_THAT(CapacityToGrowth(capacity), Eq(capacity));
295320
} else {
296-
EXPECT_THAT(CapacityToGrowth(capacity), Lt(capacity));
321+
ASSERT_THAT(CapacityToGrowth(capacity), Lt(capacity));
297322
}
298323
if (growth != 0 && capacity > 1) {
299324
// There is no smaller capacity that works.
300-
EXPECT_THAT(CapacityToGrowth(capacity / 2), Lt(growth));
325+
ASSERT_THAT(CapacityToGrowth(capacity / 2), Lt(growth)) << capacity;
301326
}
302327
}
303328

304329
for (size_t capacity = Group::kWidth - 1; capacity < 10000;
305330
capacity = 2 * capacity + 1) {
306331
SCOPED_TRACE(capacity);
307332
size_t growth = CapacityToGrowth(capacity);
308-
EXPECT_THAT(growth, Lt(capacity));
309-
EXPECT_EQ(SizeToCapacity(growth), capacity);
310-
EXPECT_EQ(NormalizeCapacity(SizeToCapacity(growth)), capacity);
333+
ASSERT_THAT(growth, Lt(capacity));
334+
ASSERT_EQ(SizeToCapacity(growth), capacity);
335+
ASSERT_EQ(NormalizeCapacity(SizeToCapacity(growth)), capacity);
311336
}
312337
}
313338

0 commit comments

Comments
 (0)