Bug 650161 - Add new stats phases for compacting GC r=terrence

This commit is contained in:
Jon Coppeard 2014-08-14 11:52:31 +01:00
parent 5ae930f7bd
commit 64e065fab8
9 changed files with 173 additions and 162 deletions

View File

@ -499,10 +499,10 @@ class GCRuntime
bool drainMarkStack(SliceBudget &sliceBudget, gcstats::Phase phase);
template <class CompartmentIterT> void markWeakReferences(gcstats::Phase phase);
void markWeakReferencesInCurrentGroup(gcstats::Phase phase);
template <class ZoneIterT, class CompartmentIterT> void markGrayReferences();
void markGrayReferencesInCurrentGroup();
template <class ZoneIterT, class CompartmentIterT> void markGrayReferences(gcstats::Phase phase);
void markGrayReferencesInCurrentGroup(gcstats::Phase phase);
void markAllWeakReferences(gcstats::Phase phase);
void markAllGrayReferences();
void markAllGrayReferences(gcstats::Phase phase);
void beginSweepPhase(bool lastGC);
void findZoneGroups();
@ -523,6 +523,7 @@ class GCRuntime
bool shouldCompact();
#ifdef JSGC_COMPACTING
void compactPhase();
ArenaHeader *relocateArenas();
void updatePointersToRelocatedCells();
void releaseRelocatedArenas(ArenaHeader *relocatedList);
#endif

View File

