blob: 80a192defdb13143dc58d0d91bf4d81164055dec [file] [log] [blame]
/* -*- 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 "jsfriendapi.h"
#include "jspubtd.h"
#include "js/GCAPI.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_TYPES,
PHASE_MARK_DELAYED,
PHASE_SWEEP,
PHASE_SWEEP_MARK,
PHASE_SWEEP_MARK_TYPES,
PHASE_SWEEP_MARK_DELAYED,
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_CLEAR_SCRIPT_ANALYSIS,
PHASE_SWEEP_OBJECT,
PHASE_SWEEP_STRING,
PHASE_SWEEP_SCRIPT,
PHASE_SWEEP_SHAPE,
PHASE_SWEEP_IONCODE,
PHASE_FINALIZE_END,
PHASE_DESTROY,
PHASE_GC_END,
PHASE_LIMIT
};
enum Stat {
STAT_NEW_CHUNK,
STAT_DESTROY_CHUNK,
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(NULL), 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<SliceData, 8, SystemAllocPolicy> 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<size_t> phaseNestingDepth;
/* Sweep times for SCCs of compartments. */
Vector<int64_t, 0, SystemAllocPolicy> 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 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
};
} /* namespace gcstats */
} /* namespace js */
#endif /* gc_Statistics_h */