Bug 771720 - Improve GC data collection (r=terrence)

This commit is contained in:
Bill McCloskey 2012-07-08 10:24:32 -07:00
parent 560a0f014c
commit 76ac85af05
4 changed files with 85 additions and 65 deletions

View File

@ -276,20 +276,26 @@ static PhaseInfo phases[] = {
{ PHASE_WAIT_BACKGROUND_THREAD, "Wait Background Thread" },
{ PHASE_PURGE, "Purge" },
{ PHASE_MARK, "Mark" },
{ PHASE_MARK_DISCARD_CODE, "Mark Discard Code" },
{ PHASE_MARK_ROOTS, "Mark Roots" },
{ PHASE_MARK_TYPES, "Mark Types" },
{ PHASE_MARK_DELAYED, "Mark Delayed" },
{ PHASE_MARK_OTHER, "Mark Other" },
{ PHASE_MARK_WEAK, "Mark Weak" },
{ PHASE_MARK_GRAY, "Mark Gray" },
{ PHASE_MARK_GRAY_WEAK, "Mark Gray and Weak" },
{ PHASE_FINALIZE_START, "Finalize Start Callback" },
{ PHASE_SWEEP, "Sweep" },
{ PHASE_SWEEP_ATOMS, "Sweep Atoms" },
{ PHASE_SWEEP_COMPARTMENTS, "Sweep Compartments" },
{ PHASE_SWEEP_TABLES, "Sweep Tables" },
{ PHASE_SWEEP_OBJECT, "Sweep Object" },
{ PHASE_SWEEP_STRING, "Sweep String" },
{ PHASE_SWEEP_SCRIPT, "Sweep Script" },
{ PHASE_SWEEP_SHAPE, "Sweep Shape" },
{ PHASE_DISCARD_CODE, "Discard Code" },
{ PHASE_SWEEP_DISCARD_CODE, "Sweep Discard Code" },
{ PHASE_DISCARD_ANALYSIS, "Discard Analysis" },
{ PHASE_DISCARD_TI, "Discard TI" },
{ PHASE_FREE_TI_ARENA, "Free TI Arena" },
{ PHASE_SWEEP_TYPES, "Sweep Types" },
{ PHASE_CLEAR_SCRIPT_ANALYSIS, "Clear Script Analysis" },
{ PHASE_FINALIZE_END, "Finalize End Callback" },
@ -307,15 +313,6 @@ FormatPhaseTimes(StatisticsSerializer &ss, const char *name, int64_t *times)
ss.endObject();
}
static void
FormatPhaseFaults(StatisticsSerializer &ss, const char *name, size_t *faults)
{
ss.beginObject(name);
for (unsigned i = 0; phases[i].name; i++)
ss.appendNumber(phases[i].name, "%u", "", unsigned(faults[phases[i].index]));
ss.endObject();
}
bool
Statistics::formatData(StatisticsSerializer &ss, uint64_t timestamp)
{
@ -367,12 +364,14 @@ Statistics::formatData(StatisticsSerializer &ss, uint64_t timestamp)
ss.extra(" (");
ss.appendDecimal("When", "ms", t(slices[i].start - slices[0].start));
ss.appendString("Reason", ExplainReason(slices[i].reason));
if (ss.isJSON()) {
ss.appendDecimal("Page Faults", "",
double(slices[i].endFaults - slices[i].startFaults));
}
if (slices[i].resetReason)
ss.appendString("Reset", slices[i].resetReason);
ss.extra("): ");
FormatPhaseTimes(ss, "Times", slices[i].phaseTimes);
if (ss.isJSON())
FormatPhaseFaults(ss, "Page Faults", slices[i].phaseFaults);
ss.endLine();
ss.endObject();
}
@ -380,8 +379,6 @@ Statistics::formatData(StatisticsSerializer &ss, uint64_t timestamp)
}
ss.extra(" Totals: ");
FormatPhaseTimes(ss, "Totals", phaseTimes);
if (ss.isJSON())
FormatPhaseFaults(ss, "Total Page Faults", phaseFaults);
ss.endObject();
return !ss.isOOM();
@ -484,9 +481,7 @@ void
Statistics::beginGC()
{
PodArrayZero(phaseStartTimes);
PodArrayZero(phaseStartFaults);
PodArrayZero(phaseTimes);
PodArrayZero(phaseFaults);
slices.clearAndFree();
nonincrementalReason = NULL;
@ -531,7 +526,7 @@ Statistics::beginSlice(int collectedCount, int compartmentCount, gcreason::Reaso
if (first)
beginGC();
SliceData data(reason, PRMJ_Now());
SliceData data(reason, PRMJ_Now(), gc::GetPageFaultCount());
(void) slices.append(data); /* Ignore any OOMs here. */
if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback)
@ -549,6 +544,7 @@ void
Statistics::endSlice()
{
slices.back().end = PRMJ_Now();
slices.back().endFaults = gc::GetPageFaultCount();
if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) {
(*cb)(JS_TELEMETRY_GC_SLICE_MS, t(slices.back().end - slices.back().start));
@ -578,7 +574,6 @@ Statistics::beginPhase(Phase phase)
JS_ASSERT(!phaseStartTimes[phase]);
phaseStartTimes[phase] = PRMJ_Now();
phaseStartFaults[phase] = gc::GetPageFaultCount();
if (phase == gcstats::PHASE_MARK)
Probes::GCStartMarkPhase();
@ -594,10 +589,6 @@ Statistics::endPhase(Phase phase)
phaseTimes[phase] += t;
phaseStartTimes[phase] = 0;
size_t faults = gc::GetPageFaultCount() - phaseStartFaults[phase];
slices.back().phaseFaults[phase] += faults;
phaseFaults[phase] += faults;
if (phase == gcstats::PHASE_MARK)
Probes::GCEndMarkPhase();
else if (phase == gcstats::PHASE_SWEEP)

View File

@ -24,20 +24,26 @@ enum Phase {
PHASE_WAIT_BACKGROUND_THREAD,
PHASE_PURGE,
PHASE_MARK,
PHASE_MARK_DISCARD_CODE,
PHASE_MARK_ROOTS,
PHASE_MARK_TYPES,
PHASE_MARK_DELAYED,
PHASE_MARK_OTHER,
PHASE_MARK_WEAK,
PHASE_MARK_GRAY,
PHASE_MARK_GRAY_WEAK,
PHASE_FINALIZE_START,
PHASE_SWEEP,
PHASE_SWEEP_ATOMS,
PHASE_SWEEP_COMPARTMENTS,
PHASE_SWEEP_TABLES,
PHASE_SWEEP_OBJECT,
PHASE_SWEEP_STRING,
PHASE_SWEEP_SCRIPT,
PHASE_SWEEP_SHAPE,
PHASE_DISCARD_CODE,
PHASE_SWEEP_DISCARD_CODE,
PHASE_DISCARD_ANALYSIS,
PHASE_DISCARD_TI,
PHASE_FREE_TI_ARENA,
PHASE_SWEEP_TYPES,
PHASE_CLEAR_SCRIPT_ANALYSIS,
PHASE_FINALIZE_END,
@ -96,18 +102,17 @@ struct Statistics {
const char *nonincrementalReason;
struct SliceData {
SliceData(gcreason::Reason reason, int64_t start)
: reason(reason), resetReason(NULL), start(start)
SliceData(gcreason::Reason reason, int64_t start, size_t startFaults)
: reason(reason), resetReason(NULL), start(start), startFaults(startFaults)
{
PodArrayZero(phaseTimes);
PodArrayZero(phaseFaults);
}
gcreason::Reason reason;
const char *resetReason;
int64_t start, end;
size_t startFaults, endFaults;
int64_t phaseTimes[PHASE_LIMIT];
size_t phaseFaults[PHASE_LIMIT];
int64_t duration() const { return end - start; }
};
@ -116,11 +121,9 @@ struct Statistics {
/* Most recent time when the given phase started. */
int64_t phaseStartTimes[PHASE_LIMIT];
size_t phaseStartFaults[PHASE_LIMIT];
/* Total time in a given phase for this GC. */
int64_t phaseTimes[PHASE_LIMIT];
size_t phaseFaults[PHASE_LIMIT];
/* Total time in a given phase over all GCs. */
int64_t phaseTotals[PHASE_LIMIT];

View File

@ -472,30 +472,35 @@ JSCompartment::discardJitCode(FreeOp *fop)
void
JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
{
sweepCrossCompartmentWrappers();
/* Remove dead references held weakly by the compartment. */
sweepBaseShapeTable();
sweepInitialShapeTable();
sweepNewTypeObjectTable(newTypeObjects);
sweepNewTypeObjectTable(lazyTypeObjects);
if (emptyTypeObject && !IsTypeObjectMarked(emptyTypeObject.unsafeGet()))
emptyTypeObject = NULL;
sweepBreakpoints(fop);
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE);
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_DISCARD_CODE);
discardJitCode(fop);
}
if (global_ && !IsObjectMarked(&global_))
global_ = NULL;
/* This function includes itself in PHASE_SWEEP_TABLES. */
sweepCrossCompartmentWrappers();
/* JIT code can hold references on RegExpShared, so sweep regexps after clearing code. */
regExps.sweep(rt);
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_TABLES);
/* Remove dead references held weakly by the compartment. */
sweepBaseShapeTable();
sweepInitialShapeTable();
sweepNewTypeObjectTable(newTypeObjects);
sweepNewTypeObjectTable(lazyTypeObjects);
if (emptyTypeObject && !IsTypeObjectMarked(emptyTypeObject.unsafeGet()))
emptyTypeObject = NULL;
sweepBreakpoints(fop);
if (global_ && !IsObjectMarked(&global_))
global_ = NULL;
/* JIT code can hold references on RegExpShared, so sweep regexps after clearing code. */
regExps.sweep(rt);
}
if (!activeAnalysis && !gcPreserveCode) {
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_ANALYSIS);
@ -548,6 +553,11 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
script->clearAnalysis();
}
}
{
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_FREE_TI_ARENA);
oldAlloc.freeAll();
}
}
active = false;
@ -561,6 +571,8 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
void
JSCompartment::sweepCrossCompartmentWrappers()
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_TABLES);
/* Remove dead wrappers from the table. */
for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
CrossCompartmentKey key = e.front().key;

