Bug 415025, try to improve CC scheduling, r=peterv, sr=jst

This commit is contained in:
Olli.Pettay@helsinki.fi 2008-02-25 09:47:25 -08:00
parent 82460f344e
commit 5bf8e82603
3 changed files with 106 additions and 21 deletions

View File

@ -160,6 +160,16 @@ static PRLogModuleInfo* gJSDiagnostics;
#define NS_PROBABILITY_MULTIPLIER 3
// Cycle collector should never run more often than this value
#define NS_MIN_CC_INTERVAL 10000 // ms
// If previous cycle collection collected more than this number of objects,
// the next collection will happen somewhat soon.
#define NS_COLLECTED_OBJECTS_LIMIT 5000
// CC will be called if GC has been called at least this number of times and
// there are at least NS_MIN_SUSPECT_CHANGES new suspected objects.
#define NS_MAX_GC_COUNT 5
#define NS_MIN_SUSPECT_CHANGES 10
// CC will be called if there are at least NS_MAX_SUSPECT_CHANGES new suspected
// objects.
#define NS_MAX_SUSPECT_CHANGES 100
// if you add statics here, add them to the list in nsJSRuntime::Startup
@ -167,7 +177,10 @@ static PRUint32 sDelayedCCollectCount;
static PRUint32 sCCollectCount;
static PRBool sUserIsActive;
static PRTime sPreviousCCTime;
static PRBool sPreviousCCDidCollect;
static PRUint32 sCollectedObjectsCounts;
static PRUint32 sGCCount;
static PRUint32 sCCSuspectChanges;
static PRUint32 sCCSuspectedCount;
static nsITimer *sGCTimer;
static PRBool sReadyForGC;
@ -839,6 +852,7 @@ MaybeGC(JSContext *cx)
|| cx->runtime->gcZeal > 0
#endif
) {
++sGCCount;
JS_GC(cx);
}
}
@ -3317,19 +3331,22 @@ nsJSContext::PreserveWrapper(nsIXPConnectWrappedNative *aWrapper)
void
nsJSContext::CC()
{
sPreviousCCTime = PR_Now();
sDelayedCCollectCount = 0;
++sCCollectCount;
#ifdef DEBUG_smaug
printf("Will run cycle collector (%i)\n", sCCollectCount);
printf("Will run cycle collector (%i), %lldms since previous.\n",
sCCollectCount, (PR_Now() - sPreviousCCTime) / PR_USEC_PER_MSEC);
#endif
sPreviousCCTime = PR_Now();
sDelayedCCollectCount = 0;
sGCCount = 0;
sCCSuspectChanges = 0;
// nsCycleCollector_collect() will run a ::JS_GC() indirectly, so
// we do not explicitly call ::JS_GC() here.
sPreviousCCDidCollect = nsCycleCollector_collect();
sCollectedObjectsCounts = nsCycleCollector_collect();
sCCSuspectedCount = nsCycleCollector_suspectedCount();
#ifdef DEBUG_smaug
printf("(1) %s\n", sPreviousCCDidCollect ?
"Cycle collector did collect nodes" :
"Cycle collector did not collect nodes");
printf("Collected %u objects, %u suspected objects\n",
sCollectedObjectsCounts, sCCSuspectedCount);
#endif
}
@ -3338,13 +3355,42 @@ PRBool
nsJSContext::MaybeCC(PRBool aHigherProbability)
{
++sDelayedCCollectCount;
// Don't check suspected count if CC will be called anyway.
if (sCCSuspectChanges <= NS_MIN_SUSPECT_CHANGES ||
sGCCount <= NS_MAX_GC_COUNT) {
#ifdef DEBUG_smaug
PRTime now = PR_Now();
#endif
PRUint32 suspected = nsCycleCollector_suspectedCount();
#ifdef DEBUG_smaug
printf("%u suspected objects (%lldms), sCCSuspectedCount %u\n",
suspected, (PR_Now() - now) / PR_USEC_PER_MSEC,
sCCSuspectedCount);
#endif
// Update only when suspected count has increased.
if (suspected > sCCSuspectedCount) {
sCCSuspectChanges += (suspected - sCCSuspectedCount);
sCCSuspectedCount = suspected;
}
}
#ifdef DEBUG_smaug
printf("sCCSuspectChanges %u, sGCCount %u\n",
sCCSuspectChanges, sGCCount);
#endif
// Increase the probability also if the previous call to cycle collector
// collected something.
if (aHigherProbability || sPreviousCCDidCollect) {
if (aHigherProbability ||
sCollectedObjectsCounts > NS_COLLECTED_OBJECTS_LIMIT) {
sDelayedCCollectCount *= NS_PROBABILITY_MULTIPLIER;
}
if (!sGCTimer && (sDelayedCCollectCount > NS_MAX_DELAYED_CCOLLECT)) {
if (!sGCTimer &&
(sDelayedCCollectCount > NS_MAX_DELAYED_CCOLLECT) &&
((sCCSuspectChanges > NS_MIN_SUSPECT_CHANGES &&
sGCCount > NS_MAX_GC_COUNT) ||
(sCCSuspectChanges > NS_MAX_SUSPECT_CHANGES))) {
if ((PR_Now() - sPreviousCCTime) >=
PRTime(NS_MIN_CC_INTERVAL * PR_USEC_PER_MSEC)) {
nsJSContext::CC();
@ -3559,7 +3605,10 @@ nsJSRuntime::Startup()
sCCollectCount = 0;
sUserIsActive = PR_FALSE;
sPreviousCCTime = 0;
sPreviousCCDidCollect = PR_FALSE;
sCollectedObjectsCounts = 0;
sGCCount = 0;
sCCSuspectChanges = 0;
sCCSuspectedCount = 0;
sGCTimer = nsnull;
sReadyForGC = PR_FALSE;
sLoadInProgressGCTimer = PR_FALSE;

View File

@ -763,6 +763,17 @@ struct nsPurpleBuffer
}
}
}
PRUint32 Count()
{
PRUint32 count = mBackingStore.Count();
for (PRUint32 i = 0; i < N_POINTERS; ++i) {
if (mCache[i]) {
++count;
}
}
return count;
}
};
static PR_CALLBACK PLDHashOperator
@ -867,6 +878,7 @@ struct nsCycleCollector
PRBool mCollectionInProgress;
PRBool mScanInProgress;
PRBool mFollowupCollection;
PRUint32 mCollectedObjects;
nsCycleCollectionLanguageRuntime *mRuntimes[nsIProgrammingLanguage::MAX+1];
nsCycleCollectionXPCOMRuntime mXPCOMRuntime;
@ -895,9 +907,10 @@ struct nsCycleCollector
PRBool Suspect(nsISupports *n);
PRBool Forget(nsISupports *n);
PRBool Collect(PRUint32 aTryCollections = 1);
PRUint32 Collect(PRUint32 aTryCollections = 1);
PRBool BeginCollection();
PRBool FinishCollection();
PRUint32 SuspectedCount();
void Shutdown();
void ClearGraph()
@ -1613,6 +1626,7 @@ nsCycleCollector::CollectWhite()
mStats.mFreedBytes += (ms1.lTotalCount - ms2.lTotalCount);
#endif
mCollectedObjects += count;
return count > 0;
}
@ -1818,6 +1832,7 @@ InitMemHook(void)
nsCycleCollector::nsCycleCollector() :
mCollectionInProgress(PR_FALSE),
mScanInProgress(PR_FALSE),
mCollectedObjects(0),
mWhiteNodes(nsnull),
mWhiteNodeCount(0),
#ifdef DEBUG_CC
@ -2138,7 +2153,7 @@ nsCycleCollector::Freed(void *n)
}
#endif
PRBool
PRUint32
nsCycleCollector::Collect(PRUint32 aTryCollections)
{
#if defined(DEBUG_CC) && !defined(__MINGW32__)
@ -2148,7 +2163,7 @@ nsCycleCollector::Collect(PRUint32 aTryCollections)
// This can legitimately happen in a few cases. See bug 383651.
if (mCollectionInProgress)
return PR_FALSE;
return 0;
#ifdef COLLECT_TIME_DEBUG
printf("cc: Starting nsCycleCollector::Collect(%d)\n", aTryCollections);
@ -2164,7 +2179,7 @@ nsCycleCollector::Collect(PRUint32 aTryCollections)
}
mFollowupCollection = PR_FALSE;
mCollectedObjects = 0;
nsAutoTPtrArray<PtrInfo, 4000> whiteNodes;
mWhiteNodes = &whiteNodes;
@ -2224,7 +2239,7 @@ nsCycleCollector::Collect(PRUint32 aTryCollections)
#ifdef DEBUG_CC
ExplainLiveExpectedGarbage();
#endif
return totalCollections > 0;
return mCollectedObjects;
}
PRBool
@ -2340,7 +2355,7 @@ nsCycleCollector::BeginCollection()
RootWhite();
#ifdef COLLECT_TIME_DEBUG
printf("cc: CollectWhite() took %lldms\n",
printf("cc: RootWhite() took %lldms\n",
(PR_Now() - now) / PR_USEC_PER_MSEC);
#endif
}
@ -2354,8 +2369,16 @@ nsCycleCollector::BeginCollection()
PRBool
nsCycleCollector::FinishCollection()
{
#ifdef COLLECT_TIME_DEBUG
PRTime now = PR_Now();
#endif
PRBool collected = CollectWhite();
#ifdef COLLECT_TIME_DEBUG
printf("cc: CollectWhite() took %lldms\n",
(PR_Now() - now) / PR_USEC_PER_MSEC);
#endif
#ifdef DEBUG_CC
mStats.mCollection++;
if (mParams.mReportStats)
@ -2372,6 +2395,12 @@ nsCycleCollector::FinishCollection()
return collected;
}
PRUint32
nsCycleCollector::SuspectedCount()
{
return mPurpleBuf.Count();
}
void
nsCycleCollector::Shutdown()
{
@ -2780,10 +2809,16 @@ NS_CycleCollectorForget(nsISupports *n)
}
PRBool
PRUint32
nsCycleCollector_collect()
{
return sCollector ? sCollector->Collect() : PR_FALSE;
return sCollector ? sCollector->Collect() : 0;
}
PRUint32
nsCycleCollector_suspectedCount()
{
return sCollector ? sCollector->SuspectedCount() : 0;
}
PRBool

View File

@ -60,8 +60,9 @@ struct nsCycleCollectionLanguageRuntime
};
nsresult nsCycleCollector_startup();
// Returns PR_TRUE if some nodes were collected.
NS_COM PRBool nsCycleCollector_collect();
// Returns the number of collected nodes.
NS_COM PRUint32 nsCycleCollector_collect();
NS_COM PRUint32 nsCycleCollector_suspectedCount();
void nsCycleCollector_shutdown();
// The JS runtime is special, it needs to call cycle collection during its GC.