Loading js/src/builtin/TestingFunctions.cpp +5 −1 Original line number Diff line number Diff line Loading @@ -3737,7 +3737,11 @@ SetGCCallback(JSContext* cx, unsigned argc, Value* vp) if (!ToInt32(cx, v, &depth)) return false; } if (depth > int32_t(gcstats::Statistics::MAX_NESTING - 4)) { if (depth < 0) { JS_ReportErrorASCII(cx, "Nesting depth cannot be negative"); return false; } if (depth + gcstats::MAX_PHASE_NESTING > gcstats::Statistics::MAX_SUSPENDED_PHASES) { JS_ReportErrorASCII(cx, "Nesting depth too large, would overflow"); return false; } Loading js/src/gc/GenerateStatsPhases.py +10 −0 Original line number Diff line number Diff line Loading @@ -231,6 +231,10 @@ for phaseKind in AllPhaseKinds: for index, phase in enumerate(phases): phase.name = "%s_%d" % (phaseKind.name, index + 1) # Find the maximum phase nesting. MaxPhaseNesting = max(phase.depth for phase in AllPhases) + 1 # Generate code. def writeList(out, items): Loading Loading @@ -267,6 +271,12 @@ def generateHeader(out): "IMPLICIT_SUSPENSION" ] writeEnumClass(out, "Phase", "uint8_t", phaseNames, extraPhases) out.write("\n") # # Generate MAX_PHASE_NESTING constant. # out.write("static const size_t MAX_PHASE_NESTING = %d;\n" % MaxPhaseNesting) def generateCpp(out): # Loading js/src/gc/Statistics.cpp +32 −38 Original line number Diff line number Diff line Loading @@ -124,10 +124,10 @@ t(TimeDuration duration) return duration.ToMilliseconds(); } Phase inline Phase Statistics::currentPhase() const { return phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : Phase::NONE; return phaseStack.empty() ? Phase::NONE : phaseStack.back(); } PhaseKind Loading @@ -137,7 +137,7 @@ Statistics::currentPhaseKind() const // PhaseKind::MUTATOR phase. Phase phase = currentPhase(); MOZ_ASSERT_IF(phase == Phase::MUTATOR, phaseNestingDepth == 1); MOZ_ASSERT_IF(phase == Phase::MUTATOR, phaseStack.length() == 1); if (phase == Phase::NONE || phase == Phase::MUTATOR) return PhaseKind::NONE; Loading Loading @@ -638,8 +638,6 @@ Statistics::Statistics(JSRuntime* rt) nonincrementalReason_(gc::AbortReason::None), preBytes(0), maxPauseInInterval(0), phaseNestingDepth(0), suspended(0), sliceCallback(nullptr), nurseryCollectionCallback(nullptr), aborted(false), Loading @@ -648,6 +646,10 @@ Statistics::Statistics(JSRuntime* rt) { for (auto& count : counts) count = 0; PodZero(&totalTimes_); MOZ_ALWAYS_TRUE(phaseStack.reserve(MAX_PHASE_NESTING)); MOZ_ALWAYS_TRUE(suspendedPhases.reserve(MAX_SUSPENDED_PHASES)); const char* env = getenv("MOZ_GCTIMER"); if (env) { Loading @@ -674,8 +676,6 @@ Statistics::Statistics(JSRuntime* rt) enableProfiling_ = true; profileThreshold_ = TimeDuration::FromMilliseconds(atoi(env)); } PodZero(&totalTimes_); } Statistics::~Statistics() Loading Loading @@ -1030,14 +1030,14 @@ Statistics::reportLongestPhase(const PhaseTimeTable& times, int telemetryId) bool Statistics::startTimingMutator() { if (phaseNestingDepth != 0) { if (phaseStack.length() != 0) { // Should only be called from outside of GC. MOZ_ASSERT(phaseNestingDepth == 1); MOZ_ASSERT(phaseNesting[0] == Phase::MUTATOR); MOZ_ASSERT(phaseStack.length() == 1); MOZ_ASSERT(phaseStack[0] == Phase::MUTATOR); return false; } MOZ_ASSERT(suspended == 0); MOZ_ASSERT(suspendedPhases.empty()); timedGCTime = 0; phaseStartTimes[Phase::MUTATOR] = TimeStamp(); Loading @@ -1052,7 +1052,7 @@ bool Statistics::stopTimingMutator(double& mutator_ms, double& gc_ms) { // This should only be called from outside of GC, while timing the mutator. if (phaseNestingDepth != 1 || phaseNesting[0] != Phase::MUTATOR) if (phaseStack.length() != 1 || phaseStack[0] != Phase::MUTATOR) return false; endPhase(PhaseKind::MUTATOR); Loading @@ -1067,30 +1067,27 @@ Statistics::suspendPhases(PhaseKind suspension) { MOZ_ASSERT(suspension == PhaseKind::EXPLICIT_SUSPENSION || suspension == PhaseKind::IMPLICIT_SUSPENSION); while (phaseNestingDepth) { MOZ_ASSERT(suspended < mozilla::ArrayLength(suspendedPhases)); Phase parent = phaseNesting[phaseNestingDepth - 1]; suspendedPhases[suspended++] = parent; while (!phaseStack.empty()) { MOZ_ASSERT(suspendedPhases.length() < MAX_SUSPENDED_PHASES); Phase parent = phaseStack.back(); suspendedPhases.infallibleAppend(parent); recordPhaseEnd(parent); } suspendedPhases[suspended++] = lookupChildPhase(suspension); suspendedPhases.infallibleAppend(lookupChildPhase(suspension)); } void Statistics::resumePhases() { suspended--; #ifdef DEBUG Phase popped = suspendedPhases[suspended]; MOZ_ASSERT(popped == Phase::EXPLICIT_SUSPENSION || popped == Phase::IMPLICIT_SUSPENSION); #endif MOZ_ASSERT(suspendedPhases.back() == Phase::EXPLICIT_SUSPENSION || suspendedPhases.back() == Phase::IMPLICIT_SUSPENSION); suspendedPhases.popBack(); while (suspended && suspendedPhases[suspended - 1] != Phase::EXPLICIT_SUSPENSION && suspendedPhases[suspended - 1] != Phase::IMPLICIT_SUSPENSION) while (!suspendedPhases.empty() && suspendedPhases.back() != Phase::EXPLICIT_SUSPENSION && suspendedPhases.back() != Phase::IMPLICIT_SUSPENSION) { Phase resumePhase = suspendedPhases[--suspended]; Phase resumePhase = suspendedPhases.popCopy(); if (resumePhase == Phase::MUTATOR) timedGCTime += TimeStamp::Now() - timedGCStart; recordPhaseBegin(resumePhase); Loading @@ -1104,9 +1101,8 @@ Statistics::beginPhase(PhaseKind phaseKind) MOZ_ASSERT(phaseKind != PhaseKind::GC_BEGIN && phaseKind != PhaseKind::GC_END); // PhaseKind::MUTATOR is suspended while performing GC. if (currentPhase() == Phase::MUTATOR) { if (currentPhase() == Phase::MUTATOR) suspendPhases(PhaseKind::IMPLICIT_SUSPENSION); } recordPhaseBegin(lookupChildPhase(phaseKind)); } Loading @@ -1117,12 +1113,10 @@ Statistics::recordPhaseBegin(Phase phase) // Guard against any other re-entry. MOZ_ASSERT(!phaseStartTimes[phase]); MOZ_ASSERT(phaseNestingDepth < MAX_NESTING); MOZ_ASSERT(phaseStack.length() < MAX_PHASE_NESTING); MOZ_ASSERT(phases[phase].parent == currentPhase()); phaseNesting[phaseNestingDepth] = phase; phaseNestingDepth++; phaseStack.infallibleAppend(phase); phaseStartTimes[phase] = TimeStamp::Now(); } Loading @@ -1134,7 +1128,7 @@ Statistics::recordPhaseEnd(Phase phase) if (phase == Phase::MUTATOR) timedGCStart = now; phaseNestingDepth--; phaseStack.popBack(); TimeDuration t = now - phaseStartTimes[phase]; if (!slices_.empty()) Loading @@ -1154,9 +1148,9 @@ Statistics::endPhase(PhaseKind phaseKind) // When emptying the stack, we may need to return to timing the mutator // (PhaseKind::MUTATOR). if (phaseNestingDepth == 0 && suspended > 0 && suspendedPhases[suspended - 1] == Phase::IMPLICIT_SUSPENSION) if (phaseStack.empty() && !suspendedPhases.empty() && suspendedPhases.back() == Phase::IMPLICIT_SUSPENSION) { resumePhases(); } Loading @@ -1182,7 +1176,7 @@ void Statistics::endParallelPhase(PhaseKind phaseKind, const GCParallelTask* task) { Phase phase = lookupChildPhase(phaseKind); phaseNestingDepth--; phaseStack.popBack(); if (!slices_.empty()) slices_.back().phaseTimes[phase] += task->duration(); Loading js/src/gc/Statistics.h +3 −5 Original line number Diff line number Diff line Loading @@ -206,7 +206,7 @@ struct Statistics PhaseKind currentPhaseKind() const; static const size_t MAX_NESTING = 20; static const size_t MAX_SUSPENDED_PHASES = MAX_PHASE_NESTING * 3; struct SliceData { SliceData(SliceBudget budget, JS::gcreason::Reason reason, Loading Loading @@ -304,8 +304,7 @@ struct Statistics mutable TimeDuration maxPauseInInterval; /* Phases that are currently on stack. */ Array<Phase, MAX_NESTING> phaseNesting; size_t phaseNestingDepth; Vector<Phase, MAX_PHASE_NESTING, SystemAllocPolicy> phaseStack; /* * Certain phases can interrupt the phase stack, eg callback phases. When Loading @@ -314,8 +313,7 @@ struct Statistics * suspensions by suspending multiple stacks with a PhaseKind::SUSPENSION in * between). */ Array<Phase, MAX_NESTING * 3> suspendedPhases; size_t suspended; Vector<Phase, MAX_SUSPENDED_PHASES, SystemAllocPolicy> suspendedPhases; /* Sweep times for SCCs of compartments. */ Vector<TimeDuration, 0, SystemAllocPolicy> sccTimes; Loading js/src/tests/shell/gcstats.js +1 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ garbage(); setGCCallback({ action: "majorGC", depth: 10, depth: 8, phases: "begin" }); Loading Loading
js/src/builtin/TestingFunctions.cpp +5 −1 Original line number Diff line number Diff line Loading @@ -3737,7 +3737,11 @@ SetGCCallback(JSContext* cx, unsigned argc, Value* vp) if (!ToInt32(cx, v, &depth)) return false; } if (depth > int32_t(gcstats::Statistics::MAX_NESTING - 4)) { if (depth < 0) { JS_ReportErrorASCII(cx, "Nesting depth cannot be negative"); return false; } if (depth + gcstats::MAX_PHASE_NESTING > gcstats::Statistics::MAX_SUSPENDED_PHASES) { JS_ReportErrorASCII(cx, "Nesting depth too large, would overflow"); return false; } Loading
js/src/gc/GenerateStatsPhases.py +10 −0 Original line number Diff line number Diff line Loading @@ -231,6 +231,10 @@ for phaseKind in AllPhaseKinds: for index, phase in enumerate(phases): phase.name = "%s_%d" % (phaseKind.name, index + 1) # Find the maximum phase nesting. MaxPhaseNesting = max(phase.depth for phase in AllPhases) + 1 # Generate code. def writeList(out, items): Loading Loading @@ -267,6 +271,12 @@ def generateHeader(out): "IMPLICIT_SUSPENSION" ] writeEnumClass(out, "Phase", "uint8_t", phaseNames, extraPhases) out.write("\n") # # Generate MAX_PHASE_NESTING constant. # out.write("static const size_t MAX_PHASE_NESTING = %d;\n" % MaxPhaseNesting) def generateCpp(out): # Loading
js/src/gc/Statistics.cpp +32 −38 Original line number Diff line number Diff line Loading @@ -124,10 +124,10 @@ t(TimeDuration duration) return duration.ToMilliseconds(); } Phase inline Phase Statistics::currentPhase() const { return phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : Phase::NONE; return phaseStack.empty() ? Phase::NONE : phaseStack.back(); } PhaseKind Loading @@ -137,7 +137,7 @@ Statistics::currentPhaseKind() const // PhaseKind::MUTATOR phase. Phase phase = currentPhase(); MOZ_ASSERT_IF(phase == Phase::MUTATOR, phaseNestingDepth == 1); MOZ_ASSERT_IF(phase == Phase::MUTATOR, phaseStack.length() == 1); if (phase == Phase::NONE || phase == Phase::MUTATOR) return PhaseKind::NONE; Loading Loading @@ -638,8 +638,6 @@ Statistics::Statistics(JSRuntime* rt) nonincrementalReason_(gc::AbortReason::None), preBytes(0), maxPauseInInterval(0), phaseNestingDepth(0), suspended(0), sliceCallback(nullptr), nurseryCollectionCallback(nullptr), aborted(false), Loading @@ -648,6 +646,10 @@ Statistics::Statistics(JSRuntime* rt) { for (auto& count : counts) count = 0; PodZero(&totalTimes_); MOZ_ALWAYS_TRUE(phaseStack.reserve(MAX_PHASE_NESTING)); MOZ_ALWAYS_TRUE(suspendedPhases.reserve(MAX_SUSPENDED_PHASES)); const char* env = getenv("MOZ_GCTIMER"); if (env) { Loading @@ -674,8 +676,6 @@ Statistics::Statistics(JSRuntime* rt) enableProfiling_ = true; profileThreshold_ = TimeDuration::FromMilliseconds(atoi(env)); } PodZero(&totalTimes_); } Statistics::~Statistics() Loading Loading @@ -1030,14 +1030,14 @@ Statistics::reportLongestPhase(const PhaseTimeTable& times, int telemetryId) bool Statistics::startTimingMutator() { if (phaseNestingDepth != 0) { if (phaseStack.length() != 0) { // Should only be called from outside of GC. MOZ_ASSERT(phaseNestingDepth == 1); MOZ_ASSERT(phaseNesting[0] == Phase::MUTATOR); MOZ_ASSERT(phaseStack.length() == 1); MOZ_ASSERT(phaseStack[0] == Phase::MUTATOR); return false; } MOZ_ASSERT(suspended == 0); MOZ_ASSERT(suspendedPhases.empty()); timedGCTime = 0; phaseStartTimes[Phase::MUTATOR] = TimeStamp(); Loading @@ -1052,7 +1052,7 @@ bool Statistics::stopTimingMutator(double& mutator_ms, double& gc_ms) { // This should only be called from outside of GC, while timing the mutator. if (phaseNestingDepth != 1 || phaseNesting[0] != Phase::MUTATOR) if (phaseStack.length() != 1 || phaseStack[0] != Phase::MUTATOR) return false; endPhase(PhaseKind::MUTATOR); Loading @@ -1067,30 +1067,27 @@ Statistics::suspendPhases(PhaseKind suspension) { MOZ_ASSERT(suspension == PhaseKind::EXPLICIT_SUSPENSION || suspension == PhaseKind::IMPLICIT_SUSPENSION); while (phaseNestingDepth) { MOZ_ASSERT(suspended < mozilla::ArrayLength(suspendedPhases)); Phase parent = phaseNesting[phaseNestingDepth - 1]; suspendedPhases[suspended++] = parent; while (!phaseStack.empty()) { MOZ_ASSERT(suspendedPhases.length() < MAX_SUSPENDED_PHASES); Phase parent = phaseStack.back(); suspendedPhases.infallibleAppend(parent); recordPhaseEnd(parent); } suspendedPhases[suspended++] = lookupChildPhase(suspension); suspendedPhases.infallibleAppend(lookupChildPhase(suspension)); } void Statistics::resumePhases() { suspended--; #ifdef DEBUG Phase popped = suspendedPhases[suspended]; MOZ_ASSERT(popped == Phase::EXPLICIT_SUSPENSION || popped == Phase::IMPLICIT_SUSPENSION); #endif MOZ_ASSERT(suspendedPhases.back() == Phase::EXPLICIT_SUSPENSION || suspendedPhases.back() == Phase::IMPLICIT_SUSPENSION); suspendedPhases.popBack(); while (suspended && suspendedPhases[suspended - 1] != Phase::EXPLICIT_SUSPENSION && suspendedPhases[suspended - 1] != Phase::IMPLICIT_SUSPENSION) while (!suspendedPhases.empty() && suspendedPhases.back() != Phase::EXPLICIT_SUSPENSION && suspendedPhases.back() != Phase::IMPLICIT_SUSPENSION) { Phase resumePhase = suspendedPhases[--suspended]; Phase resumePhase = suspendedPhases.popCopy(); if (resumePhase == Phase::MUTATOR) timedGCTime += TimeStamp::Now() - timedGCStart; recordPhaseBegin(resumePhase); Loading @@ -1104,9 +1101,8 @@ Statistics::beginPhase(PhaseKind phaseKind) MOZ_ASSERT(phaseKind != PhaseKind::GC_BEGIN && phaseKind != PhaseKind::GC_END); // PhaseKind::MUTATOR is suspended while performing GC. if (currentPhase() == Phase::MUTATOR) { if (currentPhase() == Phase::MUTATOR) suspendPhases(PhaseKind::IMPLICIT_SUSPENSION); } recordPhaseBegin(lookupChildPhase(phaseKind)); } Loading @@ -1117,12 +1113,10 @@ Statistics::recordPhaseBegin(Phase phase) // Guard against any other re-entry. MOZ_ASSERT(!phaseStartTimes[phase]); MOZ_ASSERT(phaseNestingDepth < MAX_NESTING); MOZ_ASSERT(phaseStack.length() < MAX_PHASE_NESTING); MOZ_ASSERT(phases[phase].parent == currentPhase()); phaseNesting[phaseNestingDepth] = phase; phaseNestingDepth++; phaseStack.infallibleAppend(phase); phaseStartTimes[phase] = TimeStamp::Now(); } Loading @@ -1134,7 +1128,7 @@ Statistics::recordPhaseEnd(Phase phase) if (phase == Phase::MUTATOR) timedGCStart = now; phaseNestingDepth--; phaseStack.popBack(); TimeDuration t = now - phaseStartTimes[phase]; if (!slices_.empty()) Loading @@ -1154,9 +1148,9 @@ Statistics::endPhase(PhaseKind phaseKind) // When emptying the stack, we may need to return to timing the mutator // (PhaseKind::MUTATOR). if (phaseNestingDepth == 0 && suspended > 0 && suspendedPhases[suspended - 1] == Phase::IMPLICIT_SUSPENSION) if (phaseStack.empty() && !suspendedPhases.empty() && suspendedPhases.back() == Phase::IMPLICIT_SUSPENSION) { resumePhases(); } Loading @@ -1182,7 +1176,7 @@ void Statistics::endParallelPhase(PhaseKind phaseKind, const GCParallelTask* task) { Phase phase = lookupChildPhase(phaseKind); phaseNestingDepth--; phaseStack.popBack(); if (!slices_.empty()) slices_.back().phaseTimes[phase] += task->duration(); Loading
js/src/gc/Statistics.h +3 −5 Original line number Diff line number Diff line Loading @@ -206,7 +206,7 @@ struct Statistics PhaseKind currentPhaseKind() const; static const size_t MAX_NESTING = 20; static const size_t MAX_SUSPENDED_PHASES = MAX_PHASE_NESTING * 3; struct SliceData { SliceData(SliceBudget budget, JS::gcreason::Reason reason, Loading Loading @@ -304,8 +304,7 @@ struct Statistics mutable TimeDuration maxPauseInInterval; /* Phases that are currently on stack. */ Array<Phase, MAX_NESTING> phaseNesting; size_t phaseNestingDepth; Vector<Phase, MAX_PHASE_NESTING, SystemAllocPolicy> phaseStack; /* * Certain phases can interrupt the phase stack, eg callback phases. When Loading @@ -314,8 +313,7 @@ struct Statistics * suspensions by suspending multiple stacks with a PhaseKind::SUSPENSION in * between). */ Array<Phase, MAX_NESTING * 3> suspendedPhases; size_t suspended; Vector<Phase, MAX_SUSPENDED_PHASES, SystemAllocPolicy> suspendedPhases; /* Sweep times for SCCs of compartments. */ Vector<TimeDuration, 0, SystemAllocPolicy> sccTimes; Loading
js/src/tests/shell/gcstats.js +1 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ garbage(); setGCCallback({ action: "majorGC", depth: 10, depth: 8, phases: "begin" }); Loading