mirror of
https://github.com/google/tcmalloc.git
synced 2026-10-28 16:44:45 +08:00
Fix modulo-4 low-bit sampling bias in HugePageFiller::Contribute.
When contributing a hugepage tracker, the filler steps a 48-bit linear congruential generator via `ExponentialBiased::NextRandom` and samples 1% of trackers for VMA tagging. Taking the remainder of the raw generator state modulo 100 depends on its low two bits, which cycle with period 4 because 100 is a multiple of 4. Starting from a zero seed, only contributions at index 3 modulo 4 could ever be sampled, which excluded three quarters of contributed hugepages. Extract high-order bits via `ExponentialBiased::GetRandom` before taking the remainder modulo 100 so all modulo-4 contribution indices are sampled uniformly, and initialize the generator state to 42. Co-authored-by: Chris Kennelly <ckennelly@google.com> PiperOrigin-RevId: 1008455755
This commit is contained in:
1 parent
0aed5651ce
commit
e18f88dca6
2 files changed
+28
-2
No files matched your search
@@ -927,7 +927,7 @@ class HugePageFiller {
|
||||
MemoryTagFunction& set_anon_vma_name_;
|
||||
int max_backoff_delay_ ABSL_GUARDED_BY(pageheap_lock) = 1;
|
||||
int current_backoff_delay_ ABSL_GUARDED_BY(pageheap_lock) = 0;
|
||||
uintptr_t rng_ = 0;
|
||||
uint64_t rng_ = 42;
|
||||
SubreleaseUnbackedMode subrelease_unbacked_mode_;
|
||||
};
|
||||
|
||||
@@ -1224,7 +1224,8 @@ inline void HugePageFiller<TrackerType>::Contribute(
|
||||
|
||||
// Decide whether to sample this tracker for tagging.
|
||||
rng_ = ExponentialBiased::NextRandom(rng_);
|
||||
pt->SetTagState({.sampled_for_tagging = (rng_ % 100 == 0)});
|
||||
pt->SetTagState(
|
||||
{.sampled_for_tagging = (ExponentialBiased::GetRandom(rng_) % 100 == 0)});
|
||||
|
||||
pages_allocated_[type] += pt->used_pages();
|
||||
TC_ASSERT(!(type == AccessDensityPrediction::kDense && donated));
|
||||
|
||||
@@ -8629,6 +8629,31 @@ TEST_F(FillerTest, PreferBackedFillerPages) {
|
||||
DeleteRaw(tail);
|
||||
}
|
||||
|
||||
TEST_F(FillerTest, ContributeSamplesAcrossModuloFourResidues) {
|
||||
randomize_density_ = false;
|
||||
set_anon_vma_name_.SetIgnoreName(true);
|
||||
|
||||
const Length kAlloc = kPagesPerHugePage / 2 + Length(1);
|
||||
SpanAllocInfo sparse_info = {1, AccessDensityPrediction::kSparse};
|
||||
|
||||
// Raw NextRandom(rng_) % 100 == 0 could only ever sample contributions with
|
||||
// index % 4 == 3 because 100 % 4 == 0 and the 48-bit LCG low 2 bits cycle
|
||||
// with period 4. Verify all four mod-4 residues are sampled.
|
||||
std::array<int, 4> residue_counts = {0, 0, 0, 0};
|
||||
for (int i = 0; i < 4000; ++i) {
|
||||
PAlloc p = AllocateWithSpanAllocInfo(kAlloc, sparse_info);
|
||||
if (p.pt->GetTagState().sampled_for_tagging) {
|
||||
++residue_counts[i % 4];
|
||||
}
|
||||
DeleteRaw(p);
|
||||
}
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
EXPECT_GT(residue_counts[r], 0) << "residue " << r;
|
||||
}
|
||||
DrainFreedTrackers();
|
||||
CheckStats();
|
||||
}
|
||||
|
||||
TEST(SkipSubreleaseIntervalsTest, EmptyIsNotEnabled) {
|
||||
// When we have a limit hit, we pass SkipSubreleaseIntervals{} to the
|
||||
// filler. Make sure it doesn't signal that we should skip the limit.
|
||||
|
||||
Reference in new issue
Block a user