Bug 1867190 - Make the PHC probability dynamic r=glandium

Differential Revision: https://phabricator.services.mozilla.com/D194364
This commit is contained in:
Paul Bone 2024-01-30 05:33:38 +00:00
Родитель 48de47067e
Коммит 9f2470a841
1 изменённых файлов: 45 добавлений и 37 удалений

Просмотреть файл

@ -337,32 +337,13 @@ static const size_t kAllPagesJemallocSize = kAllPagesSize - kPageSize;
// The maximum time.
static const Time kMaxTime = ~(Time(0));
// The average delay before doing any page allocations at the start of a
// process. Note that roughly 1 million allocations occur in the main process
// while starting the browser. The delay range is 1..kAvgFirstAllocDelay*2.
static const Delay kAvgFirstAllocDelay = 64 * 1024;
// The average delay until the next attempted page allocation, once we get past
// the first delay. The delay range is 1..kAvgAllocDelay*2.
static const Delay kAvgAllocDelay = 16 * 1024;
// The average delay before reusing a freed page. Should be significantly larger
// than kAvgAllocDelay, otherwise there's not much point in having it. The delay
// range is (kAvgAllocDelay / 2)..(kAvgAllocDelay / 2 * 3). This is different to
// the other delay ranges in not having a minimum of 1, because that's such a
// short delay that there is a high likelihood of bad stacks in any crash
// report.
static const Delay kAvgPageReuseDelay = 256 * 1024;
// Truncate aRnd to the range (1 .. AvgDelay*2). If aRnd is random, this
// Truncate aRnd to the range (1 .. aAvgDelay*2). If aRnd is random, this
// results in an average value of aAvgDelay + 0.5, which is close enough to
// aAvgDelay. aAvgDelay must be a power-of-two (otherwise it will crash) for
// speed.
template <Delay AvgDelay>
constexpr Delay Rnd64ToDelay(uint64_t aRnd) {
static_assert(IsPowerOfTwo(AvgDelay), "must be a power of two");
// aAvgDelay. aAvgDelay must be a power-of-two for speed.
constexpr Delay Rnd64ToDelay(Delay aAvgDelay, uint64_t aRnd) {
MOZ_ASSERT(IsPowerOfTwo(aAvgDelay), "must be a power of two");
return aRnd % (AvgDelay * 2) + 1;
return (aRnd & (aAvgDelay * 2 - 1)) + 1;
}
// Maps a pointer to a PHC-specific structure:
@ -437,10 +418,11 @@ class GAtomic {
static void SetAllocDelay(Delay aAllocDelay) { sAllocDelay = aAllocDelay; }
static bool AllocDelayHasWrapped() {
static bool AllocDelayHasWrapped(Delay aAvgAllocDelay,
Delay aAvgFirstAllocDelay) {
// Delay is unsigned so we can't test for less that zero. Instead test if
// it has wrapped around by comparing with the maximum value we ever use.
return sAllocDelay > 2 * std::max(kAvgAllocDelay, kAvgFirstAllocDelay);
return sAllocDelay > 2 * std::max(aAvgAllocDelay, aAvgFirstAllocDelay);
}
private:
@ -875,7 +857,7 @@ class GMut {
void SetState(PHCState aState) {
if (mPhcState != PHCState::Enabled && aState == PHCState::Enabled) {
MutexAutoLock lock(GMut::sMutex);
GAtomic::Init(Rnd64ToDelay<kAvgFirstAllocDelay>(Random64(lock)));
GAtomic::Init(Rnd64ToDelay(mAvgFirstAllocDelay, Random64(lock)));
}
mPhcState = aState;
@ -945,6 +927,32 @@ class GMut {
// eventually get the update.
Atomic<PHCState, Relaxed> mPhcState =
Atomic<PHCState, Relaxed>(DEFAULT_STATE);
// The average delay before doing any page allocations at the start of a
// process. Note that roughly 1 million allocations occur in the main process
// while starting the browser. The delay range is 1..gAvgFirstAllocDelay*2.
Delay mAvgFirstAllocDelay = 64 * 1024;
// The average delay until the next attempted page allocation, once we get
// past the first delay. The delay range is 1..kAvgAllocDelay*2.
Delay mAvgAllocDelay = 16 * 1024;
// The average delay before reusing a freed page. Should be significantly
// larger than kAvgAllocDelay, otherwise there's not much point in having it.
// The delay range is (kAvgAllocDelay / 2)..(kAvgAllocDelay / 2 * 3). This is
// different to the other delay ranges in not having a minimum of 1, because
// that's such a short delay that there is a high likelihood of bad stacks in
// any crash report.
Delay mAvgPageReuseDelay = 256 * 1024;
public:
Delay GetAvgAllocDelay(const MutexAutoLock&) { return mAvgAllocDelay; }
Delay GetAvgFirstAllocDelay(const MutexAutoLock&) {
return mAvgFirstAllocDelay;
}
Delay GetAvgPageReuseDelay(const MutexAutoLock&) {
return mAvgPageReuseDelay;
}
};
Mutex GMut::sMutex;
@ -1040,13 +1048,11 @@ class GTls {
static void EnableOnCurrentThread() {
MOZ_ASSERT(GTls::tlsIsDisabled.get());
uint64_t rand;
if (GAtomic::AllocDelayHasWrapped()) {
{
MutexAutoLock lock(GMut::sMutex);
rand = gMut->Random64(lock);
}
GAtomic::SetAllocDelay(Rnd64ToDelay<kAvgAllocDelay>(rand));
MutexAutoLock lock(GMut::sMutex);
Delay avg_delay = gMut->GetAvgAllocDelay(lock);
Delay avg_first_delay = gMut->GetAvgFirstAllocDelay(lock);
if (GAtomic::AllocDelayHasWrapped(avg_delay, avg_first_delay)) {
GAtomic::SetAllocDelay(Rnd64ToDelay(avg_delay, gMut->Random64(lock)));
}
tlsIsDisabled.set(false);
}
@ -1185,7 +1191,8 @@ static void* MaybePageAlloc(const Maybe<arena_id_t>& aArenaId, size_t aReqSize,
MutexAutoLock lock(GMut::sMutex);
Time now = GAtomic::Now();
Delay newAllocDelay = Rnd64ToDelay<kAvgAllocDelay>(gMut->Random64(lock));
Delay newAllocDelay =
Rnd64ToDelay(gMut->GetAvgAllocDelay(lock), gMut->Random64(lock));
// We start at a random page alloc and wrap around, to ensure pages get even
// amounts of use.
@ -1312,8 +1319,9 @@ inline void* MozJemallocPHC::malloc(size_t aReqSize) {
}
static Delay ReuseDelay(GMutLock aLock) {
return (kAvgPageReuseDelay / 2) +
Rnd64ToDelay<kAvgPageReuseDelay / 2>(gMut->Random64(aLock));
Delay avg_reuse_delay = gMut->GetAvgPageReuseDelay(aLock);
return (avg_reuse_delay / 2) +
Rnd64ToDelay(avg_reuse_delay / 2, gMut->Random64(aLock));
}
// This handles both calloc and moz_arena_calloc.