Bug 730853 - Make sure we occasionally CC with lots of incremental GCs (r=smaug,mccr8)

This commit is contained in:
Bill McCloskey 2012-03-08 15:37:13 -08:00
Родитель f92027bc93
Коммит 33fc80f486
1 изменённых файлов: 37 добавлений и 28 удалений

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

@ -147,6 +147,9 @@ static PRLogModuleInfo* gJSDiagnostics;
// Force a CC after this long if there's anything in the purple buffer.
#define NS_CC_FORCED (2 * 60 * PR_USEC_PER_SEC) // 2 min
// Don't allow an incremental GC to lock out the CC for too long.
#define NS_MAX_CC_LOCKEDOUT_TIME (5 * PR_USEC_PER_SEC) // 5 seconds
// Trigger a CC if the purple buffer exceeds this size when we check it.
#define NS_CC_PURPLE_LIMIT 250
@ -160,8 +163,8 @@ static nsITimer *sCCTimer;
static PRTime sLastCCEndTime;
static bool sGCHasRun;
static bool sCCLockedOut;
static PRTime sCCLockedOutTime;
static js::GCSliceCallback sPrevGCSliceCallback;
@ -3310,9 +3313,24 @@ TimerFireForgetSkippable(PRUint32 aSuspected, bool aRemoveChildless)
static void
CCTimerFired(nsITimer *aTimer, void *aClosure)
{
if (sDidShutdown || sCCLockedOut) {
if (sDidShutdown) {
return;
}
if (sCCLockedOut) {
PRTime now = PR_Now();
if (sCCLockedOutTime == 0) {
sCCLockedOutTime = now;
return;
}
if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) {
return;
}
// Finish the current incremental GC
nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal);
}
++sCCTimerFireCount;
// During early timer fires, we only run forgetSkippable. During the first
@ -3478,6 +3496,8 @@ nsJSContext::KillShrinkGCBuffersTimer()
void
nsJSContext::KillCCTimer()
{
sCCLockedOutTime = 0;
if (sCCTimer) {
sCCTimer->Cancel();
@ -3516,9 +3536,10 @@ DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescrip
}
}
// Prevent cycle collections during incremental GC.
// Prevent cycle collections and shrinking during incremental GC.
if (aProgress == js::GC_CYCLE_BEGIN) {
sCCLockedOut = true;
nsJSContext::KillShrinkGCBuffersTimer();
} else if (aProgress == js::GC_CYCLE_END) {
sCCLockedOut = false;
}
@ -3526,43 +3547,31 @@ DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescrip
// The GC has more work to do, so schedule another GC slice.
if (aProgress == js::GC_SLICE_END) {
nsJSContext::KillGCTimer();
nsJSContext::KillCCTimer();
nsJSContext::PokeGC(js::gcreason::INTER_SLICE_GC, NS_INTERSLICE_GC_DELAY);
}
if (aProgress == js::GC_CYCLE_END) {
// May need to kill the inter-slice GC timer
nsJSContext::KillGCTimer();
sCCollectedWaitingForGC = 0;
sCleanupSinceLastGC = false;
if (sGCTimer) {
// If we were waiting for a GC to happen, kill the timer.
nsJSContext::KillGCTimer();
if (aDesc.isCompartment) {
// If this is a compartment GC, restart it. We still want
// a full GC to happen. Compartment GCs usually happen as a
// result of last-ditch or MaybeGC. In both cases its
// result of last-ditch or MaybeGC. In both cases it is
// probably a time of heavy activity and we want to delay
// the full GC, but we do want it to happen eventually.
if (aDesc.isCompartment) {
nsJSContext::PokeGC(js::gcreason::POST_COMPARTMENT);
// We poked the GC, so we can kill any pending CC here.
nsJSContext::KillCCTimer();
}
} else {
// If this was a full GC, poke the CC to run soon.
if (!aDesc.isCompartment) {
sGCHasRun = true;
sNeedsFullCC = true;
nsJSContext::MaybePokeCC();
}
nsJSContext::PokeGC(js::gcreason::POST_COMPARTMENT);
}
// If we didn't end up scheduling a GC, make sure that we release GC buffers
// soon after canceling previous shrinking attempt.
nsJSContext::KillShrinkGCBuffersTimer();
if (!sGCTimer) {
sNeedsFullCC = true;
nsJSContext::MaybePokeCC();
if (!aDesc.isCompartment) {
// Avoid shrinking during heavy activity, which is suggested by
// compartment GC.
nsJSContext::PokeShrinkGCBuffers();
}
}
@ -3661,8 +3670,8 @@ nsJSRuntime::Startup()
{
// initialize all our statics, so that we can restart XPCOM
sGCTimer = sCCTimer = nsnull;
sGCHasRun = false;
sCCLockedOut = false;
sCCLockedOutTime = 0;
sLastCCEndTime = 0;
sPendingLoadCount = 0;
sLoadingInProgress = false;