mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-13 03:24:26 +00:00
Bug 1929640 - Add a mode to CCGCScheduler where it can collect faster in case lots of garbage is created and there isn't too much idle time to run the slices, r=mccr8,sfink
Differential Revision: https://phabricator.services.mozilla.com/D228215
This commit is contained in:
parent
c931229d0e
commit
07a2abbaab
@ -241,6 +241,10 @@ void CCGCScheduler::NoteCCEnd(const CycleCollectorResults& aResults,
|
||||
mIsCollectingCycles = false;
|
||||
mLastCCEndTime = aWhen;
|
||||
mNeedsFullCC = CCReason::NO_REASON;
|
||||
mPreferFasterCollection =
|
||||
mCurrentCollectionHasSeenNonIdle &&
|
||||
(aResults.mFreedGCed > 10000 || aResults.mFreedRefCounted > 10000);
|
||||
mCurrentCollectionHasSeenNonIdle = false;
|
||||
}
|
||||
|
||||
void CCGCScheduler::NoteWontGC() {
|
||||
@ -255,6 +259,14 @@ void CCGCScheduler::NoteWontGC() {
|
||||
bool CCGCScheduler::GCRunnerFired(TimeStamp aDeadline) {
|
||||
MOZ_ASSERT(!mDidShutdown, "GCRunner still alive during shutdown");
|
||||
|
||||
if (!aDeadline) {
|
||||
mCurrentCollectionHasSeenNonIdle = true;
|
||||
} else if (mPreferFasterCollection) {
|
||||
// We found some idle time, try to utilize that a bit more given that
|
||||
// we're in a mode where idle time is rare.
|
||||
aDeadline = aDeadline + TimeDuration::FromMilliseconds(5.0);
|
||||
}
|
||||
|
||||
GCRunnerStep step = GetNextGCRunnerAction(aDeadline);
|
||||
switch (step.mAction) {
|
||||
case GCRunnerAction::None:
|
||||
@ -544,15 +556,24 @@ void CCGCScheduler::EnsureOrResetGCRunner() {
|
||||
StaticPrefs::javascript_options_gc_delay_interslice()));
|
||||
}
|
||||
|
||||
TimeDuration CCGCScheduler::ComputeMinimumBudgetForRunner(
|
||||
TimeDuration aBaseValue) {
|
||||
// If the main thread was too busy to find idle for the whole last collection,
|
||||
// allow a very short budget this time.
|
||||
return mPreferFasterCollection ? TimeDuration::FromMilliseconds(1.0)
|
||||
: TimeDuration::FromMilliseconds(std::max(
|
||||
nsRefreshDriver::HighRateMultiplier() *
|
||||
aBaseValue.ToMilliseconds(),
|
||||
1.0));
|
||||
}
|
||||
|
||||
void CCGCScheduler::EnsureGCRunner(TimeDuration aDelay) {
|
||||
if (mGCRunner) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimeDuration minimumBudget = TimeDuration::FromMilliseconds(
|
||||
std::max(nsRefreshDriver::HighRateMultiplier() *
|
||||
mActiveIntersliceGCBudget.ToMilliseconds(),
|
||||
1.0));
|
||||
TimeDuration minimumBudget =
|
||||
ComputeMinimumBudgetForRunner(mActiveIntersliceGCBudget);
|
||||
|
||||
// Wait at most the interslice GC delay before forcing a run.
|
||||
mGCRunner = IdleTaskRunner::Create(
|
||||
@ -615,13 +636,13 @@ void CCGCScheduler::KillGCRunner() {
|
||||
void CCGCScheduler::EnsureCCRunner(TimeDuration aDelay, TimeDuration aBudget) {
|
||||
MOZ_ASSERT(!mDidShutdown);
|
||||
|
||||
TimeDuration minimumBudget = TimeDuration::FromMilliseconds(std::max(
|
||||
nsRefreshDriver::HighRateMultiplier() * aBudget.ToMilliseconds(), 1.0));
|
||||
TimeDuration minimumBudget = ComputeMinimumBudgetForRunner(aBudget);
|
||||
|
||||
if (!mCCRunner) {
|
||||
mCCRunner = IdleTaskRunner::Create(
|
||||
CCRunnerFired, "EnsureCCRunner::CCRunnerFired", 0, aDelay,
|
||||
minimumBudget, true, [this] { return mDidShutdown; });
|
||||
[this](TimeStamp aDeadline) { return CCRunnerFired(aDeadline); },
|
||||
"EnsureCCRunner::CCRunnerFired", 0, aDelay, minimumBudget, true,
|
||||
[this] { return mDidShutdown; });
|
||||
} else {
|
||||
mCCRunner->SetMinimumUsefulBudget(minimumBudget.ToMilliseconds());
|
||||
nsIEventTarget* target = mozilla::GetCurrentSerialEventTarget();
|
||||
|
@ -132,7 +132,7 @@ class CCGCScheduler {
|
||||
mReadyForMajorGC(!mAskParentBeforeMajorGC),
|
||||
mInterruptRequested(false) {}
|
||||
|
||||
static bool CCRunnerFired(TimeStamp aDeadline);
|
||||
bool CCRunnerFired(TimeStamp aDeadline);
|
||||
|
||||
// Parameter setting
|
||||
|
||||
@ -178,7 +178,9 @@ class CCGCScheduler {
|
||||
JS::SliceBudget CreateGCSliceBudget(mozilla::TimeDuration aDuration,
|
||||
bool isIdle, bool isExtended) {
|
||||
mInterruptRequested = false;
|
||||
auto budget = JS::SliceBudget(aDuration, &mInterruptRequested);
|
||||
// Don't try to interrupt if we are in a mode where idle time is rare.
|
||||
auto budget = JS::SliceBudget(
|
||||
aDuration, mPreferFasterCollection ? nullptr : &mInterruptRequested);
|
||||
budget.idle = isIdle;
|
||||
budget.extended = isExtended;
|
||||
return budget;
|
||||
@ -350,6 +352,8 @@ class CCGCScheduler {
|
||||
JS::SliceBudget ComputeInterSliceGCBudget(TimeStamp aDeadline,
|
||||
TimeStamp aNow);
|
||||
|
||||
TimeDuration ComputeMinimumBudgetForRunner(TimeDuration aBaseValue);
|
||||
|
||||
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.
|
||||
@ -451,6 +455,8 @@ class CCGCScheduler {
|
||||
JS::SliceBudget ComputeForgetSkippableBudget(TimeStamp aStartTimeStamp,
|
||||
TimeStamp aDeadline);
|
||||
|
||||
bool PreferFasterCollection() const { return mPreferFasterCollection; }
|
||||
|
||||
private:
|
||||
// State
|
||||
|
||||
@ -523,6 +529,9 @@ class CCGCScheduler {
|
||||
bool mIsCollectingCycles = false;
|
||||
bool mUserIsActive = true;
|
||||
|
||||
bool mCurrentCollectionHasSeenNonIdle = false;
|
||||
bool mPreferFasterCollection = false;
|
||||
|
||||
public:
|
||||
uint32_t mCCollectedWaitingForGC = 0;
|
||||
uint32_t mCCollectedZonesWaitingForGC = 0;
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/CycleCollectorStats.h"
|
||||
#include "mozilla/MainThreadIdlePeriod.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/SchedulerGroup.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
@ -1246,7 +1247,7 @@ void nsJSContext::EndCycleCollectionCallback(
|
||||
"A max duration ICC shouldn't reduce GC delay to 0");
|
||||
|
||||
TimeDuration delay;
|
||||
if (aResults.mFreedGCed > 10000 && aResults.mFreedRefCounted > 10000) {
|
||||
if (sScheduler->PreferFasterCollection()) {
|
||||
// If we collected lots of objects, trigger the next GC sooner so that
|
||||
// GC can cut JS-to-native edges and native objects can be then deleted.
|
||||
delay = TimeDuration::FromMilliseconds(
|
||||
@ -1268,10 +1269,17 @@ void nsJSContext::EndCycleCollectionCallback(
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool CCGCScheduler::CCRunnerFired(TimeStamp aDeadline) {
|
||||
AUTO_PROFILER_LABEL_RELEVANT_FOR_JS("Incremental CC", GCCC);
|
||||
|
||||
if (!aDeadline) {
|
||||
mCurrentCollectionHasSeenNonIdle = true;
|
||||
} else if (mPreferFasterCollection) {
|
||||
// We found some idle time, try to utilize that a bit more given that
|
||||
// we're in a mode where idle time is rare.
|
||||
aDeadline = aDeadline + TimeDuration::FromMilliseconds(5.0);
|
||||
}
|
||||
|
||||
bool didDoWork = false;
|
||||
|
||||
// The CC/GC scheduler (sScheduler) decides what action(s) to take during
|
||||
|
Loading…
x
Reference in New Issue
Block a user