View File

@ -3052,7 +3052,7 @@ BeginMarkPhase(JSRuntime *rt, bool isIncremental)
/* For non-incremental GC the following sweep discards the jit code. */
if (isIncremental) {
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE);
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK_DISCARD_CODE);
c->discardJitCode(rt->defaultFreeOp());
}
}
@ -3110,19 +3110,30 @@ MarkGrayAndWeak(JSRuntime *rt)
{
GCMarker *gcmarker = &rt->gcMarker;
JS_ASSERT(gcmarker->isDrained());
MarkWeakReferences(gcmarker);
gcmarker->setMarkColorGray();
if (gcmarker->hasBufferedGrayRoots()) {
gcmarker->markBufferedGrayRoots();
} else {
if (JSTraceDataOp op = rt->gcGrayRootsTraceOp)
(*op)(gcmarker, rt->gcGrayRootsData);
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK_WEAK);
JS_ASSERT(gcmarker->isDrained());
MarkWeakReferences(gcmarker);
}
SliceBudget budget;
gcmarker->drainMarkStack(budget);
MarkWeakReferences(gcmarker);
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK_GRAY);
gcmarker->setMarkColorGray();
if (gcmarker->hasBufferedGrayRoots()) {
gcmarker->markBufferedGrayRoots();
} else {
if (JSTraceDataOp op = rt->gcGrayRootsTraceOp)
(*op)(gcmarker, rt->gcGrayRootsData);
}
SliceBudget budget;
gcmarker->drainMarkStack(budget);
}
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK_GRAY_WEAK);
MarkWeakReferences(gcmarker);
}
JS_ASSERT(gcmarker->isDrained());
}
@ -3136,7 +3147,6 @@ EndMarkPhase(JSRuntime *rt, bool isIncremental)
{
{
gcstats::AutoPhase ap1(rt->gcStats, gcstats::PHASE_MARK);
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_MARK_OTHER);
MarkGrayAndWeak(rt);
}
@ -3315,6 +3325,7 @@ SweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool *startBackgroundSweep)
c->arenas.purge();
FreeOp fop(rt, *startBackgroundSweep, false);
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_FINALIZE_START);
if (rt->gcFinalizeCallback)
@ -3325,7 +3336,10 @@ SweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool *startBackgroundSweep)
WeakMapBase::sweepAll(&rt->gcMarker);
rt->debugScopes->sweep();
SweepAtomState(rt);
{
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_ATOMS);
SweepAtomState(rt);
}
/* Collect watch points associated with unreachable objects. */
WatchpointMap::sweepAll(rt);