// Sum up the time for a phase, including instances of the phase with different // parents. static int64_t SumPhase(Phase phase, const Statistics::PhaseTimeTable times) { int64_t sum = 0; for (auto i : MakeRange(Statistics::NumTimingArrays)) sum += times[i][phase]; return sum; }
Statistics::Statistics(JSRuntime* rt) : runtime(rt), startupTime(PRMJ_Now()), fp(nullptr), gcDepth(0), nonincrementalReason_(gc::AbortReason::None), timedGCStart(0), preBytes(0), maxPauseInInterval(0), phaseNestingDepth(0), activeDagSlot(PHASE_DAG_NONE), suspended(0), sliceCallback(nullptr), nurseryCollectionCallback(nullptr), aborted(false), enableProfiling_(false), sliceCount_(0) { PodArrayZero(phaseTotals); PodArrayZero(counts); PodArrayZero(phaseStartTimes); for (auto d : MakeRange(NumTimingArrays)) PodArrayZero(phaseTimes[d]); const char* env = getenv("MOZ_GCTIMER"); if (env) { if (strcmp(env, "none") == 0) { fp = nullptr; } else if (strcmp(env, "stdout") == 0) { fp = stdout; } else if (strcmp(env, "stderr") == 0) { fp = stderr; } else { fp = fopen(env, "a"); if (!fp) MOZ_CRASH("Failed to open MOZ_GCTIMER log file."); } } env = getenv("JS_GC_PROFILE"); if (env) { if (0 == strcmp(env, "help")) { fprintf(stderr, "JS_GC_PROFILE=N\n" "\tReport major GC's taking more than N milliseconds.\n"); exit(0); } enableProfiling_ = true; profileThreshold_ = atoi(env); } PodZero(&totalTimes_); }
void Statistics::endGC() { for (auto j : MakeRange(NumTimingArrays)) for (int i = 0; i < PHASE_LIMIT; i++) phaseTotals[j][i] += phaseTimes[j][i]; int64_t total, longest; gcDuration(&total, &longest); int64_t sccTotal, sccLongest; sccDurations(&sccTotal, &sccLongest); runtime->addTelemetry(JS_TELEMETRY_GC_IS_COMPARTMENTAL, !zoneStats.isCollectingAllZones()); runtime->addTelemetry(JS_TELEMETRY_GC_MS, t(total)); runtime->addTelemetry(JS_TELEMETRY_GC_MAX_PAUSE_MS, t(longest)); int64_t markTotal = SumPhase(PHASE_MARK, phaseTimes); int64_t markRootsTotal = SumPhase(PHASE_MARK_ROOTS, phaseTimes); runtime->addTelemetry(JS_TELEMETRY_GC_MARK_MS, t(markTotal)); runtime->addTelemetry(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP])); if (runtime->gc.isCompactingGc()) { runtime->addTelemetry(JS_TELEMETRY_GC_COMPACT_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_COMPACT])); } runtime->addTelemetry(JS_TELEMETRY_GC_MARK_ROOTS_MS, t(markRootsTotal)); runtime->addTelemetry(JS_TELEMETRY_GC_MARK_GRAY_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP_MARK_GRAY])); runtime->addTelemetry(JS_TELEMETRY_GC_NON_INCREMENTAL, !!nonincrementalReason_); runtime->addTelemetry(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gc.isIncrementalGCAllowed()); runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, t(sccTotal)); runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, t(sccLongest)); if (!aborted) { double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC); runtime->addTelemetry(JS_TELEMETRY_GC_MMU_50, mmu50 * 100); } if (fp) printStats(); // Clear the timers at the end of a GC because we accumulate time in // between GCs for some (which come before PHASE_GC_BEGIN in the list.) PodZero(&phaseStartTimes[PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN); for (size_t d = PHASE_DAG_NONE; d < NumTimingArrays; d++) PodZero(&phaseTimes[d][PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN); // Clear the OOM flag but only if we are not in a nested GC. if (gcDepth == 1) aborted = false; }
void Statistics::endGC() { for (auto j : MakeRange(NumTimingArrays)) for (int i = 0; i < PHASE_LIMIT; i++) phaseTotals[j][i] += phaseTimes[j][i]; int64_t total, longest; gcDuration(&total, &longest); int64_t sccTotal, sccLongest; sccDurations(&sccTotal, &sccLongest); runtime->addTelemetry(JS_TELEMETRY_GC_IS_ZONE_GC, !zoneStats.isCollectingAllZones()); runtime->addTelemetry(JS_TELEMETRY_GC_MS, t(total)); runtime->addTelemetry(JS_TELEMETRY_GC_MAX_PAUSE_MS, t(longest)); int64_t markTotal = SumPhase(PHASE_MARK, phaseTimes); int64_t markRootsTotal = SumPhase(PHASE_MARK_ROOTS, phaseTimes); runtime->addTelemetry(JS_TELEMETRY_GC_MARK_MS, t(markTotal)); runtime->addTelemetry(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP])); if (runtime->gc.isCompactingGc()) { runtime->addTelemetry(JS_TELEMETRY_GC_COMPACT_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_COMPACT])); } runtime->addTelemetry(JS_TELEMETRY_GC_MARK_ROOTS_MS, t(markRootsTotal)); runtime->addTelemetry(JS_TELEMETRY_GC_MARK_GRAY_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP_MARK_GRAY])); runtime->addTelemetry(JS_TELEMETRY_GC_NON_INCREMENTAL, nonincremental()); if (nonincremental()) runtime->addTelemetry(JS_TELEMETRY_GC_NON_INCREMENTAL_REASON, uint32_t(nonincrementalReason_)); runtime->addTelemetry(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gc.isIncrementalGCAllowed()); runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, t(sccTotal)); runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, t(sccLongest)); if (!aborted) { double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC); runtime->addTelemetry(JS_TELEMETRY_GC_MMU_50, mmu50 * 100); } if (fp) printStats(); // Clear the OOM flag but only if we are not in a nested GC. if (gcDepth == 1) aborted = false; }
Statistics::Statistics(JSRuntime* rt) : runtime(rt), startupTime(PRMJ_Now()), fp(nullptr), gcDepth(0), nonincrementalReason_(nullptr), timedGCStart(0), preBytes(0), maxPauseInInterval(0), phaseNestingDepth(0), activeDagSlot(PHASE_DAG_NONE), suspended(0), sliceCallback(nullptr), nurseryCollectionCallback(nullptr), aborted(false) { PodArrayZero(phaseTotals); PodArrayZero(counts); PodArrayZero(phaseStartTimes); for (auto d : MakeRange(NumTimingArrays)) PodArrayZero(phaseTimes[d]); char* env = getenv("MOZ_GCTIMER"); if (env) { if (strcmp(env, "none") == 0) { fp = nullptr; } else if (strcmp(env, "stdout") == 0) { fp = stdout; } else if (strcmp(env, "stderr") == 0) { fp = stderr; } else { fp = fopen(env, "a"); if (!fp) MOZ_CRASH("Failed to open MOZ_GCTIMER log file."); } } }
Statistics::Statistics(JSRuntime* rt) : runtime(rt), startupTime(PRMJ_Now()), fp(nullptr), gcDepth(0), nonincrementalReason_(nullptr), timedGCStart(0), preBytes(0), maxPauseInInterval(0), phaseNestingDepth(0), activeDagSlot(PHASE_DAG_NONE), suspendedPhaseNestingDepth(0), sliceCallback(nullptr), aborted(false) { PodArrayZero(phaseTotals); PodArrayZero(counts); PodArrayZero(phaseStartTimes); for (auto d : MakeRange(NumTimingArrays)) PodArrayZero(phaseTimes[d]); static bool initialized = false; if (!initialized) { initialized = true; for (size_t i = 0; i < PHASE_LIMIT; i++) { MOZ_ASSERT(phases[i].index == i); for (size_t j = 0; j < PHASE_LIMIT; j++) MOZ_ASSERT_IF(i != j, phases[i].telemetryBucket != phases[j].telemetryBucket); } // Create a static table of descendants for every phase with multiple // children. This assumes that all descendants come linearly in the // list, which is reasonable since full dags are not supported; any // path from the leaf to the root must encounter at most one node with // multiple parents. size_t dagSlot = 0; for (size_t i = 0; i < mozilla::ArrayLength(dagChildEdges); i++) { Phase parent = dagChildEdges[i].parent; if (!phaseExtra[parent].dagSlot) phaseExtra[parent].dagSlot = ++dagSlot; Phase child = dagChildEdges[i].child; MOZ_ASSERT(phases[child].parent == PHASE_MULTI_PARENTS); int j = child; do { dagDescendants[phaseExtra[parent].dagSlot].append(Phase(j)); j++; } while (j != PHASE_LIMIT && phases[j].parent != PHASE_MULTI_PARENTS); } MOZ_ASSERT(dagSlot <= MaxMultiparentPhases - 1); // Fill in the depth of each node in the tree. Multi-parented nodes // have depth 0. mozilla::Vector<Phase> stack; stack.append(PHASE_LIMIT); // Dummy entry to avoid special-casing the first node for (int i = 0; i < PHASE_LIMIT; i++) { if (phases[i].parent == PHASE_NO_PARENT || phases[i].parent == PHASE_MULTI_PARENTS) { stack.clear(); } else { while (stack.back() != phases[i].parent) stack.popBack(); } phaseExtra[i].depth = stack.length(); stack.append(Phase(i)); } } char* env = getenv("MOZ_GCTIMER"); if (env) { if (strcmp(env, "none") == 0) { fp = nullptr; } else if (strcmp(env, "stdout") == 0) { fp = stdout; } else if (strcmp(env, "stderr") == 0) { fp = stderr; } else { fp = fopen(env, "a"); if (!fp) MOZ_CRASH("Failed to open MOZ_GCTIMER log file."); } } }