author | Ryan VanderMeulen <ryanvm@gmail.com> |
Thu, 19 Dec 2013 16:57:55 -0500 | |
changeset 161288 | e9bab00a241eaa8fdba8de3a310cb53c12f1fd5d |
parent 161287 | 6296ca67d80b1357834ec2b0076efb8354267c2f |
child 161289 | 3c174bf854cef3a62462ae3d76b64d57741868c0 |
push id | 37876 |
push user | ryanvm@gmail.com |
push date | Thu, 19 Dec 2013 21:57:53 +0000 |
treeherder | mozilla-inbound@e9bab00a241e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 937960 |
milestone | 29.0a1 |
backs out | ccdc3d4f4571472ab95d65bd1f91c8b37bdad266 4dcc91e771e3dabdd7ff008251ce8de2f6f09c4a 0ae14946314ba1fd8c5cdde1fc0db1af285b744b 94d22ab0b17f1033726e7f7aee63c16de46dbb5e |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -116,25 +116,16 @@ static PRLogModuleInfo* gJSDiagnostics; #define NS_INTERSLICE_GC_BUDGET 40 // ms // The amount of time we wait between a request to CC (after GC ran) // and doing the actual CC. #define NS_CC_DELAY 6000 // ms #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 - -// Time budget for an incremental CC slice -static const int64_t kICCSliceBudget = 10; // ms - -// Maximum total duration for an ICC -static const uint32_t kMaxICCDuration = 2000; // 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 #define NS_CC_FORCED_PURPLE_LIMIT 10 // Don't allow an incremental GC to lock out the CC for too long. #define NS_MAX_CC_LOCKEDOUT_TIME (15 * PR_USEC_PER_SEC) // 15 seconds @@ -148,17 +139,16 @@ static const uint32_t kMaxICCDuration = #define NS_MAJOR_FORGET_SKIPPABLE_CALLS 2 // if you add statics here, add them to the list in StartupJSEnvironment static nsITimer *sGCTimer; static nsITimer *sShrinkGCBuffersTimer; static nsITimer *sCCTimer; -static nsITimer *sICCTimer; static nsITimer *sFullGCTimer; static nsITimer *sInterSliceGCTimer; static PRTime sLastCCEndTime; static bool sCCLockedOut; static PRTime sCCLockedOutTime; @@ -185,17 +175,16 @@ static uint32_t sMaxForgetSkippableTime static uint32_t sTotalForgetSkippableTime = 0; static uint32_t sRemovedPurples = 0; static uint32_t sForgetSkippableBeforeCC = 0; static uint32_t sPreviousSuspectedCount = 0; static uint32_t sCleanupsSinceLastGC = UINT32_MAX; static bool sNeedsFullCC = false; static bool sNeedsGCAfterCC = false; static nsJSContext *sContextList = nullptr; -static bool sIncrementalCC = false; static nsScriptNameSpaceManager *gNameSpaceManager; static nsIJSRuntimeService *sRuntimeService; static const char kJSRuntimeServiceContractID[] = "@mozilla.org/js/xpc/RuntimeService;1"; @@ -228,17 +217,16 @@ GetCollectionTimeDelta() } static void KillTimers() { nsJSContext::KillGCTimer(); nsJSContext::KillShrinkGCBuffersTimer(); nsJSContext::KillCCTimer(); - nsJSContext::KillICCTimer(); nsJSContext::KillFullGCTimer(); nsJSContext::KillInterSliceGCTimer(); } class nsJSEnvironmentObserver MOZ_FINAL : public nsIObserver { public: NS_DECL_ISUPPORTS @@ -2020,32 +2008,16 @@ struct CycleCollectorStats uint32_t mMaxSkippableDuration; // True if we were locked out by the GC in any slice of the current CC. bool mAnyLockedOut; }; CycleCollectorStats gCCStats; -static int64_t -ICCSliceTime() -{ - // If CC is not incremental, use an unlimited budget. - if (!sIncrementalCC) { - return -1; - } - - // If an ICC is in progress and is taking too long, finish it off. - if (gCCStats.mBeginTime != 0 && - TimeBetween(gCCStats.mBeginTime, PR_Now()) >= kMaxICCDuration) { - return -1; - } - - return kICCSliceBudget; -} static void PrepareForCycleCollection(int32_t aExtraForgetSkippableCalls = 0) { gCCStats.mBeginSliceTime = PR_Now(); // Before we begin the cycle collection, make sure there is no active GC. PRTime endGCTime; @@ -2093,88 +2065,45 @@ nsJSContext::CycleCollectNow(nsICycleCol PROFILER_LABEL("CC", "CycleCollectNow"); PrepareForCycleCollection(aExtraForgetSkippableCalls); nsCycleCollector_collect(aListener); } //static void -nsJSContext::ScheduledCycleCollectNow(int64_t aSliceTime) +nsJSContext::ScheduledCycleCollectNow() { if (!NS_IsMainThread()) { return; } PROFILER_LABEL("CC", "ScheduledCycleCollectNow"); - - // Ideally, the slice time would be decreased by the amount of - // time spent on PrepareForCycleCollection(). PrepareForCycleCollection(); - nsCycleCollector_scheduledCollect(aSliceTime); -} - -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(ICCSliceTime()); + nsCycleCollector_scheduledCollect(); } //static void nsJSContext::BeginCycleCollectionCallback() { MOZ_ASSERT(NS_IsMainThread()); gCCStats.mBeginTime = gCCStats.mBeginSliceTime ? gCCStats.mBeginSliceTime : PR_Now(); 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 void 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 // might be unreachable now. if (sCCollectedWaitingForGC > 250 || sLikelyShortLivingObjectsNeedingGC > 2500 || sNeedsGCAfterCC) { PokeGC(JS::gcreason::CC_WAITING); @@ -2332,37 +2261,26 @@ static bool ShouldTriggerCC(uint32_t aSuspected) { return sNeedsFullCC || aSuspected > NS_CC_PURPLE_LIMIT || (aSuspected > NS_CC_FORCED_PURPLE_LIMIT && sLastCCEndTime + NS_CC_FORCED < PR_Now()); } -static uint32_t -TimeToNextCC() -{ - if (sIncrementalCC) { - return NS_CC_DELAY - kMaxICCDuration; - } - return NS_CC_DELAY; -} - -static_assert(NS_CC_DELAY > kMaxICCDuration, "ICC shouldn't reduce CC delay to 0"); - static void CCTimerFired(nsITimer *aTimer, void *aClosure) { if (sDidShutdown) { return; } static uint32_t ccDelay = NS_CC_DELAY; if (sCCLockedOut) { - ccDelay = TimeToNextCC() / 3; + ccDelay = NS_CC_DELAY / 3; PRTime now = PR_Now(); if (sCCLockedOutTime == 0) { // Reset sCCTimerFireCount so that we run forgetSkippable // often enough before CC. Because of reduced ccDelay // forgetSkippable will be called just a few times. // NS_MAX_CC_LOCKEDOUT_TIME limit guarantees that we end up calling // forgetSkippable and CycleCollectNow eventually. @@ -2374,41 +2292,41 @@ CCTimerFired(nsITimer *aTimer, void *aCl return; } } ++sCCTimerFireCount; // 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 begin to run the CC. - uint32_t numEarlyTimerFires = ccDelay / NS_CC_SKIPPABLE_DELAY - 2; + // late timer fire, where we may run the CC. + const uint32_t numEarlyTimerFires = ccDelay / NS_CC_SKIPPABLE_DELAY - 2; bool isLateTimerFire = sCCTimerFireCount > numEarlyTimerFires; uint32_t suspected = nsCycleCollector_suspectedCount(); if (isLateTimerFire && ShouldTriggerCC(suspected)) { if (sCCTimerFireCount == numEarlyTimerFires + 1) { FireForgetSkippable(suspected, true); if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) { // Our efforts to avoid a CC have failed, so we return to let the // timer fire once more to trigger a CC. return; } } else { // We are in the final timer fire and still meet the conditions for // triggering a CC. Let CycleCollectNow finish the current IGC, if any, // because that will allow us to include the GC time in the CC pause. - nsJSContext::ScheduledCycleCollectNow(ICCSliceTime()); + nsJSContext::ScheduledCycleCollectNow(); } } else if ((sPreviousSuspectedCount + 100) <= suspected) { // Only do a forget skippable if there are more than a few new objects. FireForgetSkippable(suspected, false); } if (isLateTimerFire) { - ccDelay = TimeToNextCC(); + ccDelay = NS_CC_DELAY; // We have either just run the CC or decided we don't want to run the CC // next time, so kill the timer. sPreviousSuspectedCount = 0; nsJSContext::KillCCTimer(); } } @@ -2502,17 +2420,17 @@ nsJSContext::PokeShrinkGCBuffers() NS_SHRINK_GC_BUFFERS_DELAY, nsITimer::TYPE_ONE_SHOT); } // static void nsJSContext::MaybePokeCC() { - if (sCCTimer || sICCTimer || sShuttingDown || !sHasRunGC) { + if (sCCTimer || sShuttingDown || !sHasRunGC) { return; } if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) { sCCTimerFireCount = 0; CallCreateInstance("@mozilla.org/timer;1", &sCCTimer); if (!sCCTimer) { return; @@ -2574,29 +2492,16 @@ nsJSContext::KillCCTimer() if (sCCTimer) { sCCTimer->Cancel(); NS_RELEASE(sCCTimer); } } -//static -void -nsJSContext::KillICCTimer() -{ - sCCLockedOutTime = 0; - - if (sICCTimer) { - sICCTimer->Cancel(); - - NS_RELEASE(sICCTimer); - } -} - void nsJSContext::GC(JS::gcreason::Reason aReason) { PokeGC(aReason); } class NotifyGCEndRunnable : public nsRunnable { @@ -2748,17 +2653,17 @@ nsJSContext::LikelyShortLivingObjectCrea { ++sLikelyShortLivingObjectsNeedingGC; } void mozilla::dom::StartupJSEnvironment() { // initialize all our statics, so that we can restart XPCOM - sGCTimer = sFullGCTimer = sCCTimer = sICCTimer = nullptr; + sGCTimer = sFullGCTimer = sCCTimer = nullptr; sCCLockedOut = false; sCCLockedOutTime = 0; sLastCCEndTime = 0; sHasRunGC = false; sPendingLoadCount = 0; sLoadingInProgress = false; sCCollectedWaitingForGC = 0; sLikelyShortLivingObjectsNeedingGC = 0; @@ -2844,23 +2749,16 @@ SetMemoryGCDynamicHeapGrowthPrefChangedC static void SetMemoryGCDynamicMarkSlicePrefChangedCallback(const char* aPrefName, void* aClosure) { bool pref = Preferences::GetBool(aPrefName); JS_SetGCParameter(sRuntime, JSGC_DYNAMIC_MARK_SLICE, pref); } -static void -SetIncrementalCCPrefChangedCallback(const char* aPrefName, void* aClosure) -{ - bool pref = Preferences::GetBool(aPrefName); - sIncrementalCC = pref; -} - JSObject* NS_DOMReadStructuredClone(JSContext* cx, JSStructuredCloneReader* reader, uint32_t tag, uint32_t data, void* closure) { if (tag == SCTAG_DOM_IMAGEDATA) { @@ -3057,19 +2955,16 @@ nsJSContext::EnsureStatics() Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback, "javascript.options.mem.gc_allocation_threshold_mb", (void *)JSGC_ALLOCATION_THRESHOLD); Preferences::RegisterCallbackAndCall(SetMemoryGCPrefChangedCallback, "javascript.options.mem.gc_decommit_threshold_mb", (void *)JSGC_DECOMMIT_THRESHOLD); - Preferences::RegisterCallbackAndCall(SetIncrementalCCPrefChangedCallback, - "dom.cycle_collector.incremental"); - nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); if (!obs) { MOZ_CRASH(); } Preferences::AddBoolVarCache(&sGCOnMemoryPressure, "javascript.options.gc_on_memory_pressure", true);
--- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -96,39 +96,32 @@ public: void EnsureStatics(); static void GarbageCollectNow(JS::gcreason::Reason reason, IsIncremental aIncremental = NonIncrementalGC, IsCompartment aCompartment = NonCompartmentGC, IsShrinking aShrinking = NonShrinkingGC, int64_t aSliceMillis = 0); static void ShrinkGCBuffersNow(); - // If aExtraForgetSkippableCalls is -1, forgetSkippable won't be // called even if the previous collection was GC. static void CycleCollectNow(nsICycleCollectorListener *aListener = nullptr, int32_t aExtraForgetSkippableCalls = 0); - - // If aSliceTime is negative, the CC will run to completion. If aSliceTime - // is 0, only a minimum quantum of work will be done. Otherwise, aSliceTime - // will be used as the time budget for the slice, in ms. - static void ScheduledCycleCollectNow(int64_t aSliceTime); - + static void ScheduledCycleCollectNow(); static void BeginCycleCollectionCallback(); static void EndCycleCollectionCallback(mozilla::CycleCollectorResults &aResults); static void PokeGC(JS::gcreason::Reason aReason, int aDelay = 0); static void KillGCTimer(); static void PokeShrinkGCBuffers(); static void KillShrinkGCBuffersTimer(); static void MaybePokeCC(); static void KillCCTimer(); - static void KillICCTimer(); static void KillFullGCTimer(); static void KillInterSliceGCTimer(); // Calling LikelyShortLivingObjectCreated() makes a GC more likely. static void LikelyShortLivingObjectCreated(); virtual void GC(JS::gcreason::Reason aReason) MOZ_OVERRIDE;
--- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -708,18 +708,16 @@ pref("dom.forms.number", true); pref("dom.forms.color", true); // Enables system messages and activities pref("dom.sysmsg.enabled", false); // Enable pre-installed applications. pref("dom.webapps.useCurrentProfile", false); -pref("dom.cycle_collector.incremental", false); - // Parsing perf prefs. For now just mimic what the old code did. #ifndef XP_WIN pref("content.sink.pending_event_mode", 0); #endif // Disable popups from plugins by default // 0 = openAllowed // 1 = openControlled
--- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -3051,18 +3051,17 @@ nsCycleCollector::Collect(ccType aCCType return collectedAny; } // Any JS objects we have in the graph could die when we GC, but we // don't want to abandon the current CC, because the graph contains // information about purple roots. So we synchronously finish off // the current CC. -void -nsCycleCollector::PrepareForGarbageCollection() +void nsCycleCollector::PrepareForGarbageCollection() { if (mIncrementalPhase == IdlePhase) { MOZ_ASSERT(mGraph.IsEmpty(), "Non-empty graph when idle"); MOZ_ASSERT(!mBuilder, "Non-null builder when idle"); return; } SliceBudget unlimitedBudget; @@ -3547,32 +3546,27 @@ nsCycleCollector_collect(nsICycleCollect MOZ_ASSERT(data->mCollector); PROFILER_LABEL("CC", "nsCycleCollector_collect"); SliceBudget unlimitedBudget; data->mCollector->Collect(ManualCC, unlimitedBudget, aManualListener); } void -nsCycleCollector_scheduledCollect(int64_t aSliceTime) +nsCycleCollector_scheduledCollect() { CollectorData *data = sCollectorData.get(); // We should have started the cycle collector by now. MOZ_ASSERT(data); MOZ_ASSERT(data->mCollector); PROFILER_LABEL("CC", "nsCycleCollector_scheduledCollect"); - SliceBudget budget; - if (aSliceTime > 0) { - budget = SliceBudget::TimeBudget(aSliceTime); - } else if (aSliceTime == 0) { - budget = SliceBudget::WorkBudget(1); - } - data->mCollector->Collect(ScheduledCC, budget, nullptr); + SliceBudget unlimitedBudget; + data->mCollector->Collect(ScheduledCC, unlimitedBudget, nullptr); } void nsCycleCollector_prepareForGarbageCollection() { CollectorData *data = sCollectorData.get(); MOZ_ASSERT(data);
--- a/xpcom/base/nsCycleCollector.h +++ b/xpcom/base/nsCycleCollector.h @@ -36,21 +36,17 @@ void nsCycleCollector_forgetSkippable(bo bool aAsyncSnowWhiteFreeing = false); void nsCycleCollector_prepareForGarbageCollection(); void nsCycleCollector_dispatchDeferredDeletion(bool aContinuation = false); bool nsCycleCollector_doDeferredDeletion(); void nsCycleCollector_collect(nsICycleCollectorListener *aManualListener); - -// If aSliceTime is negative, the CC will run to completion. If aSliceTime -// is 0, only a minimum quantum of work will be done. Otherwise, aSliceTime -// will be used as the time budget for the slice, in ms. -void nsCycleCollector_scheduledCollect(int64_t aSliceTime); +void nsCycleCollector_scheduledCollect(); uint32_t nsCycleCollector_suspectedCount(); void nsCycleCollector_shutdown(); // Helpers for interacting with JS void nsCycleCollector_registerJSRuntime(mozilla::CycleCollectedJSRuntime *aRt); void nsCycleCollector_forgetJSRuntime();