From 40b5bfe7e9b27465ec4bdb335a7a250a691f25b9 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Wed, 18 Dec 2013 11:42:16 -0800 Subject: [PATCH] Bug 937960, part 2 - Add ICC slice timer and scheduling. r=smaug --- dom/base/nsJSEnvironment.cpp | 64 ++++++++++++++++++++++++++++++++++-- dom/base/nsJSEnvironment.h | 1 + 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 6ca3f1bd5c5e..28a687e96cd6 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -121,6 +121,9 @@ static PRLogModuleInfo* gJSDiagnostics; #define NS_CC_SKIPPABLE_DELAY 400 // ms +// Maximum amount of time that should elapse between incremental CC slices +static const int64_t kICCIntersliceDelay = 32; // ms + // Force a CC after this long if there's more than NS_CC_FORCED_PURPLE_LIMIT // objects in the purple buffer. #define NS_CC_FORCED (2 * 60 * PR_USEC_PER_SEC) // 2 min @@ -144,6 +147,7 @@ static PRLogModuleInfo* gJSDiagnostics; static nsITimer *sGCTimer; static nsITimer *sShrinkGCBuffersTimer; static nsITimer *sCCTimer; +static nsITimer *sICCTimer; static nsITimer *sFullGCTimer; static nsITimer *sInterSliceGCTimer; @@ -223,6 +227,7 @@ KillTimers() nsJSContext::KillGCTimer(); nsJSContext::KillShrinkGCBuffersTimer(); nsJSContext::KillCCTimer(); + nsJSContext::KillICCTimer(); nsJSContext::KillFullGCTimer(); nsJSContext::KillInterSliceGCTimer(); } @@ -2082,6 +2087,30 @@ nsJSContext::ScheduledCycleCollectNow() nsCycleCollector_scheduledCollect(); } +static void +ICCTimerFired(nsITimer* aTimer, void* aClosure) +{ + if (sDidShutdown) { + return; + } + + // Ignore ICC timer fires during IGC. Running ICC during an IGC will cause us + // to synchronously finish the GC, which is bad. + + if (sCCLockedOut) { + PRTime now = PR_Now(); + if (sCCLockedOutTime == 0) { + sCCLockedOutTime = now; + return; + } + if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) { + return; + } + } + + nsJSContext::ScheduledCycleCollectNow(); +} + //static void nsJSContext::BeginCycleCollectionCallback() @@ -2092,6 +2121,20 @@ nsJSContext::BeginCycleCollectionCallback() gCCStats.mSuspected = nsCycleCollector_suspectedCount(); KillCCTimer(); + + MOZ_ASSERT(!sICCTimer, "Tried to create a new ICC timer when one already existed."); + + if (!sIncrementalCC) { + return; + } + + CallCreateInstance("@mozilla.org/timer;1", &sICCTimer); + if (sICCTimer) { + sICCTimer->InitWithFuncCallback(ICCTimerFired, + nullptr, + kICCIntersliceDelay, + nsITimer::TYPE_REPEATING_SLACK); + } } //static @@ -2100,6 +2143,8 @@ nsJSContext::EndCycleCollectionCallback(CycleCollectorResults &aResults) { MOZ_ASSERT(NS_IsMainThread()); + nsJSContext::KillICCTimer(); + sCCollectedWaitingForGC += aResults.mFreedRefCounted + aResults.mFreedGCed; // If we collected a substantial amount of cycles, poke the GC since more objects @@ -2298,7 +2343,7 @@ CCTimerFired(nsITimer *aTimer, void *aClosure) // During early timer fires, we only run forgetSkippable. During the first // late timer fire, we decide if we are going to have a second and final - // late timer fire, where we may run the CC. + // late timer fire, where we may begin to run the CC. const uint32_t numEarlyTimerFires = ccDelay / NS_CC_SKIPPABLE_DELAY - 2; bool isLateTimerFire = sCCTimerFireCount > numEarlyTimerFires; uint32_t suspected = nsCycleCollector_suspectedCount(); @@ -2426,7 +2471,7 @@ nsJSContext::PokeShrinkGCBuffers() void nsJSContext::MaybePokeCC() { - if (sCCTimer || sShuttingDown || !sHasRunGC) { + if (sCCTimer || sICCTimer || sShuttingDown || !sHasRunGC) { return; } @@ -2498,6 +2543,19 @@ nsJSContext::KillCCTimer() } } +//static +void +nsJSContext::KillICCTimer() +{ + sCCLockedOutTime = 0; + + if (sICCTimer) { + sICCTimer->Cancel(); + + NS_RELEASE(sICCTimer); + } +} + void nsJSContext::GC(JS::gcreason::Reason aReason) { @@ -2659,7 +2717,7 @@ void mozilla::dom::StartupJSEnvironment() { // initialize all our statics, so that we can restart XPCOM - sGCTimer = sFullGCTimer = sCCTimer = nullptr; + sGCTimer = sFullGCTimer = sCCTimer = sICCTimer = nullptr; sCCLockedOut = false; sCCLockedOutTime = 0; sLastCCEndTime = 0; diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index 002351c658ef..cbfbd1559f30 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -117,6 +117,7 @@ public: static void MaybePokeCC(); static void KillCCTimer(); + static void KillICCTimer(); static void KillFullGCTimer(); static void KillInterSliceGCTimer();