Bug 1703443 - pt 14. Pass aSuspectedCCObjects into CC scheduling code r=smaug

Pass this value in also and remove the need for duplicate inlined
definitions between Firefox and gtest.

Differential Revision: https://phabricator.services.mozilla.com/D119363
This commit is contained in:
Paul Bone 2021-07-09 07:14:15 +00:00
Родитель bfe8bd0b67
Коммит ae50acaba7
4 изменённых файлов: 59 добавлений и 69 удалений

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

@ -10,11 +10,6 @@
namespace mozilla {
// This definition must match the one in nsJSEnvironment.cpp
uint32_t CCGCScheduler::SuspectedCCObjects() {
return nsCycleCollector_suspectedCount();
}
void CCGCScheduler::FullGCTimerFired(nsITimer* aTimer) {
KillFullGCTimer();
@ -330,12 +325,12 @@ void CCGCScheduler::EnsureCCRunner(TimeDuration aDelay, TimeDuration aBudget) {
}
}
void CCGCScheduler::MaybePokeCC(TimeStamp aNow) {
void CCGCScheduler::MaybePokeCC(TimeStamp aNow, uint32_t aSuspectedCCObjects) {
if (mCCRunner || mDidShutdown) {
return;
}
if (ShouldScheduleCC(aNow)) {
if (ShouldScheduleCC(aNow, aSuspectedCCObjects)) {
// We can kill some objects before running forgetSkippable.
nsCycleCollector_dispatchDeferredDeletion();

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

@ -108,15 +108,6 @@ struct CCRunnerStep {
class CCGCScheduler {
public:
// Mockable functions to interface with the code being scheduled. They
// are unused in CCGCScheduler.cpp but must be defined there anyway. Keep
// the definitions synchronised.
// Number of entries in the purple buffer (those objects whose ref counts
// have been decremented since the previous CC, roughly), and are therefore
// "suspected" of being members of cyclic garbage.
static inline uint32_t SuspectedCCObjects();
static bool CCRunnerFired(TimeStamp aDeadline);
// Parameter setting
@ -147,7 +138,7 @@ class CCGCScheduler {
void PokeGC(JS::GCReason aReason, JSObject* aObj, uint32_t aDelay = 0);
void PokeShrinkingGC();
void PokeFullGC();
void MaybePokeCC(TimeStamp aNow);
void MaybePokeCC(TimeStamp aNow, uint32_t aSuspectedCCObjects);
void UserIsInactive();
void UserIsActive();
@ -265,13 +256,13 @@ class CCGCScheduler {
void UnblockCC() { mCCBlockStart = TimeStamp(); }
// Returns the number of purple buffer items that were processed and removed.
uint32_t NoteForgetSkippableComplete(
TimeStamp aNow, uint32_t aSuspectedBeforeForgetSkippable) {
uint32_t NoteForgetSkippableComplete(TimeStamp aNow,
uint32_t aSuspectedBeforeForgetSkippable,
uint32_t aSuspectedCCObjects) {
mLastForgetSkippableEndTime = aNow;
uint32_t suspected = SuspectedCCObjects();
mPreviousSuspectedCount = suspected;
mPreviousSuspectedCount = aSuspectedCCObjects;
mCleanupsSinceLastGC++;
return aSuspectedBeforeForgetSkippable - suspected;
return aSuspectedBeforeForgetSkippable - aSuspectedCCObjects;
}
// After collecting cycles, record the results that are used in scheduling
@ -318,10 +309,10 @@ class CCGCScheduler {
inline TimeDuration ComputeInterSliceGCBudget(TimeStamp aDeadline,
TimeStamp aNow) const;
bool ShouldForgetSkippable() const {
bool ShouldForgetSkippable(uint32_t aSuspectedCCObjects) const {
// Only do a forget skippable if there are more than a few new objects
// or we're doing the initial forget skippables.
return ((mPreviousSuspectedCount + 100) <= SuspectedCCObjects()) ||
return ((mPreviousSuspectedCount + 100) <= aSuspectedCCObjects) ||
mCleanupsSinceLastGC < kMajorForgetSkippableCalls;
}
@ -329,17 +320,17 @@ class CCGCScheduler {
// garbage to cycle collect: either we just finished a GC, or the purple
// buffer is getting really big, or it's getting somewhat big and it has been
// too long since the last CC.
bool IsCCNeeded(TimeStamp aNow) const {
bool IsCCNeeded(TimeStamp aNow, uint32_t aSuspectedCCObjects) const {
if (mNeedsFullCC) {
return true;
}
uint32_t suspected = SuspectedCCObjects();
return suspected > kCCPurpleLimit ||
(suspected > kCCForcedPurpleLimit && mLastCCEndTime &&
return aSuspectedCCObjects > kCCPurpleLimit ||
(aSuspectedCCObjects > kCCForcedPurpleLimit && mLastCCEndTime &&
aNow - mLastCCEndTime > kCCForced);
}
inline bool ShouldScheduleCC(TimeStamp aNow) const;
inline bool ShouldScheduleCC(TimeStamp aNow,
uint32_t aSuspectedCCObjects) const;
// If we collected a substantial amount of cycles, poke the GC since more
// objects might be unreachable now.
@ -394,7 +385,8 @@ class CCGCScheduler {
inline GCRunnerStep GetNextGCRunnerAction(TimeStamp aDeadline);
inline CCRunnerStep AdvanceCCRunner(TimeStamp aDeadline, TimeStamp aNow);
inline CCRunnerStep AdvanceCCRunner(TimeStamp aDeadline, TimeStamp aNow,
uint32_t aSuspectedCCObjects);
// aStartTimeStamp : when the ForgetSkippable timer fired. This may be some
// time ago, if an incremental GC needed to be finished.
@ -525,7 +517,8 @@ inline TimeDuration CCGCScheduler::ComputeInterSliceGCBudget(
return std::max(budget, maxSliceGCBudget.MultDouble(percentOfBlockedTime));
}
bool CCGCScheduler::ShouldScheduleCC(TimeStamp aNow) const {
bool CCGCScheduler::ShouldScheduleCC(TimeStamp aNow,
uint32_t aSuspectedCCObjects) const {
if (!mHasRunGC) {
return false;
}
@ -547,11 +540,11 @@ bool CCGCScheduler::ShouldScheduleCC(TimeStamp aNow) const {
}
}
return IsCCNeeded(aNow);
return IsCCNeeded(aNow, aSuspectedCCObjects);
}
CCRunnerStep CCGCScheduler::AdvanceCCRunner(TimeStamp aDeadline,
TimeStamp aNow) {
CCRunnerStep CCGCScheduler::AdvanceCCRunner(TimeStamp aDeadline, TimeStamp aNow,
uint32_t aSuspectedCCObjects) {
struct StateDescriptor {
// When in this state, should we first check to see if we still have
// enough reason to CC?
@ -625,7 +618,7 @@ CCRunnerStep CCGCScheduler::AdvanceCCRunner(TimeStamp aDeadline,
// For states that aren't just continuations of previous states, check
// whether a CC is still needed (after doing various things to reduce the
// purple buffer).
if (desc.mCanAbortCC && !IsCCNeeded(aNow)) {
if (desc.mCanAbortCC && !IsCCNeeded(aNow, aSuspectedCCObjects)) {
// If we don't pass the threshold for wanting to cycle collect, stop now
// (after possibly doing a final ForgetSkippable).
mCCRunnerState = CCRunnerState::Canceled;
@ -633,7 +626,8 @@ CCRunnerStep CCGCScheduler::AdvanceCCRunner(TimeStamp aDeadline,
// Preserve the previous code's idea of when to check whether a
// ForgetSkippable should be fired.
if (desc.mTryFinalForgetSkippable && ShouldForgetSkippable()) {
if (desc.mTryFinalForgetSkippable &&
ShouldForgetSkippable(aSuspectedCCObjects)) {
// The Canceled state will make us StopRunning after this action is
// performed (see conditional at top of function).
return {CCRunnerAction::ForgetSkippable, Yield, KeepChildless};
@ -653,7 +647,7 @@ CCRunnerStep CCGCScheduler::AdvanceCCRunner(TimeStamp aDeadline,
mCCRunnerState = CCRunnerState::CleanupChildless;
}
if (ShouldForgetSkippable()) {
if (ShouldForgetSkippable(aSuspectedCCObjects)) {
return {CCRunnerAction::ForgetSkippable, Yield, KeepChildless};
}

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

@ -101,11 +101,6 @@ static bool sShuttingDown;
static CCGCScheduler sScheduler;
// This definition must match the one in CCGCScheduler.cpp
uint32_t mozilla::CCGCScheduler::SuspectedCCObjects() {
return nsCycleCollector_suspectedCount();
}
struct CycleCollectorStats {
constexpr CycleCollectorStats() = default;
void Init();
@ -1103,8 +1098,8 @@ static void FireForgetSkippable(bool aRemoveChildless, TimeStamp aDeadline) {
nsCycleCollector_forgetSkippable(budget, aRemoveChildless,
earlyForgetSkippable);
TimeStamp now = TimeStamp::Now();
uint32_t removedPurples =
sScheduler.NoteForgetSkippableComplete(now, suspectedBefore);
uint32_t removedPurples = sScheduler.NoteForgetSkippableComplete(
now, suspectedBefore, nsCycleCollector_suspectedCount());
TimeDuration duration = now - startTimeStamp;
@ -1522,7 +1517,8 @@ bool CCGCScheduler::CCRunnerFired(TimeStamp aDeadline) {
// `Yield` in step.mYield.
CCRunnerStep step;
do {
step = sScheduler.AdvanceCCRunner(aDeadline, TimeStamp::Now());
step = sScheduler.AdvanceCCRunner(aDeadline, TimeStamp::Now(),
nsCycleCollector_suspectedCount());
switch (step.mAction) {
case CCRunnerAction::None:
break;
@ -1669,7 +1665,9 @@ void nsJSContext::LowMemoryGC() {
}
// static
void nsJSContext::MaybePokeCC() { sScheduler.MaybePokeCC(TimeStamp::Now()); }
void nsJSContext::MaybePokeCC() {
sScheduler.MaybePokeCC(TimeStamp::Now(), nsCycleCollector_suspectedCount());
}
static void DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress,
const JS::GCDescription& aDesc) {
@ -1716,7 +1714,7 @@ static void DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress,
sScheduler.KillGCRunner();
TimeStamp now = TimeStamp::Now();
sScheduler.MaybePokeCC(now);
sScheduler.MaybePokeCC(now, nsCycleCollector_suspectedCount());
if (aDesc.isZone_) {
sScheduler.PokeFullGC();
@ -1725,7 +1723,7 @@ static void DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress,
sScheduler.KillFullGCTimer();
}
if (sScheduler.IsCCNeeded(now)) {
if (sScheduler.IsCCNeeded(now, nsCycleCollector_suspectedCount())) {
nsCycleCollector_dispatchDeferredDeletion();
}
@ -1750,7 +1748,8 @@ static void DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress,
sScheduler.EnsureGCRunner(0);
}
if (sScheduler.IsCCNeeded(TimeStamp::Now())) {
if (sScheduler.IsCCNeeded(TimeStamp::Now(),
nsCycleCollector_suspectedCount())) {
nsCycleCollector_dispatchDeferredDeletion();
}

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

@ -28,9 +28,7 @@ static TimeStamp Now() { return sNow; }
static uint32_t sSuspected = 0;
inline uint32_t mozilla::CCGCScheduler::SuspectedCCObjects() {
return sSuspected;
}
static uint32_t SuspectedCCObjects() { return sSuspected; }
static void SetNumSuspected(uint32_t n) { sSuspected = n; }
static void SuspectMore(uint32_t n) { sSuspected += n; }
@ -54,7 +52,7 @@ void TestGC::Run(int aNumSlices) {
// Running the GC should not influence whether a CC is currently seen as
// needed. But the first time we run GC, it will be false; later, we will
// have run a GC and set it to true.
bool neededCCAtStartOfGC = mScheduler.IsCCNeeded(Now());
bool neededCCAtStartOfGC = mScheduler.IsCCNeeded(Now(), SuspectedCCObjects());
mScheduler.NoteGCBegin();
@ -67,7 +65,8 @@ void TestGC::Run(int aNumSlices) {
// Pretend the GC took exactly the budget.
AdvanceTime(budget);
EXPECT_EQ(mScheduler.IsCCNeeded(Now()), neededCCAtStartOfGC);
EXPECT_EQ(mScheduler.IsCCNeeded(Now(), SuspectedCCObjects()),
neededCCAtStartOfGC);
// Mutator runs for 1 second.
AdvanceTime(kOneSecond);
@ -105,7 +104,7 @@ class TestCC {
void TestCC::MaybePokeCC() {
// nsJSContext::MaybePokeCC
EXPECT_TRUE(mScheduler.ShouldScheduleCC(Now()));
EXPECT_TRUE(mScheduler.ShouldScheduleCC(Now(), SuspectedCCObjects()));
mScheduler.InitCCRunnerStateMachine(CCRunnerState::ReducePurple);
EXPECT_TRUE(mScheduler.IsEarlyForgetSkippable());
@ -118,7 +117,8 @@ void TestCC::TimerFires(int aNumSlices) {
while (true) {
SuspectMore(1000);
TimeStamp idleDeadline = Now() + kOneSecond;
step = mScheduler.AdvanceCCRunner(idleDeadline, Now());
step =
mScheduler.AdvanceCCRunner(idleDeadline, Now(), SuspectedCCObjects());
// Should first see a series of ForgetSkippable actions.
if (step.mAction != CCRunnerAction::ForgetSkippable ||
step.mRemoveChildless != KeepChildless) {
@ -130,16 +130,17 @@ void TestCC::TimerFires(int aNumSlices) {
while (step.mYield == Continue) {
TimeStamp idleDeadline = Now() + kOneSecond;
step = mScheduler.AdvanceCCRunner(idleDeadline, Now());
step =
mScheduler.AdvanceCCRunner(idleDeadline, Now(), SuspectedCCObjects());
}
EXPECT_EQ(step.mAction, CCRunnerAction::ForgetSkippable);
EXPECT_EQ(step.mRemoveChildless, RemoveChildless);
ForgetSkippable();
TimeStamp idleDeadline = Now() + kOneSecond;
step = mScheduler.AdvanceCCRunner(idleDeadline, Now());
step = mScheduler.AdvanceCCRunner(idleDeadline, Now(), SuspectedCCObjects());
EXPECT_EQ(step.mAction, CCRunnerAction::CleanupContentUnbinder);
step = mScheduler.AdvanceCCRunner(idleDeadline, Now());
step = mScheduler.AdvanceCCRunner(idleDeadline, Now(), SuspectedCCObjects());
EXPECT_EQ(step.mAction, CCRunnerAction::CleanupDeferred);
RunSlices(aNumSlices);
@ -152,7 +153,8 @@ void TestCC::ForgetSkippable() {
mScheduler.ComputeForgetSkippableBudget(Now(), Now() + kTenthSecond);
EXPECT_NEAR(budget.timeBudget(), kTenthSecond.ToMilliseconds(), 1);
AdvanceTime(kTenthSecond);
mScheduler.NoteForgetSkippableComplete(Now(), suspectedBefore);
mScheduler.NoteForgetSkippableComplete(Now(), suspectedBefore,
SuspectedCCObjects());
}
void TestCC::RunSlices(int aNumSlices) {
@ -201,7 +203,7 @@ void TestIdleCC::RunSlice(TimeStamp aCCStartTime, TimeStamp aPrevSliceEnd,
TimeStamp idleDeadline = Now() + kTenthSecond;
// The scheduler should request a CycleCollect slice.
step = mScheduler.AdvanceCCRunner(idleDeadline, Now());
step = mScheduler.AdvanceCCRunner(idleDeadline, Now(), SuspectedCCObjects());
EXPECT_EQ(step.mAction, CCRunnerAction::CycleCollect);
// nsJSContext::RunCycleCollectorSlice
@ -239,7 +241,7 @@ void TestNonIdleCC::RunSlice(TimeStamp aCCStartTime, TimeStamp aPrevSliceEnd,
TimeStamp nullDeadline;
// The scheduler should tell us to run a slice of cycle collection.
step = mScheduler.AdvanceCCRunner(nullDeadline, Now());
step = mScheduler.AdvanceCCRunner(nullDeadline, Now(), SuspectedCCObjects());
EXPECT_EQ(step.mAction, CCRunnerAction::CycleCollect);
// nsJSContext::RunCycleCollectorSlice
@ -292,25 +294,25 @@ static bool BasicScenario(CCGCScheduler& aScheduler, TestGC* aTestGC,
// After a GC, the scheduler should decide to do a full CC regardless of the
// number of purple buffer entries.
SetNumSuspected(3);
EXPECT_TRUE(aScheduler.IsCCNeeded(Now()));
EXPECT_TRUE(aScheduler.IsCCNeeded(Now(), SuspectedCCObjects()));
// Now we should want to CC.
EXPECT_TRUE(aScheduler.ShouldScheduleCC(Now()));
EXPECT_TRUE(aScheduler.ShouldScheduleCC(Now(), SuspectedCCObjects()));
// Do a 5-slice CC.
aTestCC->Run(5);
// Not enough suspected objects to deserve a CC.
EXPECT_FALSE(aScheduler.IsCCNeeded(Now()));
EXPECT_FALSE(aScheduler.ShouldScheduleCC(Now()));
EXPECT_FALSE(aScheduler.IsCCNeeded(Now(), SuspectedCCObjects()));
EXPECT_FALSE(aScheduler.ShouldScheduleCC(Now(), SuspectedCCObjects()));
SetNumSuspected(10000);
// We shouldn't want to CC again yet, it's too soon.
EXPECT_FALSE(aScheduler.ShouldScheduleCC(Now()));
EXPECT_FALSE(aScheduler.ShouldScheduleCC(Now(), SuspectedCCObjects()));
AdvanceTime(mozilla::kCCDelay);
// *Now* it's time for another CC.
EXPECT_TRUE(aScheduler.ShouldScheduleCC(Now()));
EXPECT_TRUE(aScheduler.ShouldScheduleCC(Now(), SuspectedCCObjects()));
// Run a 3-slice incremental GC.
EXPECT_TRUE(!aScheduler.InIncrementalGC());
@ -327,7 +329,7 @@ static TestNonIdleCC ccNonIdle(scheduler);
TEST(TestScheduler, Idle)
{
// Cannot CC until we GC once.
EXPECT_FALSE(scheduler.ShouldScheduleCC(Now()));
EXPECT_FALSE(scheduler.ShouldScheduleCC(Now(), SuspectedCCObjects()));
EXPECT_TRUE(BasicScenario(scheduler, &gc, &ccIdle));
}