@ -307,6 +307,10 @@ static const PhaseInfo phases[] = {
{ PHASE_SWEEP_SCRIPT, "Sweep Script", PHASE_SWEEP },
{ PHASE_SWEEP_SHAPE, "Sweep Shape", PHASE_SWEEP },
{ PHASE_SWEEP_JITCODE, "Sweep JIT code", PHASE_SWEEP },
{ PHASE_COMPACT, "Compact", PHASE_NO_PARENT },
{ PHASE_COMPACT_MOVE, "Compact Move", PHASE_COMPACT },
{ PHASE_COMPACT_UPDATE, "Compact Update", PHASE_COMPACT, },
{ PHASE_COMPACT_UPDATE_GRAY, "Compact Update Gray", PHASE_COMPACT_UPDATE, },
{ PHASE_FINALIZE_END, "Finalize End Callback", PHASE_SWEEP },
{ PHASE_DESTROY, "Deallocate", PHASE_SWEEP },
{ PHASE_GC_END, "End Callback", PHASE_NO_PARENT },

View File

@ -58,6 +58,10 @@ enum Phase {
PHASE_SWEEP_SCRIPT,
PHASE_SWEEP_SHAPE,
PHASE_SWEEP_JITCODE,
PHASE_COMPACT,
PHASE_COMPACT_MOVE,
PHASE_COMPACT_UPDATE,
PHASE_COMPACT_UPDATE_GRAY,
PHASE_FINALIZE_END,
PHASE_DESTROY,
PHASE_GC_END,
@ -227,18 +231,17 @@ struct AutoPhase
struct MaybeAutoPhase
{
explicit MaybeAutoPhase(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
explicit MaybeAutoPhase(Statistics &statsArg, bool condition, Phase phaseArg
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: stats(nullptr)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
void construct(Statistics &statsArg, Phase phaseArg)
{
JS_ASSERT(!stats);
if (condition) {
stats = &statsArg;
phase = phaseArg;
stats->beginPhase(phase);
}
}
~MaybeAutoPhase() {
if (stats)
stats->endPhase(phase);

View File

@ -554,9 +554,8 @@ GCMarker::markDelayedChildren(ArenaHeader *aheader)
bool
GCMarker::markDelayedChildren(SliceBudget &budget)
{
gcstats::MaybeAutoPhase ap;
if (runtime()->gc.state() == MARK)
ap.construct(runtime()->gc.stats, gcstats::PHASE_MARK_DELAYED);
GCRuntime &gc = runtime()->gc;
gcstats::MaybeAutoPhase ap(gc.stats, gc.state() == MARK, gcstats::PHASE_MARK_DELAYED);
JS_ASSERT(unmarkedArenaStackTop);
do {

View File

@ -113,13 +113,21 @@ Zone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
if (active)
releaseTypes = false;
GCRuntime &gc = fop->runtime()->gc;
{
gcstats::AutoPhase ap(fop->runtime()->gc.stats, gcstats::PHASE_DISCARD_ANALYSIS);
gcstats::MaybeAutoPhase ap(gc.stats, !gc.isHeapCompacting(),
gcstats::PHASE_DISCARD_ANALYSIS);
types.sweep(fop, releaseTypes, oom);
}
if (!fop->runtime()->debuggerList.isEmpty())
if (!fop->runtime()->debuggerList.isEmpty()) {
gcstats::MaybeAutoPhase ap1(gc.stats, !gc.isHeapCompacting(),
gcstats::PHASE_SWEEP_TABLES);
gcstats::MaybeAutoPhase ap2(gc.stats, !gc.isHeapCompacting(),
gcstats::PHASE_SWEEP_TABLES_BREAKPOINT);
sweepBreakpoints(fop);
}
}
void
@ -130,9 +138,6 @@ Zone::sweepBreakpoints(FreeOp *fop)
* to iterate over the scripts belonging to a single compartment in a zone.
*/
gcstats::AutoPhase ap1(fop->runtime()->gc.stats, gcstats::PHASE_SWEEP_TABLES);
gcstats::AutoPhase ap2(fop->runtime()->gc.stats, gcstats::PHASE_SWEEP_TABLES_BREAKPOINT);
JS_ASSERT(isGCSweepingOrCompacting());
for (ZoneCellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();

View File

@ -572,21 +572,20 @@ void
JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
{
JS_ASSERT(!activeAnalysis);
/* This function includes itself in PHASE_SWEEP_TABLES. */
sweepCrossCompartmentWrappers();
JSRuntime *rt = runtimeFromMainThread();
{
gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP_TABLES);
gcstats::MaybeAutoPhase ap(rt->gc.stats, !rt->isHeapCompacting(),
gcstats::PHASE_SWEEP_TABLES_WRAPPER);
sweepCrossCompartmentWrappers();
}
/* Remove dead references held weakly by the compartment. */
sweepBaseShapeTable();
sweepInitialShapeTable();
{
gcstats::AutoPhase ap(runtimeFromMainThread()->gc.stats,
gcstats::MaybeAutoPhase ap(rt->gc.stats, !rt->isHeapCompacting(),
gcstats::PHASE_SWEEP_TABLES_TYPE_OBJECT);
sweepNewTypeObjectTable(newTypeObjects);
sweepNewTypeObjectTable(lazyTypeObjects);
@ -618,8 +617,8 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
/* Finalize unreachable (key,value) pairs in all weak maps. */
WeakMapBase::sweepCompartment(this);
}
/* Sweep list of native iterators. */
NativeIterator *ni = enumerators->next();
while (ni != enumerators) {
JSObject *iterObj = ni->iterObj();
@ -638,11 +637,6 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
void
JSCompartment::sweepCrossCompartmentWrappers()
{
JSRuntime *rt = runtimeFromMainThread();
gcstats::AutoPhase ap1(rt->gc.stats, gcstats::PHASE_SWEEP_TABLES);
gcstats::AutoPhase ap2(rt->gc.stats, gcstats::PHASE_SWEEP_TABLES_WRAPPER);
/* Remove dead wrappers from the table. */
for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
CrossCompartmentKey key = e.front().key();

View File

@ -2220,6 +2220,26 @@ ArenaLists::relocateArenas(ArenaHeader *relocatedList)
return relocatedList;
}
ArenaHeader *
GCRuntime::relocateArenas()
{
gcstats::AutoPhase ap(stats, gcstats::PHASE_COMPACT_MOVE);
ArenaHeader *relocatedList = nullptr;
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
JS_ASSERT(zone->isGCFinished());
JS_ASSERT(!zone->isPreservingCode());
// We cannot move atoms as we depend on their addresses being constant.
if (!rt->isAtomsZone(zone)) {
zone->setGCState(Zone::Compact);
relocatedList = zone->allocator.arenas.relocateArenas(relocatedList);
}
}
return relocatedList;
}
struct MovingTracer : JSTracer {
MovingTracer(JSRuntime *rt) : JSTracer(rt, Visit, TraceWeakMapValues) {}
@ -2254,8 +2274,6 @@ MovingTracer::Sweep(JSTracer *jstrc)
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
if (zone->isCollecting()) {
gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP_COMPARTMENTS);
bool oom = false;
zone->sweep(fop, false, &oom);
JS_ASSERT(!oom);
@ -2301,11 +2319,9 @@ void
GCRuntime::updatePointersToRelocatedCells()
{
JS_ASSERT(rt->currentThreadHasExclusiveAccess());
MovingTracer trc(rt);
{
// TODO: Maybe give compaction its own set of phases.
gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK);
gcstats::AutoPhase ap(stats, gcstats::PHASE_COMPACT_UPDATE);
MovingTracer trc(rt);
// TODO: We may need to fix up other weak pointers here.
@ -2346,15 +2362,11 @@ GCRuntime::updatePointersToRelocatedCells()
if (c->watchpointMap)
c->watchpointMap->markAll(&trc);
}
}
{
gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP);
markAllGrayReferences();
markAllGrayReferences(gcstats::PHASE_COMPACT_UPDATE_GRAY);
markAllWeakReferences(gcstats::PHASE_COMPACT_UPDATE_GRAY);
MovingTracer::Sweep(&trc);
}
}
void
@ -3742,7 +3754,6 @@ GCRuntime::markWeakReferences(gcstats::Phase phase)
{
JS_ASSERT(marker.isDrained());
gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_MARK);
gcstats::AutoPhase ap1(stats, phase);
for (;;) {
@ -3770,12 +3781,9 @@ GCRuntime::markWeakReferencesInCurrentGroup(gcstats::Phase phase)
template <class ZoneIterT, class CompartmentIterT>
void
GCRuntime::markGrayReferences()
GCRuntime::markGrayReferences(gcstats::Phase phase)
{
{
gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_MARK);
gcstats::AutoPhase ap1(stats, gcstats::PHASE_SWEEP_MARK_GRAY);
marker.setMarkColorGray();
gcstats::AutoPhase ap(stats, phase);
if (marker.hasBufferedGrayRoots()) {
for (ZoneIterT zone(rt); !zone.done(); zone.next())
marker.markBufferedGrayRoots(zone);
@ -3786,19 +3794,12 @@ GCRuntime::markGrayReferences()
}
SliceBudget budget;
marker.drainMarkStack(budget);
}
markWeakReferences<CompartmentIterT>(gcstats::PHASE_SWEEP_MARK_GRAY_WEAK);
JS_ASSERT(marker.isDrained());
marker.setMarkColorBlack();
}
void
GCRuntime::markGrayReferencesInCurrentGroup()
GCRuntime::markGrayReferencesInCurrentGroup(gcstats::Phase phase)
{
markGrayReferences<GCZoneGroupIter, GCCompartmentGroupIter>();
markGrayReferences<GCZoneGroupIter, GCCompartmentGroupIter>(phase);
}
void
@ -3808,9 +3809,9 @@ GCRuntime::markAllWeakReferences(gcstats::Phase phase)
}
void
GCRuntime::markAllGrayReferences()
GCRuntime::markAllGrayReferences(gcstats::Phase phase)
{
markGrayReferences<GCZonesIter, GCCompartmentsIter>();
markGrayReferences<GCZonesIter, GCCompartmentsIter>(phase);
}
#ifdef DEBUG
@ -3931,7 +3932,8 @@ js::gc::MarkingValidator::nonIncrementalMark()
gc->incrementalState = SWEEP;
{
gcstats::AutoPhase ap(gc->stats, gcstats::PHASE_SWEEP);
gcstats::AutoPhase ap1(gc->stats, gcstats::PHASE_SWEEP);
gcstats::AutoPhase ap2(gc->stats, gcstats::PHASE_SWEEP_MARK);
gc->markAllWeakReferences(gcstats::PHASE_SWEEP_MARK_WEAK);
/* Update zone state for gray marking. */
@ -3939,14 +3941,18 @@ js::gc::MarkingValidator::nonIncrementalMark()
JS_ASSERT(zone->isGCMarkingBlack());
zone->setGCState(Zone::MarkGray);
}
gc->marker.setMarkColorGray();
gc->markAllGrayReferences();
gc->markAllGrayReferences(gcstats::PHASE_SWEEP_MARK_GRAY);
gc->markAllWeakReferences(gcstats::PHASE_SWEEP_MARK_GRAY_WEAK);
/* Restore zone state. */
for (GCZonesIter zone(runtime); !zone.done(); zone.next()) {
JS_ASSERT(zone->isGCMarkingGray());
zone->setGCState(Zone::Mark);
}
JS_ASSERT(gc->marker.isDrained());
gc->marker.setMarkColorBlack();
}
/* Take a copy of the non-incremental mark state and restore the original. */
@ -4347,7 +4353,6 @@ MarkIncomingCrossCompartmentPointers(JSRuntime *rt, const uint32_t color)
{
JS_ASSERT(color == BLACK || color == GRAY);
gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP_MARK);
static const gcstats::Phase statsPhases[] = {
gcstats::PHASE_SWEEP_MARK_INCOMING_BLACK,
gcstats::PHASE_SWEEP_MARK_INCOMING_GRAY
@ -4472,6 +4477,8 @@ js::NotifyGCPostSwap(JSObject *a, JSObject *b, unsigned removedFlags)
void
GCRuntime::endMarkingZoneGroup()
{
gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_MARK);
/*
* Mark any incoming black pointers from previously swept compartments
* whose referents are not marked. This can occur when gray cells become
@ -4491,22 +4498,22 @@ GCRuntime::endMarkingZoneGroup()
JS_ASSERT(zone->isGCMarkingBlack());
zone->setGCState(Zone::MarkGray);
}
marker.setMarkColorGray();
/* Mark incoming gray pointers from previously swept compartments. */
marker.setMarkColorGray();
MarkIncomingCrossCompartmentPointers(rt, GRAY);
marker.setMarkColorBlack();
/* Mark gray roots and mark transitively inside the current compartment group. */
markGrayReferencesInCurrentGroup();
markGrayReferencesInCurrentGroup(gcstats::PHASE_SWEEP_MARK_GRAY);
markWeakReferencesInCurrentGroup(gcstats::PHASE_SWEEP_MARK_GRAY_WEAK);
/* Restore marking state. */
for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) {
JS_ASSERT(zone->isGCMarkingGray());
zone->setGCState(Zone::Mark);
}
JS_ASSERT(marker.isDrained());
MOZ_ASSERT(marker.isDrained());
marker.setMarkColorBlack();
}
void
@ -4579,6 +4586,8 @@ GCRuntime::beginSweepingZoneGroup()
for (GCCompartmentGroupIter c(rt); !c.done(); c.next()) {
gcstats::AutoSCC scc(stats, zoneGroupIndex);
gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_TABLES);
c->sweep(&fop, releaseObservedTypes && !c->zone()->isPreservingCode());
}
@ -4940,18 +4949,9 @@ GCRuntime::compactPhase()
JS_ASSERT(rt->gc.nursery.isEmpty());
JS_ASSERT(!sweepOnBackgroundThread);
ArenaHeader *relocatedList = nullptr;
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
JS_ASSERT(zone->isGCFinished());
JS_ASSERT(!zone->isPreservingCode());
// We cannot move atoms as we depend on their addresses being constant.
if (!rt->isAtomsZone(zone)) {
zone->setGCState(Zone::Compact);
relocatedList = zone->allocator.arenas.relocateArenas(relocatedList);
}
}
gcstats::AutoPhase ap(stats, gcstats::PHASE_COMPACT);
ArenaHeader *relocatedList = relocateArenas();
updatePointersToRelocatedCells();
releaseRelocatedArenas(relocatedList);

View File

@ -4390,7 +4390,8 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
}
{
gcstats::AutoPhase ap2(rt->gc.stats, gcstats::PHASE_DISCARD_TI);
gcstats::MaybeAutoPhase ap2(rt->gc.stats, !rt->isHeapCompacting(),
gcstats::PHASE_DISCARD_TI);
for (ZoneCellIterUnderGC i(zone(), FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
@ -4421,7 +4422,8 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
}
{
gcstats::AutoPhase ap2(rt->gc.stats, gcstats::PHASE_SWEEP_TYPES);
gcstats::MaybeAutoPhase ap2(rt->gc.stats, !rt->isHeapCompacting(),
gcstats::PHASE_SWEEP_TYPES);
for (gc::ZoneCellIterUnderGC iter(zone(), gc::FINALIZE_TYPE_OBJECT);
!iter.done(); iter.next())
@ -4449,7 +4451,8 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
}
{
gcstats::AutoPhase ap2(rt->gc.stats, gcstats::PHASE_FREE_TI_ARENA);
gcstats::MaybeAutoPhase ap2(rt->gc.stats, !rt->isHeapCompacting(),
gcstats::PHASE_FREE_TI_ARENA);
rt->freeLifoAlloc.transferFrom(&oldAlloc);
}
}

View File

@ -1542,7 +1542,8 @@ BaseShape::assertConsistency()
void
JSCompartment::sweepBaseShapeTable()
{
gcstats::AutoPhase ap(runtimeFromMainThread()->gc.stats,
GCRuntime &gc = runtimeFromMainThread()->gc;
gcstats::MaybeAutoPhase ap(gc.stats, !gc.isHeapCompacting(),
gcstats::PHASE_SWEEP_TABLES_BASE_SHAPE);
if (baseShapes.initialized()) {
@ -1839,7 +1840,8 @@ EmptyShape::insertInitialShape(ExclusiveContext *cx, HandleShape shape, HandleOb
void
JSCompartment::sweepInitialShapeTable()
{
gcstats::AutoPhase ap(runtimeFromMainThread()->gc.stats,
GCRuntime &gc = runtimeFromMainThread()->gc;
gcstats::MaybeAutoPhase ap(gc.stats, !gc.isHeapCompacting(),
gcstats::PHASE_SWEEP_TABLES_INITIAL_SHAPE);
if (initialShapes.initialized()) {