Bug 1335413 - Use mozilla array containers in GC statistics code r=sfink

This commit is contained in:
Jon Coppeard 2017-02-01 14:10:44 +00:00
Родитель 246770dae0
Коммит 132610707a
2 изменённых файлов: 74 добавлений и 49 удалений

Просмотреть файл

@ -44,6 +44,12 @@ using mozilla::TimeDuration;
*/
JS_STATIC_ASSERT(JS::gcreason::NUM_TELEMETRY_REASONS >= JS::gcreason::NUM_REASONS);
static inline decltype(mozilla::MakeEnumeratedRange(PHASE_FIRST, PHASE_LIMIT))
AllPhases()
{
return mozilla::MakeEnumeratedRange(PHASE_FIRST, PHASE_LIMIT);
}
const char*
js::gcstats::ExplainInvocationKind(JSGCInvocationKind gckind)
{
@ -114,6 +120,8 @@ struct ExtraPhaseInfo
// Index into the set of parallel arrays of timing data, for parents with
// at least one multi-parented child
size_t dagSlot;
ExtraPhaseInfo() : depth(0), dagSlot(0) {}
};
static const Phase PHASE_NO_PARENT = PHASE_LIMIT;
@ -210,7 +218,7 @@ static const PhaseInfo phases[] = {
// numbers.
};
static ExtraPhaseInfo phaseExtra[PHASE_LIMIT] = { { 0, 0 } };
static mozilla::EnumeratedArray<Phase, PHASE_LIMIT, ExtraPhaseInfo> phaseExtra;
// Mapping from all nodes with a multi-parented child to a Vector of all
// multi-parented children and their descendants. (Single-parented children will
@ -237,7 +245,7 @@ struct AllPhaseIterator {
// subtree nodes.
mozilla::Vector<Phase, 0, SystemAllocPolicy>::Range descendants;
explicit AllPhaseIterator(const Statistics::PhaseTimeTable table)
explicit AllPhaseIterator()
: current(0)
, baseLevel(0)
, activeSlot(PHASE_DAG_NONE)
@ -271,13 +279,14 @@ struct AllPhaseIterator {
return;
}
if (phaseExtra[current].dagSlot != PHASE_DAG_NONE) {
auto phase = Phase(current);
if (phaseExtra[phase].dagSlot != PHASE_DAG_NONE) {
// The current phase has a shared subtree. Load them up into
// 'descendants' and advance to the first child.
activeSlot = phaseExtra[current].dagSlot;
activeSlot = phaseExtra[phase].dagSlot;
descendants = dagDescendants[activeSlot].all();
MOZ_ASSERT(!descendants.empty());
baseLevel += phaseExtra[current].depth + 1;
baseLevel += phaseExtra[phase].depth + 1;
return;
}
@ -343,18 +352,19 @@ Join(const FragmentVector& fragments, const char* separator = "") {
}
static TimeDuration
SumChildTimes(size_t phaseSlot, Phase phase, const Statistics::PhaseTimeTable phaseTimes)
SumChildTimes(size_t phaseSlot, Phase phase, const Statistics::PhaseTimeTable& phaseTimes)
{
// Sum the contributions from single-parented children.
TimeDuration total = 0;
size_t depth = phaseExtra[phase].depth;
for (unsigned i = phase + 1; i < PHASE_LIMIT && phaseExtra[i].depth > depth; i++) {
for (unsigned i = phase + 1; i < PHASE_LIMIT && phaseExtra[Phase(i)].depth > depth; i++) {
if (phases[i].parent == phase)
total += phaseTimes[phaseSlot][i];
total += phaseTimes[phaseSlot][Phase(i)];
}
// Sum the contributions from multi-parented children.
size_t dagSlot = phaseExtra[phase].dagSlot;
MOZ_ASSERT(dagSlot <= Statistics::MaxMultiparentPhases - 1);
if (dagSlot != PHASE_DAG_NONE) {
for (auto edge : dagChildEdges) {
if (edge.parent == phase)
@ -448,13 +458,13 @@ Statistics::formatCompactSummaryMessage() const
}
UniqueChars
Statistics::formatCompactSlicePhaseTimes(const PhaseTimeTable phaseTimes) const
Statistics::formatCompactSlicePhaseTimes(const PhaseTimeTable& phaseTimes) const
{
static const TimeDuration MaxUnaccountedTime = TimeDuration::FromMicroseconds(100);
FragmentVector fragments;
char buffer[128];
for (AllPhaseIterator iter(phaseTimes); !iter.done(); iter.advance()) {
for (AllPhaseIterator iter; !iter.done(); iter.advance()) {
Phase phase;
size_t dagSlot;
size_t level;
@ -575,14 +585,14 @@ Statistics::formatDetailedSliceDescription(unsigned i, const SliceData& slice)
}
UniqueChars
Statistics::formatDetailedPhaseTimes(const PhaseTimeTable phaseTimes)
Statistics::formatDetailedPhaseTimes(const PhaseTimeTable& phaseTimes)
{
static const char* LevelToIndent[] = { "", " ", " ", " " };
static const TimeDuration MaxUnaccountedChildTime = TimeDuration::FromMicroseconds(50);
FragmentVector fragments;
char buffer[128];
for (AllPhaseIterator iter(phaseTimes); !iter.done(); iter.advance()) {
for (AllPhaseIterator iter; !iter.done(); iter.advance()) {
Phase phase;
size_t dagSlot;
size_t level;
@ -781,11 +791,11 @@ FilterJsonKey(const char*const buffer)
}
UniqueChars
Statistics::formatJsonPhaseTimes(const PhaseTimeTable phaseTimes)
Statistics::formatJsonPhaseTimes(const PhaseTimeTable& phaseTimes)
{
FragmentVector fragments;
char buffer[128];
for (AllPhaseIterator iter(phaseTimes); !iter.done(); iter.advance()) {
for (AllPhaseIterator iter; !iter.done(); iter.advance()) {
Phase phase;
size_t dagSlot;
iter.get(&phase, &dagSlot);
@ -819,11 +829,8 @@ Statistics::Statistics(JSRuntime* rt)
enableProfiling_(false),
sliceCount_(0)
{
PodArrayZero(phaseTotals);
PodArrayZero(counts);
PodArrayZero(phaseStartTimes);
for (auto& phaseTime : phaseTimes)
PodArrayZero(phaseTime);
for (auto& count : counts)
count = 0;
const char* env = getenv("MOZ_GCTIMER");
if (env) {
@ -863,9 +870,9 @@ Statistics::~Statistics()
/* static */ bool
Statistics::initialize()
{
for (size_t i = 0; i < PHASE_LIMIT; i++) {
for (auto i : AllPhases()) {
MOZ_ASSERT(phases[i].index == i);
for (size_t j = 0; j < PHASE_LIMIT; j++)
for (auto j : AllPhases())
MOZ_ASSERT_IF(i != j, phases[i].telemetryBucket != phases[j].telemetryBucket);
}
@ -896,7 +903,7 @@ Statistics::initialize()
mozilla::Vector<Phase, 0, SystemAllocPolicy> stack;
if (!stack.append(PHASE_LIMIT)) // Dummy entry to avoid special-casing the first node
return false;
for (int i = 0; i < PHASE_LIMIT; i++) {
for (auto i : AllPhases()) {
if (phases[i].parent == PHASE_NO_PARENT ||
phases[i].parent == PHASE_MULTI_PARENTS)
{
@ -906,7 +913,7 @@ Statistics::initialize()
stack.popBack();
}
phaseExtra[i].depth = stack.length();
if (!stack.append(Phase(i)))
if (!stack.append(i))
return false;
}
@ -974,11 +981,11 @@ LongestPhaseSelfTime(const Statistics::PhaseTimeTable& times)
TimeDuration selfTimes[PHASE_LIMIT];
// Start with total times, including children's times.
for (size_t i = 0; i < PHASE_LIMIT; ++i)
selfTimes[i] = SumPhase(Phase(i), times);
for (auto i : AllPhases())
selfTimes[i] = SumPhase(i, times);
// Subtract out the children's times.
for (size_t i = 0; i < PHASE_LIMIT; ++i) {
for (auto i : AllPhases()) {
Phase parent = phases[i].parent;
if (parent == PHASE_MULTI_PARENTS) {
// Subtract out only the time for the children specific to this
@ -986,6 +993,7 @@ LongestPhaseSelfTime(const Statistics::PhaseTimeTable& times)
for (auto edge : dagChildEdges) {
if (edge.parent == parent) {
size_t dagSlot = phaseExtra[edge.parent].dagSlot;
MOZ_ASSERT(dagSlot <= Statistics::MaxMultiparentPhases - 1);
CheckSelfTime(parent, edge.child, times, selfTimes, times[dagSlot][edge.child]);
MOZ_ASSERT(selfTimes[parent] >= times[dagSlot][edge.child]);
selfTimes[parent] -= times[dagSlot][edge.child];
@ -993,17 +1001,17 @@ LongestPhaseSelfTime(const Statistics::PhaseTimeTable& times)
}
} else if (parent != PHASE_NO_PARENT) {
MOZ_ASSERT(selfTimes[parent] >= selfTimes[i]);
CheckSelfTime(parent, Phase(i), times, selfTimes, selfTimes[i]);
CheckSelfTime(parent, i, times, selfTimes, selfTimes[i]);
selfTimes[parent] -= selfTimes[i];
}
}
TimeDuration longestTime = 0;
Phase longestPhase = PHASE_NONE;
for (size_t i = 0; i < PHASE_LIMIT; ++i) {
for (auto i : AllPhases()) {
if (selfTimes[i] > longestTime) {
longestTime = selfTimes[i];
longestPhase = Phase(i);
longestPhase = i;
}
}
@ -1042,7 +1050,7 @@ void
Statistics::endGC()
{
for (auto j : IntegerRange(NumTimingArrays)) {
for (int i = 0; i < PHASE_LIMIT; i++)
for (auto i : AllPhases())
phaseTotals[j][i] += phaseTimes[j][i];
}
@ -1116,8 +1124,12 @@ Statistics::beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
if (first)
beginGC(gckind);
SliceData data(budget, reason, TimeStamp::Now(), GetPageFaultCount(), runtime->gc.state());
if (!slices.append(data)) {
if (!slices.emplaceBack(budget,
reason,
TimeStamp::Now(),
GetPageFaultCount(),
runtime->gc.state()))
{
// If we are OOM, set a flag to indicate we have missing slice data.
aborted = true;
return;
@ -1181,7 +1193,8 @@ Statistics::endSlice()
// Do this after the slice callback since it uses these values.
if (last) {
PodArrayZero(counts);
for (auto& count : counts)
count = 0;
// 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.)
@ -1279,8 +1292,11 @@ Statistics::beginPhase(Phase phase)
phaseNesting[phaseNestingDepth] = phase;
phaseNestingDepth++;
if (phases[phase].parent == PHASE_MULTI_PARENTS)
if (phases[phase].parent == PHASE_MULTI_PARENTS) {
MOZ_ASSERT(parent != PHASE_NO_PARENT);
activeDagSlot = phaseExtra[parent].dagSlot;
}
MOZ_ASSERT(activeDagSlot <= MaxMultiparentPhases - 1);
phaseStartTimes[phase] = TimeStamp::Now();
}

Просмотреть файл

@ -7,6 +7,7 @@
#ifndef gc_Statistics_h
#define gc_Statistics_h
#include "mozilla/Array.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/IntegerRange.h"
#include "mozilla/Maybe.h"
@ -28,7 +29,9 @@ class GCParallelTask;
namespace gcstats {
enum Phase : uint8_t {
PHASE_MUTATOR,
PHASE_FIRST,
PHASE_MUTATOR = PHASE_FIRST,
PHASE_GC_BEGIN,
PHASE_WAIT_BACKGROUND_THREAD,
PHASE_MARK_DISCARD_CODE,
@ -170,6 +173,12 @@ const char* ExplainInvocationKind(JSGCInvocationKind gckind);
*/
struct Statistics
{
template <typename T, size_t Length>
using Array = mozilla::Array<T, Length>;
template <typename IndexType, IndexType SizeAsEnumValue, typename ValueType>
using EnumeratedArray = mozilla::EnumeratedArray<IndexType, SizeAsEnumValue, ValueType>;
using TimeDuration = mozilla::TimeDuration;
using TimeStamp = mozilla::TimeStamp;
@ -191,13 +200,17 @@ struct Statistics
static const size_t NumTimingArrays = MaxMultiparentPhases + 1;
/* Create a convenient type for referring to tables of phase times. */
using PhaseTimeTable = TimeDuration[NumTimingArrays][PHASE_LIMIT];
using PhaseTimeTable =
Array<EnumeratedArray<Phase, PHASE_LIMIT, TimeDuration>, NumTimingArrays>;
static MOZ_MUST_USE bool initialize();
explicit Statistics(JSRuntime* rt);
~Statistics();
Statistics(const Statistics&) = delete;
Statistics& operator=(const Statistics&) = delete;
void beginPhase(Phase phase);
void endPhase(Phase phase);
void endParallelPhase(Phase phase, const GCParallelTask* task);
@ -290,10 +303,7 @@ struct Statistics
resetReason(gc::AbortReason::None),
start(start),
startFaults(startFaults)
{
for (auto i : mozilla::IntegerRange(NumTimingArrays))
mozilla::PodArrayZero(phaseTimes[i]);
}
{}
SliceBudget budget;
JS::gcreason::Reason reason;
@ -337,7 +347,7 @@ struct Statistics
SliceDataVector slices;
/* Most recent time when the given phase started. */
TimeStamp phaseStartTimes[PHASE_LIMIT];
EnumeratedArray<Phase, PHASE_LIMIT, TimeStamp> phaseStartTimes;
/* Bookkeeping for GC timings when timingMutator is true */
TimeStamp timedGCStart;
@ -350,7 +360,7 @@ struct Statistics
PhaseTimeTable phaseTotals;
/* Number of events of this type for this GC. */
unsigned int counts[STAT_LIMIT];
EnumeratedArray<Stat, STAT_LIMIT, unsigned int> counts;
/* Allocated space before the GC started. */
size_t preBytes;
@ -359,7 +369,7 @@ struct Statistics
mutable TimeDuration maxPauseInInterval;
/* Phases that are currently on stack. */
Phase phaseNesting[MAX_NESTING];
Array<Phase, MAX_NESTING> phaseNesting;
size_t phaseNestingDepth;
size_t activeDagSlot;
@ -370,7 +380,7 @@ struct Statistics
* suspensions by suspending multiple stacks with a PHASE_SUSPENSION in
* between).
*/
Phase suspendedPhases[MAX_NESTING * 3];
Array<Phase, MAX_NESTING * 3> suspendedPhases;
size_t suspended;
/* Sweep times for SCCs of compartments. */
@ -397,8 +407,7 @@ FOR_EACH_GC_PROFILE_TIME(DEFINE_TIME_KEY)
KeyCount
};
using ProfileDurations =
mozilla::EnumeratedArray<ProfileKey, ProfileKey::KeyCount, TimeDuration>;
using ProfileDurations = EnumeratedArray<ProfileKey, ProfileKey::KeyCount, TimeDuration>;
TimeDuration profileThreshold_;
bool enableProfiling_;
@ -414,16 +423,16 @@ FOR_EACH_GC_PROFILE_TIME(DEFINE_TIME_KEY)
void sccDurations(TimeDuration* total, TimeDuration* maxPause);
void printStats();
UniqueChars formatCompactSlicePhaseTimes(const PhaseTimeTable phaseTimes) const;
UniqueChars formatCompactSlicePhaseTimes(const PhaseTimeTable& phaseTimes) const;
UniqueChars formatDetailedDescription();
UniqueChars formatDetailedSliceDescription(unsigned i, const SliceData& slice);
UniqueChars formatDetailedPhaseTimes(const PhaseTimeTable phaseTimes);
UniqueChars formatDetailedPhaseTimes(const PhaseTimeTable& phaseTimes);
UniqueChars formatDetailedTotals();
UniqueChars formatJsonDescription(uint64_t timestamp);
UniqueChars formatJsonSliceDescription(unsigned i, const SliceData& slice);
UniqueChars formatJsonPhaseTimes(const PhaseTimeTable phaseTimes);
UniqueChars formatJsonPhaseTimes(const PhaseTimeTable& phaseTimes);
double computeMMU(TimeDuration resolution) const;