1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/gc/Statistics.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,256 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef gc_Statistics_h 1.11 +#define gc_Statistics_h 1.12 + 1.13 +#include "mozilla/DebugOnly.h" 1.14 +#include "mozilla/PodOperations.h" 1.15 + 1.16 +#include "jsalloc.h" 1.17 +#include "jspubtd.h" 1.18 + 1.19 +#include "js/GCAPI.h" 1.20 +#include "js/Vector.h" 1.21 + 1.22 +struct JSCompartment; 1.23 + 1.24 +namespace js { 1.25 +namespace gcstats { 1.26 + 1.27 +enum Phase { 1.28 + PHASE_GC_BEGIN, 1.29 + PHASE_WAIT_BACKGROUND_THREAD, 1.30 + PHASE_MARK_DISCARD_CODE, 1.31 + PHASE_PURGE, 1.32 + PHASE_MARK, 1.33 + PHASE_MARK_ROOTS, 1.34 + PHASE_MARK_DELAYED, 1.35 + PHASE_SWEEP, 1.36 + PHASE_SWEEP_MARK, 1.37 + PHASE_SWEEP_MARK_TYPES, 1.38 + PHASE_SWEEP_MARK_INCOMING_BLACK, 1.39 + PHASE_SWEEP_MARK_WEAK, 1.40 + PHASE_SWEEP_MARK_INCOMING_GRAY, 1.41 + PHASE_SWEEP_MARK_GRAY, 1.42 + PHASE_SWEEP_MARK_GRAY_WEAK, 1.43 + PHASE_FINALIZE_START, 1.44 + PHASE_SWEEP_ATOMS, 1.45 + PHASE_SWEEP_COMPARTMENTS, 1.46 + PHASE_SWEEP_DISCARD_CODE, 1.47 + PHASE_SWEEP_TABLES, 1.48 + PHASE_SWEEP_TABLES_WRAPPER, 1.49 + PHASE_SWEEP_TABLES_BASE_SHAPE, 1.50 + PHASE_SWEEP_TABLES_INITIAL_SHAPE, 1.51 + PHASE_SWEEP_TABLES_TYPE_OBJECT, 1.52 + PHASE_SWEEP_TABLES_BREAKPOINT, 1.53 + PHASE_SWEEP_TABLES_REGEXP, 1.54 + PHASE_DISCARD_ANALYSIS, 1.55 + PHASE_DISCARD_TI, 1.56 + PHASE_FREE_TI_ARENA, 1.57 + PHASE_SWEEP_TYPES, 1.58 + PHASE_SWEEP_OBJECT, 1.59 + PHASE_SWEEP_STRING, 1.60 + PHASE_SWEEP_SCRIPT, 1.61 + PHASE_SWEEP_SHAPE, 1.62 + PHASE_SWEEP_JITCODE, 1.63 + PHASE_FINALIZE_END, 1.64 + PHASE_DESTROY, 1.65 + PHASE_GC_END, 1.66 + 1.67 + PHASE_LIMIT 1.68 +}; 1.69 + 1.70 +enum Stat { 1.71 + STAT_NEW_CHUNK, 1.72 + STAT_DESTROY_CHUNK, 1.73 + STAT_MINOR_GC, 1.74 + 1.75 + STAT_LIMIT 1.76 +}; 1.77 + 1.78 +class StatisticsSerializer; 1.79 + 1.80 +struct Statistics { 1.81 + Statistics(JSRuntime *rt); 1.82 + ~Statistics(); 1.83 + 1.84 + void beginPhase(Phase phase); 1.85 + void endPhase(Phase phase); 1.86 + 1.87 + void beginSlice(int collectedCount, int zoneCount, int compartmentCount, JS::gcreason::Reason reason); 1.88 + void endSlice(); 1.89 + 1.90 + void reset(const char *reason) { slices.back().resetReason = reason; } 1.91 + void nonincremental(const char *reason) { nonincrementalReason = reason; } 1.92 + 1.93 + void count(Stat s) { 1.94 + JS_ASSERT(s < STAT_LIMIT); 1.95 + counts[s]++; 1.96 + } 1.97 + 1.98 + int64_t beginSCC(); 1.99 + void endSCC(unsigned scc, int64_t start); 1.100 + 1.101 + jschar *formatMessage(); 1.102 + jschar *formatJSON(uint64_t timestamp); 1.103 + 1.104 + private: 1.105 + JSRuntime *runtime; 1.106 + 1.107 + int64_t startupTime; 1.108 + 1.109 + FILE *fp; 1.110 + bool fullFormat; 1.111 + 1.112 + /* 1.113 + * GCs can't really nest, but a second GC can be triggered from within the 1.114 + * JSGC_END callback. 1.115 + */ 1.116 + int gcDepth; 1.117 + 1.118 + int collectedCount; 1.119 + int zoneCount; 1.120 + int compartmentCount; 1.121 + const char *nonincrementalReason; 1.122 + 1.123 + struct SliceData { 1.124 + SliceData(JS::gcreason::Reason reason, int64_t start, size_t startFaults) 1.125 + : reason(reason), resetReason(nullptr), start(start), startFaults(startFaults) 1.126 + { 1.127 + mozilla::PodArrayZero(phaseTimes); 1.128 + } 1.129 + 1.130 + JS::gcreason::Reason reason; 1.131 + const char *resetReason; 1.132 + int64_t start, end; 1.133 + size_t startFaults, endFaults; 1.134 + int64_t phaseTimes[PHASE_LIMIT]; 1.135 + 1.136 + int64_t duration() const { return end - start; } 1.137 + }; 1.138 + 1.139 + Vector<SliceData, 8, SystemAllocPolicy> slices; 1.140 + 1.141 + /* Most recent time when the given phase started. */ 1.142 + int64_t phaseStartTimes[PHASE_LIMIT]; 1.143 + 1.144 + /* Total time in a given phase for this GC. */ 1.145 + int64_t phaseTimes[PHASE_LIMIT]; 1.146 + 1.147 + /* Total time in a given phase over all GCs. */ 1.148 + int64_t phaseTotals[PHASE_LIMIT]; 1.149 + 1.150 + /* Number of events of this type for this GC. */ 1.151 + unsigned int counts[STAT_LIMIT]; 1.152 + 1.153 + /* Allocated space before the GC started. */ 1.154 + size_t preBytes; 1.155 + 1.156 +#ifdef DEBUG 1.157 + /* Phases that are currently on stack. */ 1.158 + static const size_t MAX_NESTING = 8; 1.159 + Phase phaseNesting[MAX_NESTING]; 1.160 +#endif 1.161 + mozilla::DebugOnly<size_t> phaseNestingDepth; 1.162 + 1.163 + /* Sweep times for SCCs of compartments. */ 1.164 + Vector<int64_t, 0, SystemAllocPolicy> sccTimes; 1.165 + 1.166 + void beginGC(); 1.167 + void endGC(); 1.168 + 1.169 + void gcDuration(int64_t *total, int64_t *maxPause); 1.170 + void sccDurations(int64_t *total, int64_t *maxPause); 1.171 + void printStats(); 1.172 + bool formatData(StatisticsSerializer &ss, uint64_t timestamp); 1.173 + 1.174 + double computeMMU(int64_t resolution); 1.175 +}; 1.176 + 1.177 +struct AutoGCSlice 1.178 +{ 1.179 + AutoGCSlice(Statistics &stats, int collectedCount, int zoneCount, int compartmentCount, 1.180 + JS::gcreason::Reason reason 1.181 + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) 1.182 + : stats(stats) 1.183 + { 1.184 + MOZ_GUARD_OBJECT_NOTIFIER_INIT; 1.185 + stats.beginSlice(collectedCount, zoneCount, compartmentCount, reason); 1.186 + } 1.187 + ~AutoGCSlice() { stats.endSlice(); } 1.188 + 1.189 + Statistics &stats; 1.190 + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER 1.191 +}; 1.192 + 1.193 +struct AutoPhase 1.194 +{ 1.195 + AutoPhase(Statistics &stats, Phase phase 1.196 + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) 1.197 + : stats(stats), phase(phase) 1.198 + { 1.199 + MOZ_GUARD_OBJECT_NOTIFIER_INIT; 1.200 + stats.beginPhase(phase); 1.201 + } 1.202 + ~AutoPhase() { 1.203 + stats.endPhase(phase); 1.204 + } 1.205 + 1.206 + Statistics &stats; 1.207 + Phase phase; 1.208 + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER 1.209 +}; 1.210 + 1.211 +struct MaybeAutoPhase 1.212 +{ 1.213 + MaybeAutoPhase(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) 1.214 + : stats(nullptr) 1.215 + { 1.216 + MOZ_GUARD_OBJECT_NOTIFIER_INIT; 1.217 + } 1.218 + void construct(Statistics &statsArg, Phase phaseArg) 1.219 + { 1.220 + JS_ASSERT(!stats); 1.221 + stats = &statsArg; 1.222 + phase = phaseArg; 1.223 + stats->beginPhase(phase); 1.224 + } 1.225 + ~MaybeAutoPhase() { 1.226 + if (stats) 1.227 + stats->endPhase(phase); 1.228 + } 1.229 + 1.230 + Statistics *stats; 1.231 + Phase phase; 1.232 + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER 1.233 +}; 1.234 + 1.235 +struct AutoSCC 1.236 +{ 1.237 + AutoSCC(Statistics &stats, unsigned scc 1.238 + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) 1.239 + : stats(stats), scc(scc) 1.240 + { 1.241 + MOZ_GUARD_OBJECT_NOTIFIER_INIT; 1.242 + start = stats.beginSCC(); 1.243 + } 1.244 + ~AutoSCC() { 1.245 + stats.endSCC(scc, start); 1.246 + } 1.247 + 1.248 + Statistics &stats; 1.249 + unsigned scc; 1.250 + int64_t start; 1.251 + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER 1.252 +}; 1.253 + 1.254 +const char *ExplainReason(JS::gcreason::Reason reason); 1.255 + 1.256 +} /* namespace gcstats */ 1.257 +} /* namespace js */ 1.258 + 1.259 +#endif /* gc_Statistics_h */