Bug 817341 - Differentiate marking and sweep-marking in GC stats (r=jonco)

This commit is contained in:
Bill McCloskey 2012-12-04 18:29:45 -08:00
parent 546e48620c
commit 8e805e4167
3 changed files with 102 additions and 65 deletions

View File

@ -267,49 +267,55 @@ t(int64_t t)
struct PhaseInfo
{
unsigned index;
Phase index;
const char *name;
Phase parent;
};
static const Phase PHASE_NO_PARENT = PHASE_LIMIT;
static PhaseInfo phases[] = {
{ PHASE_GC_BEGIN, "Begin Callback" },
{ 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_SWEEP, "Sweep" },
{ PHASE_SWEEP_MARK_INCOMING_BLACK, "Mark Incoming Black Pointers" },
{ PHASE_SWEEP_MARK_WEAK, "Mark Weak" },
{ PHASE_SWEEP_MARK_GRAY, "Mark Gray" },
{ PHASE_SWEEP_MARK_GRAY_WEAK, "Mark Gray and Weak" },
{ PHASE_SWEEP_MARK_INCOMING_GRAY, "Mark Incoming Gray Pointers" },
{ PHASE_FINALIZE_START, "Finalize Start Callback" },
{ PHASE_SWEEP_ATOMS, "Sweep Atoms" },
{ PHASE_SWEEP_COMPARTMENTS, "Sweep Compartments" },
{ PHASE_SWEEP_TABLES, "Sweep Tables" },
{ PHASE_SWEEP_TABLES_WRAPPER, "Sweep Cross Compartment Wrappers" },
{ PHASE_SWEEP_TABLES_BASE_SHAPE, "Sweep Base Shapes" },
{ PHASE_SWEEP_TABLES_INITIAL_SHAPE, "Sweep Intital Shapes" },
{ PHASE_SWEEP_TABLES_TYPE_OBJECT, "Sweep Type Objects" },
{ PHASE_SWEEP_TABLES_BREAKPOINT, "Sweep Breakpoints" },
{ PHASE_SWEEP_TABLES_REGEXP, "Sweep Regexps" },
{ PHASE_SWEEP_OBJECT, "Sweep Object" },
{ PHASE_SWEEP_STRING, "Sweep String" },
{ PHASE_SWEEP_SCRIPT, "Sweep Script" },
{ PHASE_SWEEP_SHAPE, "Sweep Shape" },
{ 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" },
{ PHASE_DESTROY, "Deallocate" },
{ PHASE_GC_END, "End Callback" },
{ 0, NULL }
{ PHASE_GC_BEGIN, "Begin Callback", PHASE_NO_PARENT },
{ PHASE_WAIT_BACKGROUND_THREAD, "Wait Background Thread", PHASE_NO_PARENT },
{ PHASE_MARK_DISCARD_CODE, "Mark Discard Code", PHASE_NO_PARENT },
{ PHASE_PURGE, "Purge", PHASE_NO_PARENT },
{ PHASE_MARK, "Mark", PHASE_NO_PARENT },
{ PHASE_MARK_ROOTS, "Mark Roots", PHASE_MARK },
{ PHASE_MARK_TYPES, "Mark Types", PHASE_MARK_ROOTS },
{ PHASE_MARK_DELAYED, "Mark Delayed", PHASE_MARK },
{ PHASE_SWEEP, "Sweep", PHASE_NO_PARENT },
{ PHASE_SWEEP_MARK, "Mark During Sweeping", PHASE_SWEEP },
{ PHASE_SWEEP_MARK_DELAYED, "Mark Delayed During Sweeping", PHASE_SWEEP_MARK },
{ PHASE_SWEEP_MARK_INCOMING_BLACK, "Mark Incoming Black Pointers", PHASE_SWEEP_MARK },
{ PHASE_SWEEP_MARK_WEAK, "Mark Weak", PHASE_SWEEP_MARK },
{ PHASE_SWEEP_MARK_INCOMING_GRAY, "Mark Incoming Gray Pointers", PHASE_SWEEP_MARK },
{ PHASE_SWEEP_MARK_GRAY, "Mark Gray", PHASE_SWEEP_MARK },
{ PHASE_SWEEP_MARK_GRAY_WEAK, "Mark Gray and Weak", PHASE_SWEEP_MARK },
{ PHASE_FINALIZE_START, "Finalize Start Callback", PHASE_SWEEP },
{ PHASE_SWEEP_ATOMS, "Sweep Atoms", PHASE_SWEEP },
{ PHASE_SWEEP_COMPARTMENTS, "Sweep Compartments", PHASE_SWEEP },
{ PHASE_SWEEP_DISCARD_CODE, "Sweep Discard Code", PHASE_SWEEP_COMPARTMENTS },
{ PHASE_SWEEP_TABLES, "Sweep Tables", PHASE_SWEEP_COMPARTMENTS },
{ PHASE_SWEEP_TABLES_WRAPPER, "Sweep Cross Compartment Wrappers", PHASE_SWEEP_TABLES },
{ PHASE_SWEEP_TABLES_BASE_SHAPE, "Sweep Base Shapes", PHASE_SWEEP_TABLES },
{ PHASE_SWEEP_TABLES_INITIAL_SHAPE, "Sweep Intital Shapes", PHASE_SWEEP_TABLES },
{ PHASE_SWEEP_TABLES_TYPE_OBJECT, "Sweep Type Objects", PHASE_SWEEP_TABLES },
{ PHASE_SWEEP_TABLES_BREAKPOINT, "Sweep Breakpoints", PHASE_SWEEP_TABLES },
{ PHASE_SWEEP_TABLES_REGEXP, "Sweep Regexps", PHASE_SWEEP_TABLES },
{ PHASE_DISCARD_ANALYSIS, "Discard Analysis", PHASE_SWEEP_COMPARTMENTS },
{ PHASE_DISCARD_TI, "Discard TI", PHASE_DISCARD_ANALYSIS },
{ PHASE_FREE_TI_ARENA, "Free TI Arena", PHASE_DISCARD_ANALYSIS },
{ PHASE_SWEEP_TYPES, "Sweep Types", PHASE_DISCARD_ANALYSIS },
{ PHASE_CLEAR_SCRIPT_ANALYSIS, "Clear Script Analysis", PHASE_DISCARD_ANALYSIS },
{ PHASE_SWEEP_OBJECT, "Sweep Object", PHASE_SWEEP },
{ PHASE_SWEEP_STRING, "Sweep String", PHASE_SWEEP },
{ PHASE_SWEEP_SCRIPT, "Sweep Script", PHASE_SWEEP },
{ PHASE_SWEEP_SHAPE, "Sweep Shape", PHASE_SWEEP },
{ PHASE_SWEEP_IONCODE, "Sweep Ion code", PHASE_SWEEP },
{ PHASE_FINALIZE_END, "Finalize End Callback", PHASE_SWEEP },
{ PHASE_DESTROY, "Deallocate", PHASE_SWEEP },
{ PHASE_GC_END, "End Callback", PHASE_NO_PARENT },
{ PHASE_LIMIT, NULL, PHASE_NO_PARENT }
};
static void
@ -441,7 +447,9 @@ Statistics::Statistics(JSRuntime *rt)
gcDepth(0),
collectedCount(0),
compartmentCount(0),
nonincrementalReason(NULL)
nonincrementalReason(NULL),
preBytes(0),
phaseNestingDepth(0)
{
PodArrayZero(phaseTotals);
PodArrayZero(counts);
@ -615,6 +623,15 @@ Statistics::beginPhase(Phase phase)
/* Guard against re-entry */
JS_ASSERT(!phaseStartTimes[phase]);
#ifdef DEBUG
JS_ASSERT(phases[phase].index == phase);
Phase parent = phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : PHASE_NO_PARENT;
JS_ASSERT(phaseNestingDepth < MAX_NESTING);
JS_ASSERT_IF(gcDepth == 1, phases[phase].parent == parent);
phaseNesting[phaseNestingDepth] = phase;
phaseNestingDepth++;
#endif
phaseStartTimes[phase] = PRMJ_Now();
if (phase == gcstats::PHASE_MARK)
@ -626,6 +643,8 @@ Statistics::beginPhase(Phase phase)
void
Statistics::endPhase(Phase phase)
{
phaseNestingDepth--;
int64_t t = PRMJ_Now() - phaseStartTimes[phase];
slices.back().phaseTimes[phase] += t;
phaseTimes[phase] += t;

View File

@ -10,6 +10,8 @@
#include <string.h>
#include "mozilla/Util.h"
#include "jsfriendapi.h"
#include "jspubtd.h"
#include "jsutil.h"
@ -22,21 +24,24 @@ namespace gcstats {
enum Phase {
PHASE_GC_BEGIN,
PHASE_WAIT_BACKGROUND_THREAD,
PHASE_MARK_DISCARD_CODE,
PHASE_PURGE,
PHASE_MARK,
PHASE_MARK_DISCARD_CODE,
PHASE_MARK_ROOTS,
PHASE_MARK_TYPES,
PHASE_MARK_DELAYED,
PHASE_FINALIZE_START,
PHASE_SWEEP,
PHASE_SWEEP_MARK,
PHASE_SWEEP_MARK_DELAYED,
PHASE_SWEEP_MARK_INCOMING_BLACK,
PHASE_SWEEP_MARK_WEAK,
PHASE_SWEEP_MARK_INCOMING_GRAY,
PHASE_SWEEP_MARK_GRAY,
PHASE_SWEEP_MARK_GRAY_WEAK,
PHASE_FINALIZE_START,
PHASE_SWEEP_ATOMS,
PHASE_SWEEP_COMPARTMENTS,
PHASE_SWEEP_DISCARD_CODE,
PHASE_SWEEP_TABLES,
PHASE_SWEEP_TABLES_WRAPPER,
PHASE_SWEEP_TABLES_BASE_SHAPE,
@ -44,17 +49,16 @@ enum Phase {
PHASE_SWEEP_TABLES_TYPE_OBJECT,
PHASE_SWEEP_TABLES_BREAKPOINT,
PHASE_SWEEP_TABLES_REGEXP,
PHASE_SWEEP_OBJECT,
PHASE_SWEEP_STRING,
PHASE_SWEEP_SCRIPT,
PHASE_SWEEP_SHAPE,
PHASE_SWEEP_IONCODE,
PHASE_SWEEP_DISCARD_CODE,
PHASE_DISCARD_ANALYSIS,
PHASE_DISCARD_TI,
PHASE_FREE_TI_ARENA,
PHASE_SWEEP_TYPES,
PHASE_CLEAR_SCRIPT_ANALYSIS,
PHASE_SWEEP_OBJECT,
PHASE_SWEEP_STRING,
PHASE_SWEEP_SCRIPT,
PHASE_SWEEP_SHAPE,
PHASE_SWEEP_IONCODE,
PHASE_FINALIZE_END,
PHASE_DESTROY,
PHASE_GC_END,
@ -146,6 +150,13 @@ struct Statistics {
/* Allocated space before the GC started. */
size_t preBytes;
#ifdef DEBUG
/* Phases that are currently on stack. */
static const size_t MAX_NESTING = 8;
Phase phaseNesting[MAX_NESTING];
#endif
mozilla::DebugOnly<size_t> phaseNestingDepth;
/* Sweep times for SCCs of compartments. */
Vector<int64_t, 0, SystemAllocPolicy> sccTimes;

View File

@ -1370,6 +1370,7 @@ ArenaLists::queueShapesForSweep(FreeOp *fop)
void
ArenaLists::queueIonCodeForSweep(FreeOp *fop)
{
gcstats::AutoPhase ap(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_IONCODE);
finalizeNow(fop, FINALIZE_IONCODE);
}
@ -1680,7 +1681,10 @@ GCMarker::markDelayedChildren(ArenaHeader *aheader)
bool
GCMarker::markDelayedChildren(SliceBudget &budget)
{
gcstats::AutoPhase ap(runtime->gcStats, gcstats::PHASE_MARK_DELAYED);
gcstats::Phase phase = runtime->gcIncrementalState == MARK
? gcstats::PHASE_MARK_DELAYED
: gcstats::PHASE_SWEEP_MARK_DELAYED;
gcstats::AutoPhase ap(runtime->gcStats, phase);
JS_ASSERT(unmarkedArenaStackTop);
do {
@ -2710,7 +2714,8 @@ MarkWeakReferences(JSRuntime *rt, gcstats::Phase phase)
GCMarker *gcmarker = &rt->gcMarker;
JS_ASSERT(gcmarker->isDrained());
gcstats::AutoPhase ap(rt->gcStats, phase);
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_MARK);
gcstats::AutoPhase ap1(rt->gcStats, phase);
for (;;) {
bool markedAny = false;
@ -2735,7 +2740,8 @@ MarkGrayReferences(JSRuntime *rt)
GCMarker *gcmarker = &rt->gcMarker;
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_MARK_GRAY);
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_MARK);
gcstats::AutoPhase ap1(rt->gcStats, gcstats::PHASE_SWEEP_MARK_GRAY);
gcmarker->setMarkColorGray();
if (gcmarker->hasBufferedGrayRoots()) {
gcmarker->markBufferedGrayRoots();
@ -3095,6 +3101,7 @@ MarkIncomingCrossCompartmentPointers(JSRuntime *rt, const uint32_t color)
{
JS_ASSERT(color == BLACK || color == GRAY);
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_MARK);
static const gcstats::Phase statsPhases[] = {
gcstats::PHASE_SWEEP_MARK_INCOMING_BLACK,
gcstats::PHASE_SWEEP_MARK_INCOMING_GRAY
@ -3409,12 +3416,24 @@ ArenaLists::foregroundFinalize(FreeOp *fop, AllocKind thingKind, SliceBudget &sl
return FinalizeArenas(fop, &arenaListsToSweep[thingKind], dest, thingKind, sliceBudget);
}
static bool
DrainMarkStack(JSRuntime *rt, SliceBudget &sliceBudget, gcstats::Phase phase)
{
/* Run a marking slice and return whether the stack is now empty. */
gcstats::AutoPhase ap(rt->gcStats, phase);
return rt->gcMarker.drainMarkStack(sliceBudget);
}
static bool
SweepPhase(JSRuntime *rt, SliceBudget &sliceBudget)
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP);
FreeOp fop(rt, rt->gcSweepOnBackgroundThread);
bool finished = DrainMarkStack(rt, sliceBudget, gcstats::PHASE_SWEEP_MARK);
if (!finished)
return false;
for (;;) {
for (; rt->gcSweepPhase < FinalizePhaseCount ; ++rt->gcSweepPhase) {
gcstats::AutoPhase ap(rt->gcStats, FinalizePhaseStatsPhase[rt->gcSweepPhase]);
@ -3770,14 +3789,6 @@ PushZealSelectedObjects(JSRuntime *rt)
#endif
}
static bool
DrainMarkStack(JSRuntime *rt, SliceBudget &sliceBudget)
{
/* Run a marking slice and return whether the stack is now empty. */
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK);
return rt->gcMarker.drainMarkStack(sliceBudget);
}
static void
IncrementalCollectSlice(JSRuntime *rt,
int64_t budget,
@ -3844,7 +3855,7 @@ IncrementalCollectSlice(JSRuntime *rt,
if (!rt->gcMarker.hasBufferedGrayRoots())
sliceBudget.reset();
bool finished = DrainMarkStack(rt, sliceBudget);
bool finished = DrainMarkStack(rt, sliceBudget, gcstats::PHASE_MARK);
if (!finished)
break;
@ -3884,11 +3895,7 @@ IncrementalCollectSlice(JSRuntime *rt,
}
case SWEEP: {
bool finished = DrainMarkStack(rt, sliceBudget);
if (!finished)
break;
finished = SweepPhase(rt, sliceBudget);
bool finished = SweepPhase(rt, sliceBudget);
if (!finished)
break;