diff -r 000000000000 -r 6474c204b198 js/src/gc/Statistics.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/src/gc/Statistics.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,256 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef gc_Statistics_h +#define gc_Statistics_h + +#include "mozilla/DebugOnly.h" +#include "mozilla/PodOperations.h" + +#include "jsalloc.h" +#include "jspubtd.h" + +#include "js/GCAPI.h" +#include "js/Vector.h" + +struct JSCompartment; + +namespace js { +namespace gcstats { + +enum Phase { + PHASE_GC_BEGIN, + PHASE_WAIT_BACKGROUND_THREAD, + PHASE_MARK_DISCARD_CODE, + PHASE_PURGE, + PHASE_MARK, + PHASE_MARK_ROOTS, + PHASE_MARK_DELAYED, + PHASE_SWEEP, + PHASE_SWEEP_MARK, + PHASE_SWEEP_MARK_TYPES, + PHASE_SWEEP_MARK_INCOMING_BLACK, + PHASE_SWEEP_MARK_WEAK, + PHASE_SWEEP_MARK_INCOMING_GRAY, + PHASE_SWEEP_MARK_GRAY, + PHASE_SWEEP_MARK_GRAY_WEAK, + PHASE_FINALIZE_START, + PHASE_SWEEP_ATOMS, + PHASE_SWEEP_COMPARTMENTS, + PHASE_SWEEP_DISCARD_CODE, + PHASE_SWEEP_TABLES, + PHASE_SWEEP_TABLES_WRAPPER, + PHASE_SWEEP_TABLES_BASE_SHAPE, + PHASE_SWEEP_TABLES_INITIAL_SHAPE, + PHASE_SWEEP_TABLES_TYPE_OBJECT, + PHASE_SWEEP_TABLES_BREAKPOINT, + PHASE_SWEEP_TABLES_REGEXP, + PHASE_DISCARD_ANALYSIS, + PHASE_DISCARD_TI, + PHASE_FREE_TI_ARENA, + PHASE_SWEEP_TYPES, + PHASE_SWEEP_OBJECT, + PHASE_SWEEP_STRING, + PHASE_SWEEP_SCRIPT, + PHASE_SWEEP_SHAPE, + PHASE_SWEEP_JITCODE, + PHASE_FINALIZE_END, + PHASE_DESTROY, + PHASE_GC_END, + + PHASE_LIMIT +}; + +enum Stat { + STAT_NEW_CHUNK, + STAT_DESTROY_CHUNK, + STAT_MINOR_GC, + + STAT_LIMIT +}; + +class StatisticsSerializer; + +struct Statistics { + Statistics(JSRuntime *rt); + ~Statistics(); + + void beginPhase(Phase phase); + void endPhase(Phase phase); + + void beginSlice(int collectedCount, int zoneCount, int compartmentCount, JS::gcreason::Reason reason); + void endSlice(); + + void reset(const char *reason) { slices.back().resetReason = reason; } + void nonincremental(const char *reason) { nonincrementalReason = reason; } + + void count(Stat s) { + JS_ASSERT(s < STAT_LIMIT); + counts[s]++; + } + + int64_t beginSCC(); + void endSCC(unsigned scc, int64_t start); + + jschar *formatMessage(); + jschar *formatJSON(uint64_t timestamp); + + private: + JSRuntime *runtime; + + int64_t startupTime; + + FILE *fp; + bool fullFormat; + + /* + * GCs can't really nest, but a second GC can be triggered from within the + * JSGC_END callback. + */ + int gcDepth; + + int collectedCount; + int zoneCount; + int compartmentCount; + const char *nonincrementalReason; + + struct SliceData { + SliceData(JS::gcreason::Reason reason, int64_t start, size_t startFaults) + : reason(reason), resetReason(nullptr), start(start), startFaults(startFaults) + { + mozilla::PodArrayZero(phaseTimes); + } + + JS::gcreason::Reason reason; + const char *resetReason; + int64_t start, end; + size_t startFaults, endFaults; + int64_t phaseTimes[PHASE_LIMIT]; + + int64_t duration() const { return end - start; } + }; + + Vector slices; + + /* Most recent time when the given phase started. */ + int64_t phaseStartTimes[PHASE_LIMIT]; + + /* Total time in a given phase for this GC. */ + int64_t phaseTimes[PHASE_LIMIT]; + + /* Total time in a given phase over all GCs. */ + int64_t phaseTotals[PHASE_LIMIT]; + + /* Number of events of this type for this GC. */ + unsigned int counts[STAT_LIMIT]; + + /* Allocated space before the GC started. */ + size_t preBytes; + +#ifdef DEBUG + /* Phases that are currently on stack. */ + static const size_t MAX_NESTING = 8; + Phase phaseNesting[MAX_NESTING]; +#endif + mozilla::DebugOnly phaseNestingDepth; + + /* Sweep times for SCCs of compartments. */ + Vector sccTimes; + + void beginGC(); + void endGC(); + + void gcDuration(int64_t *total, int64_t *maxPause); + void sccDurations(int64_t *total, int64_t *maxPause); + void printStats(); + bool formatData(StatisticsSerializer &ss, uint64_t timestamp); + + double computeMMU(int64_t resolution); +}; + +struct AutoGCSlice +{ + AutoGCSlice(Statistics &stats, int collectedCount, int zoneCount, int compartmentCount, + JS::gcreason::Reason reason + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : stats(stats) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + stats.beginSlice(collectedCount, zoneCount, compartmentCount, reason); + } + ~AutoGCSlice() { stats.endSlice(); } + + Statistics &stats; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +struct AutoPhase +{ + AutoPhase(Statistics &stats, Phase phase + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : stats(stats), phase(phase) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + stats.beginPhase(phase); + } + ~AutoPhase() { + stats.endPhase(phase); + } + + Statistics &stats; + Phase phase; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +struct MaybeAutoPhase +{ + MaybeAutoPhase(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) + : stats(nullptr) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + void construct(Statistics &statsArg, Phase phaseArg) + { + JS_ASSERT(!stats); + stats = &statsArg; + phase = phaseArg; + stats->beginPhase(phase); + } + ~MaybeAutoPhase() { + if (stats) + stats->endPhase(phase); + } + + Statistics *stats; + Phase phase; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +struct AutoSCC +{ + AutoSCC(Statistics &stats, unsigned scc + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : stats(stats), scc(scc) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + start = stats.beginSCC(); + } + ~AutoSCC() { + stats.endSCC(scc, start); + } + + Statistics &stats; + unsigned scc; + int64_t start; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +const char *ExplainReason(JS::gcreason::Reason reason); + +} /* namespace gcstats */ +} /* namespace js */ + +#endif /* gc_Statistics_h */