UniqueChars Statistics::formatPhaseTimes(int64_t (*phaseTimes)[PHASE_LIMIT]) { static const char* LevelToIndent[] = { "", " ", " ", " " }; static const int64_t MaxUnaccountedChildTimeUS = 50; FragmentVector fragments; char buffer[128]; for (AllPhaseIterator iter(phaseTimes); !iter.done(); iter.advance()) { Phase phase; size_t dagSlot; size_t level; iter.get(&phase, &dagSlot, &level); MOZ_ASSERT(level < 4); int64_t ownTime = phaseTimes[dagSlot][phase]; int64_t childTime = SumChildTimes(dagSlot, phase, phaseTimes); if (ownTime > 0) { JS_snprintf(buffer, sizeof(buffer), " %s%s: %.3fms\n", LevelToIndent[level], phases[phase].name, t(ownTime)); if (!fragments.append(make_string_copy(buffer))) return UniqueChars(nullptr); if (childTime && (ownTime - childTime) > MaxUnaccountedChildTimeUS) { MOZ_ASSERT(level < 3); JS_snprintf(buffer, sizeof(buffer), " %s%s: %.3fms\n", LevelToIndent[level + 1], "Other", t(ownTime - childTime)); if (!fragments.append(make_string_copy(buffer))) return UniqueChars(nullptr); } } } return Join(fragments); }
UniqueChars Statistics::formatCompactSlicePhaseTimes(const PhaseTimeTable phaseTimes) const { static const int64_t MaxUnaccountedTimeUS = 100; FragmentVector fragments; char buffer[128]; for (AllPhaseIterator iter(phaseTimes); !iter.done(); iter.advance()) { Phase phase; size_t dagSlot; size_t level; iter.get(&phase, &dagSlot, &level); MOZ_ASSERT(level < 4); int64_t ownTime = phaseTimes[dagSlot][phase]; int64_t childTime = SumChildTimes(dagSlot, phase, phaseTimes); if (ownTime > MaxUnaccountedTimeUS) { SprintfLiteral(buffer, "%s: %.3fms", phases[phase].name, t(ownTime)); if (!fragments.append(DuplicateString(buffer))) return UniqueChars(nullptr); if (childTime && (ownTime - childTime) > MaxUnaccountedTimeUS) { MOZ_ASSERT(level < 3); SprintfLiteral(buffer, "%s: %.3fms", "Other", t(ownTime - childTime)); if (!fragments.append(DuplicateString(buffer))) return UniqueChars(nullptr); } } } return Join(fragments, ", "); }
UniqueChars Statistics::formatCompactSliceMessage() const { // Skip if we OOM'ed. if (slices.length() == 0) return UniqueChars(nullptr); const size_t index = slices.length() - 1; const SliceData& slice = slices[index]; char budgetDescription[200]; slice.budget.describe(budgetDescription, sizeof(budgetDescription) - 1); const char* format = "GC Slice %u - Pause: %.3fms of %s budget (@ %.3fms); Reason: %s; Reset: %s%s; Times: "; char buffer[1024]; SprintfLiteral(buffer, format, index, t(slice.duration()), budgetDescription, t(slice.start - slices[0].start), ExplainReason(slice.reason), slice.wasReset() ? "yes - " : "no", slice.wasReset() ? ExplainAbortReason(slice.resetReason) : ""); FragmentVector fragments; if (!fragments.append(DuplicateString(buffer)) || !fragments.append(formatCompactSlicePhaseTimes(slices[index].phaseTimes))) { return UniqueChars(nullptr); } return Join(fragments); }
UniqueChars Statistics::formatCompactSummaryMessage() const { const double bytesPerMiB = 1024 * 1024; FragmentVector fragments; if (!fragments.append(DuplicateString("Summary - "))) return UniqueChars(nullptr); int64_t total, longest; gcDuration(&total, &longest); const double mmu20 = computeMMU(20 * PRMJ_USEC_PER_MSEC); const double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC); char buffer[1024]; if (!nonincremental()) { SprintfLiteral(buffer, "Max Pause: %.3fms; MMU 20ms: %.1f%%; MMU 50ms: %.1f%%; Total: %.3fms; ", t(longest), mmu20 * 100., mmu50 * 100., t(total)); } else { SprintfLiteral(buffer, "Non-Incremental: %.3fms (%s); ", t(total), ExplainAbortReason(nonincrementalReason_)); } if (!fragments.append(DuplicateString(buffer))) return UniqueChars(nullptr); SprintfLiteral(buffer, "Zones: %d of %d (-%d); Compartments: %d of %d (-%d); HeapSize: %.3f MiB; " \ "HeapChange (abs): %+d (%d); ", zoneStats.collectedZoneCount, zoneStats.zoneCount, zoneStats.sweptZoneCount, zoneStats.collectedCompartmentCount, zoneStats.compartmentCount, zoneStats.sweptCompartmentCount, double(preBytes) / bytesPerMiB, counts[STAT_NEW_CHUNK] - counts[STAT_DESTROY_CHUNK], counts[STAT_NEW_CHUNK] + counts[STAT_DESTROY_CHUNK]); if (!fragments.append(DuplicateString(buffer))) return UniqueChars(nullptr); MOZ_ASSERT_IF(counts[STAT_ARENA_RELOCATED], gckind == GC_SHRINK); if (gckind == GC_SHRINK) { SprintfLiteral(buffer, "Kind: %s; Relocated: %.3f MiB; ", ExplainInvocationKind(gckind), double(ArenaSize * counts[STAT_ARENA_RELOCATED]) / bytesPerMiB); if (!fragments.append(DuplicateString(buffer))) return UniqueChars(nullptr); } return Join(fragments); }
UniqueChars Statistics::formatDetailedMessage() { FragmentVector fragments; if (!fragments.append(formatDescription())) return UniqueChars(nullptr); if (slices.length() > 1) { for (unsigned i = 0; i < slices.length(); i++) { if (!fragments.append(formatSliceDescription(i, slices[i]))) return UniqueChars(nullptr); if (!fragments.append(formatPhaseTimes(slices[i].phaseTimes))) return UniqueChars(nullptr); } } if (!fragments.append(formatTotals())) return UniqueChars(nullptr); if (!fragments.append(formatPhaseTimes(phaseTimes))) return UniqueChars(nullptr); return Join(fragments); }
UniqueChars Statistics::formatPhaseTimes(int64_t *phaseTimes) { static const char *LevelToIndent[] = { "", " ", " ", " " }; static const int64_t MaxUnaccountedChildTimeUS = 50; FragmentVector fragments; char buffer[128]; for (unsigned i = 0; phases[i].name; i++) { unsigned level = 0; unsigned current = i; while (phases[current].parent != PHASE_NO_PARENT) { current = phases[current].parent; level++; } MOZ_ASSERT(level < 4); int64_t ownTime = phaseTimes[phases[i].index]; int64_t childTime = SumChildTimes(Phase(i), phaseTimes); if (ownTime > 0) { JS_snprintf(buffer, sizeof(buffer), " %s%s: %.3fms\n", LevelToIndent[level], phases[i].name, t(ownTime)); if (!fragments.append(make_string_copy(buffer))) return UniqueChars(nullptr); if (childTime && (ownTime - childTime) > MaxUnaccountedChildTimeUS) { MOZ_ASSERT(level < 3); JS_snprintf(buffer, sizeof(buffer), " %s%s: %.3fms\n", LevelToIndent[level + 1], "Other", t(ownTime - childTime)); if (!fragments.append(make_string_copy(buffer))) return UniqueChars(nullptr); } } } return Join(fragments); }
UniqueChars Statistics::formatJsonPhaseTimes(const PhaseTimeTable phaseTimes) { FragmentVector fragments; char buffer[128]; for (AllPhaseIterator iter(phaseTimes); !iter.done(); iter.advance()) { Phase phase; size_t dagSlot; iter.get(&phase, &dagSlot); UniqueChars name = FilterJsonKey(phases[phase].name); int64_t ownTime = phaseTimes[dagSlot][phase]; JS_snprintf(buffer, sizeof(buffer), "\"%s\":%llu.%03llu", name.get(), ownTime / 1000, ownTime % 1000); if (!fragments.append(DuplicateString(buffer))) return UniqueChars(nullptr); } return Join(fragments, ","); }
UniqueChars Statistics::formatJsonMessage(uint64_t timestamp) { MOZ_ASSERT(!aborted); FragmentVector fragments; if (!fragments.append(DuplicateString("{")) || !fragments.append(formatJsonDescription(timestamp)) || !fragments.append(DuplicateString("\"slices\":["))) { return UniqueChars(nullptr); } for (unsigned i = 0; i < slices.length(); i++) { if (!fragments.append(DuplicateString("{")) || !fragments.append(formatJsonSliceDescription(i, slices[i])) || !fragments.append(DuplicateString("\"times\":{")) || !fragments.append(formatJsonPhaseTimes(slices[i].phaseTimes)) || !fragments.append(DuplicateString("}}")) || (i < (slices.length() - 1) && !fragments.append(DuplicateString(",")))) { return UniqueChars(nullptr); } } if (!fragments.append(DuplicateString("],\"totals\":{")) || !fragments.append(formatJsonPhaseTimes(phaseTimes)) || !fragments.append(DuplicateString("}}"))) { return UniqueChars(nullptr); } return Join(fragments); }