Bug 728460, part 2: remove childless nodes in slice before CC. r=smaug

This commit is contained in:
Andrew McCreight 2012-03-05 13:48:33 -08:00
parent 1a7388ab3b
commit 7c84ed2c56

View File

@ -144,7 +144,11 @@ static PRLogModuleInfo* gJSDiagnostics;
#define NS_CC_SKIPPABLE_DELAY 400 // ms
#define NS_CC_FORCED (5 * 60 * PR_USEC_PER_SEC) // 5 min
// 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
// Trigger a CC if the purple buffer exceeds this size when we check it.
#define NS_CC_PURPLE_LIMIT 250
#define JAVASCRIPT nsIProgrammingLanguage::JAVASCRIPT
@ -3286,46 +3290,70 @@ ShrinkGCBuffersTimerFired(nsITimer *aTimer, void *aClosure)
nsJSContext::ShrinkGCBuffersNow();
}
// static
void
static bool
ShouldTriggerCC(PRUint32 aSuspected)
{
return sNeedsFullCC ||
aSuspected > NS_CC_PURPLE_LIMIT ||
sLastCCEndTime + NS_CC_FORCED < PR_Now();
}
static void
TimerFireForgetSkippable(PRUint32 aSuspected, bool aRemoveChildless)
{
PRTime startTime = PR_Now();
nsCycleCollector_forgetSkippable(aRemoveChildless);
sPreviousSuspectedCount = nsCycleCollector_suspectedCount();
sCleanupSinceLastGC = true;
PRTime delta = PR_Now() - startTime;
if (sMinForgetSkippableTime > delta) {
sMinForgetSkippableTime = delta;
}
if (sMaxForgetSkippableTime < delta) {
sMaxForgetSkippableTime = delta;
}
sTotalForgetSkippableTime += delta;
sRemovedPurples += (aSuspected - sPreviousSuspectedCount);
++sForgetSkippableBeforeCC;
}
static void
CCTimerFired(nsITimer *aTimer, void *aClosure)
{
if (sDidShutdown) {
return;
}
if (sCCLockedOut) {
if (sDidShutdown || sCCLockedOut) {
return;
}
++sCCTimerFireCount;
if (sCCTimerFireCount < (NS_CC_DELAY / NS_CC_SKIPPABLE_DELAY)) {
PRUint32 suspected = nsCycleCollector_suspectedCount();
if ((sPreviousSuspectedCount + 100) > suspected) {
// Just few new suspected objects, return early.
return;
}
PRTime startTime = PR_Now();
nsCycleCollector_forgetSkippable();
sPreviousSuspectedCount = nsCycleCollector_suspectedCount();
sCleanupSinceLastGC = true;
PRTime delta = PR_Now() - startTime;
if (sMinForgetSkippableTime > delta) {
sMinForgetSkippableTime = delta;
}
if (sMaxForgetSkippableTime < delta) {
sMaxForgetSkippableTime = delta;
}
sTotalForgetSkippableTime += delta;
sRemovedPurples += (suspected - sPreviousSuspectedCount);
++sForgetSkippableBeforeCC;
} else {
sPreviousSuspectedCount = 0;
nsJSContext::KillCCTimer();
if (sNeedsFullCC ||
nsCycleCollector_suspectedCount() > 500 ||
sLastCCEndTime + NS_CC_FORCED < PR_Now()) {
// 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.
const PRUint32 numEarlyTimerFires = NS_CC_DELAY / NS_CC_SKIPPABLE_DELAY - 2;
bool isLateTimerFire = sCCTimerFireCount > numEarlyTimerFires;
PRUint32 suspected = nsCycleCollector_suspectedCount();
if (isLateTimerFire && ShouldTriggerCC(suspected)) {
if (sCCTimerFireCount == numEarlyTimerFires + 1) {
TimerFireForgetSkippable(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.
nsJSContext::CycleCollectNow();
}
} else if ((sPreviousSuspectedCount + 100) <= suspected) {
// Only do a forget skippable if there are more than a few new objects.
TimerFireForgetSkippable(suspected, false);
}
if (isLateTimerFire) {
// 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();
}
}