1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/public/MemoryMetrics.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,665 @@ 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 js_MemoryMetrics_h 1.11 +#define js_MemoryMetrics_h 1.12 + 1.13 +// These declarations are highly likely to change in the future. Depend on them 1.14 +// at your own risk. 1.15 + 1.16 +#include "mozilla/MemoryReporting.h" 1.17 +#include "mozilla/NullPtr.h" 1.18 +#include "mozilla/PodOperations.h" 1.19 + 1.20 +#include <string.h> 1.21 + 1.22 +#include "jsalloc.h" 1.23 +#include "jspubtd.h" 1.24 + 1.25 +#include "js/HashTable.h" 1.26 +#include "js/Utility.h" 1.27 +#include "js/Vector.h" 1.28 + 1.29 +class nsISupports; // Needed for ObjectPrivateVisitor. 1.30 + 1.31 +namespace JS { 1.32 + 1.33 +struct TabSizes 1.34 +{ 1.35 + enum Kind { 1.36 + Objects, 1.37 + Strings, 1.38 + Private, 1.39 + Other 1.40 + }; 1.41 + 1.42 + TabSizes() { mozilla::PodZero(this); } 1.43 + 1.44 + void add(Kind kind, size_t n) { 1.45 + switch (kind) { 1.46 + case Objects: objects += n; break; 1.47 + case Strings: strings += n; break; 1.48 + case Private: private_ += n; break; 1.49 + case Other: other += n; break; 1.50 + default: MOZ_CRASH("bad TabSizes kind"); 1.51 + } 1.52 + } 1.53 + 1.54 + size_t objects; 1.55 + size_t strings; 1.56 + size_t private_; 1.57 + size_t other; 1.58 +}; 1.59 + 1.60 +} // namespace JS 1.61 + 1.62 +namespace js { 1.63 + 1.64 +// In memory reporting, we have concept of "sundries", line items which are too 1.65 +// small to be worth reporting individually. Under some circumstances, a memory 1.66 +// reporter gets tossed into the sundries bucket if it's smaller than 1.67 +// MemoryReportingSundriesThreshold() bytes. 1.68 +// 1.69 +// We need to define this value here, rather than in the code which actually 1.70 +// generates the memory reports, because NotableStringInfo uses this value. 1.71 +JS_FRIEND_API(size_t) MemoryReportingSundriesThreshold(); 1.72 + 1.73 +// This hash policy avoids flattening ropes (which perturbs the site being 1.74 +// measured and requires a JSContext) at the expense of doing a FULL ROPE COPY 1.75 +// on every hash and match! Beware. 1.76 +struct InefficientNonFlatteningStringHashPolicy 1.77 +{ 1.78 + typedef JSString *Lookup; 1.79 + static HashNumber hash(const Lookup &l); 1.80 + static bool match(const JSString *const &k, const Lookup &l); 1.81 +}; 1.82 + 1.83 +struct CStringHashPolicy 1.84 +{ 1.85 + typedef const char *Lookup; 1.86 + static HashNumber hash(const Lookup &l); 1.87 + static bool match(const char *const &k, const Lookup &l); 1.88 +}; 1.89 + 1.90 +// This file features many classes with numerous size_t fields, and each such 1.91 +// class has one or more methods that need to operate on all of these fields. 1.92 +// Writing these individually is error-prone -- it's easy to add a new field 1.93 +// without updating all the required methods. So we define a single macro list 1.94 +// in each class to name the fields (and notable characteristics of them), and 1.95 +// then use the following macros to transform those lists into the required 1.96 +// methods. 1.97 +// 1.98 +// In some classes, one or more of the macro arguments aren't used. We use '_' 1.99 +// for those. 1.100 +// 1.101 +#define DECL_SIZE(kind, gc, mSize) size_t mSize; 1.102 +#define ZERO_SIZE(kind, gc, mSize) mSize(0), 1.103 +#define COPY_OTHER_SIZE(kind, gc, mSize) mSize(other.mSize), 1.104 +#define ADD_OTHER_SIZE(kind, gc, mSize) mSize += other.mSize; 1.105 +#define SUB_OTHER_SIZE(kind, gc, mSize) MOZ_ASSERT(mSize >= other.mSize); \ 1.106 + mSize -= other.mSize; 1.107 +#define ADD_SIZE_TO_N(kind, gc, mSize) n += mSize; 1.108 +#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(kind, gc, mSize) n += (js::gc) ? mSize : 0; 1.109 +#define ADD_TO_TAB_SIZES(kind, gc, mSize) sizes->add(JS::TabSizes::kind, mSize); 1.110 + 1.111 +// Used to annotate which size_t fields measure live GC things and which don't. 1.112 +enum { 1.113 + NotLiveGCThing = false, 1.114 + IsLiveGCThing = true 1.115 +}; 1.116 + 1.117 +} // namespace js 1.118 + 1.119 +namespace JS { 1.120 + 1.121 +// Data for tracking memory usage of things hanging off objects. 1.122 +struct ObjectsExtraSizes 1.123 +{ 1.124 +#define FOR_EACH_SIZE(macro) \ 1.125 + macro(Objects, NotLiveGCThing, mallocHeapSlots) \ 1.126 + macro(Objects, NotLiveGCThing, mallocHeapElementsNonAsmJS) \ 1.127 + macro(Objects, NotLiveGCThing, mallocHeapElementsAsmJS) \ 1.128 + macro(Objects, NotLiveGCThing, nonHeapElementsAsmJS) \ 1.129 + macro(Objects, NotLiveGCThing, nonHeapElementsMapped) \ 1.130 + macro(Objects, NotLiveGCThing, nonHeapCodeAsmJS) \ 1.131 + macro(Objects, NotLiveGCThing, mallocHeapAsmJSModuleData) \ 1.132 + macro(Objects, NotLiveGCThing, mallocHeapArgumentsData) \ 1.133 + macro(Objects, NotLiveGCThing, mallocHeapRegExpStatics) \ 1.134 + macro(Objects, NotLiveGCThing, mallocHeapPropertyIteratorData) \ 1.135 + macro(Objects, NotLiveGCThing, mallocHeapCtypesData) 1.136 + 1.137 + ObjectsExtraSizes() 1.138 + : FOR_EACH_SIZE(ZERO_SIZE) 1.139 + dummy() 1.140 + {} 1.141 + 1.142 + void add(const ObjectsExtraSizes &other) { 1.143 + FOR_EACH_SIZE(ADD_OTHER_SIZE) 1.144 + } 1.145 + 1.146 + size_t sizeOfLiveGCThings() const { 1.147 + size_t n = 0; 1.148 + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) 1.149 + return n; 1.150 + } 1.151 + 1.152 + void addToTabSizes(TabSizes *sizes) const { 1.153 + FOR_EACH_SIZE(ADD_TO_TAB_SIZES) 1.154 + } 1.155 + 1.156 + FOR_EACH_SIZE(DECL_SIZE) 1.157 + int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE) 1.158 + 1.159 +#undef FOR_EACH_SIZE 1.160 +}; 1.161 + 1.162 +// Data for tracking JIT-code memory usage. 1.163 +struct CodeSizes 1.164 +{ 1.165 +#define FOR_EACH_SIZE(macro) \ 1.166 + macro(_, _, ion) \ 1.167 + macro(_, _, baseline) \ 1.168 + macro(_, _, regexp) \ 1.169 + macro(_, _, other) \ 1.170 + macro(_, _, unused) 1.171 + 1.172 + CodeSizes() 1.173 + : FOR_EACH_SIZE(ZERO_SIZE) 1.174 + dummy() 1.175 + {} 1.176 + 1.177 + FOR_EACH_SIZE(DECL_SIZE) 1.178 + int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE) 1.179 + 1.180 +#undef FOR_EACH_SIZE 1.181 +}; 1.182 + 1.183 +// Data for tracking GC memory usage. 1.184 +struct GCSizes 1.185 +{ 1.186 +#define FOR_EACH_SIZE(macro) \ 1.187 + macro(_, _, marker) \ 1.188 + macro(_, _, nurseryCommitted) \ 1.189 + macro(_, _, nurseryDecommitted) \ 1.190 + macro(_, _, nurseryHugeSlots) \ 1.191 + macro(_, _, storeBufferVals) \ 1.192 + macro(_, _, storeBufferCells) \ 1.193 + macro(_, _, storeBufferSlots) \ 1.194 + macro(_, _, storeBufferWholeCells) \ 1.195 + macro(_, _, storeBufferRelocVals) \ 1.196 + macro(_, _, storeBufferRelocCells) \ 1.197 + macro(_, _, storeBufferGenerics) 1.198 + 1.199 + GCSizes() 1.200 + : FOR_EACH_SIZE(ZERO_SIZE) 1.201 + dummy() 1.202 + {} 1.203 + 1.204 + FOR_EACH_SIZE(DECL_SIZE) 1.205 + int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE) 1.206 + 1.207 +#undef FOR_EACH_SIZE 1.208 +}; 1.209 + 1.210 +// This class holds information about the memory taken up by identical copies of 1.211 +// a particular string. Multiple JSStrings may have their sizes aggregated 1.212 +// together into one StringInfo object. Note that two strings with identical 1.213 +// chars will not be aggregated together if one is a short string and the other 1.214 +// is not. 1.215 +struct StringInfo 1.216 +{ 1.217 +#define FOR_EACH_SIZE(macro) \ 1.218 + macro(Strings, IsLiveGCThing, gcHeap) \ 1.219 + macro(Strings, NotLiveGCThing, mallocHeap) \ 1.220 + 1.221 + StringInfo() 1.222 + : FOR_EACH_SIZE(ZERO_SIZE) 1.223 + numCopies(0) 1.224 + {} 1.225 + 1.226 + void add(const StringInfo &other) { 1.227 + FOR_EACH_SIZE(ADD_OTHER_SIZE); 1.228 + numCopies++; 1.229 + } 1.230 + 1.231 + void subtract(const StringInfo &other) { 1.232 + FOR_EACH_SIZE(SUB_OTHER_SIZE); 1.233 + numCopies--; 1.234 + } 1.235 + 1.236 + bool isNotable() const { 1.237 + static const size_t NotabilityThreshold = 16 * 1024; 1.238 + size_t n = 0; 1.239 + FOR_EACH_SIZE(ADD_SIZE_TO_N) 1.240 + return n >= NotabilityThreshold; 1.241 + } 1.242 + 1.243 + size_t sizeOfLiveGCThings() const { 1.244 + size_t n = 0; 1.245 + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) 1.246 + return n; 1.247 + } 1.248 + 1.249 + void addToTabSizes(TabSizes *sizes) const { 1.250 + FOR_EACH_SIZE(ADD_TO_TAB_SIZES) 1.251 + } 1.252 + 1.253 + FOR_EACH_SIZE(DECL_SIZE) 1.254 + uint32_t numCopies; // How many copies of the string have we seen? 1.255 + 1.256 +#undef FOR_EACH_SIZE 1.257 +}; 1.258 + 1.259 +// Holds data about a notable string (one which, counting all duplicates, uses 1.260 +// more than a certain amount of memory) so we can report it individually. 1.261 +// 1.262 +// The only difference between this class and StringInfo is that 1.263 +// NotableStringInfo holds a copy of some or all of the string's chars. 1.264 +struct NotableStringInfo : public StringInfo 1.265 +{ 1.266 + static const size_t MAX_SAVED_CHARS = 1024; 1.267 + 1.268 + NotableStringInfo(); 1.269 + NotableStringInfo(JSString *str, const StringInfo &info); 1.270 + NotableStringInfo(NotableStringInfo &&info); 1.271 + NotableStringInfo &operator=(NotableStringInfo &&info); 1.272 + 1.273 + ~NotableStringInfo() { 1.274 + js_free(buffer); 1.275 + } 1.276 + 1.277 + char *buffer; 1.278 + size_t length; 1.279 + 1.280 + private: 1.281 + NotableStringInfo(const NotableStringInfo& info) MOZ_DELETE; 1.282 +}; 1.283 + 1.284 +// This class holds information about the memory taken up by script sources 1.285 +// from a particular file. 1.286 +struct ScriptSourceInfo 1.287 +{ 1.288 +#define FOR_EACH_SIZE(macro) \ 1.289 + macro(_, _, compressed) \ 1.290 + macro(_, _, uncompressed) \ 1.291 + macro(_, _, misc) 1.292 + 1.293 + ScriptSourceInfo() 1.294 + : FOR_EACH_SIZE(ZERO_SIZE) 1.295 + numScripts(0) 1.296 + {} 1.297 + 1.298 + void add(const ScriptSourceInfo &other) { 1.299 + FOR_EACH_SIZE(ADD_OTHER_SIZE) 1.300 + numScripts++; 1.301 + } 1.302 + 1.303 + void subtract(const ScriptSourceInfo &other) { 1.304 + FOR_EACH_SIZE(SUB_OTHER_SIZE) 1.305 + numScripts--; 1.306 + } 1.307 + 1.308 + bool isNotable() const { 1.309 + static const size_t NotabilityThreshold = 16 * 1024; 1.310 + size_t n = 0; 1.311 + FOR_EACH_SIZE(ADD_SIZE_TO_N) 1.312 + return n >= NotabilityThreshold; 1.313 + } 1.314 + 1.315 + FOR_EACH_SIZE(DECL_SIZE) 1.316 + uint32_t numScripts; // How many ScriptSources come from this file? (It 1.317 + // can be more than one in XML files that have 1.318 + // multiple scripts in CDATA sections.) 1.319 +#undef FOR_EACH_SIZE 1.320 +}; 1.321 + 1.322 +// Holds data about a notable script source file (one whose combined 1.323 +// script sources use more than a certain amount of memory) so we can report it 1.324 +// individually. 1.325 +// 1.326 +// The only difference between this class and ScriptSourceInfo is that this 1.327 +// class holds a copy of the filename. 1.328 +struct NotableScriptSourceInfo : public ScriptSourceInfo 1.329 +{ 1.330 + NotableScriptSourceInfo(); 1.331 + NotableScriptSourceInfo(const char *filename, const ScriptSourceInfo &info); 1.332 + NotableScriptSourceInfo(NotableScriptSourceInfo &&info); 1.333 + NotableScriptSourceInfo &operator=(NotableScriptSourceInfo &&info); 1.334 + 1.335 + ~NotableScriptSourceInfo() { 1.336 + js_free(filename_); 1.337 + } 1.338 + 1.339 + char *filename_; 1.340 + 1.341 + private: 1.342 + NotableScriptSourceInfo(const NotableScriptSourceInfo& info) MOZ_DELETE; 1.343 +}; 1.344 + 1.345 +// These measurements relate directly to the JSRuntime, and not to zones and 1.346 +// compartments within it. 1.347 +struct RuntimeSizes 1.348 +{ 1.349 +#define FOR_EACH_SIZE(macro) \ 1.350 + macro(_, _, object) \ 1.351 + macro(_, _, atomsTable) \ 1.352 + macro(_, _, contexts) \ 1.353 + macro(_, _, dtoa) \ 1.354 + macro(_, _, temporary) \ 1.355 + macro(_, _, regexpData) \ 1.356 + macro(_, _, interpreterStack) \ 1.357 + macro(_, _, mathCache) \ 1.358 + macro(_, _, sourceDataCache) \ 1.359 + macro(_, _, scriptData) \ 1.360 + 1.361 + RuntimeSizes() 1.362 + : FOR_EACH_SIZE(ZERO_SIZE) 1.363 + scriptSourceInfo(), 1.364 + code(), 1.365 + gc(), 1.366 + notableScriptSources() 1.367 + { 1.368 + allScriptSources = js_new<ScriptSourcesHashMap>(); 1.369 + if (!allScriptSources || !allScriptSources->init()) 1.370 + MOZ_CRASH("oom"); 1.371 + } 1.372 + 1.373 + ~RuntimeSizes() { 1.374 + // |allScriptSources| is usually deleted and set to nullptr before this 1.375 + // destructor runs. But there are failure cases due to OOMs that may 1.376 + // prevent that, so it doesn't hurt to try again here. 1.377 + js_delete(allScriptSources); 1.378 + } 1.379 + 1.380 + // The script source measurements in |scriptSourceInfo| are initially for 1.381 + // all script sources. At the end, if the measurement granularity is 1.382 + // FineGrained, we subtract the measurements of the notable script sources 1.383 + // and move them into |notableScriptSources|. 1.384 + FOR_EACH_SIZE(DECL_SIZE) 1.385 + ScriptSourceInfo scriptSourceInfo; 1.386 + CodeSizes code; 1.387 + GCSizes gc; 1.388 + 1.389 + typedef js::HashMap<const char*, ScriptSourceInfo, 1.390 + js::CStringHashPolicy, 1.391 + js::SystemAllocPolicy> ScriptSourcesHashMap; 1.392 + 1.393 + // |allScriptSources| is only used transiently. During the reporting phase 1.394 + // it is filled with info about every script source in the runtime. It's 1.395 + // then used to fill in |notableScriptSources| (which actually gets 1.396 + // reported), and immediately discarded afterwards. 1.397 + ScriptSourcesHashMap *allScriptSources; 1.398 + js::Vector<NotableScriptSourceInfo, 0, js::SystemAllocPolicy> notableScriptSources; 1.399 + 1.400 +#undef FOR_EACH_SIZE 1.401 +}; 1.402 + 1.403 +struct ZoneStats 1.404 +{ 1.405 +#define FOR_EACH_SIZE(macro) \ 1.406 + macro(Other, NotLiveGCThing, gcHeapArenaAdmin) \ 1.407 + macro(Other, NotLiveGCThing, unusedGCThings) \ 1.408 + macro(Other, IsLiveGCThing, lazyScriptsGCHeap) \ 1.409 + macro(Other, NotLiveGCThing, lazyScriptsMallocHeap) \ 1.410 + macro(Other, IsLiveGCThing, jitCodesGCHeap) \ 1.411 + macro(Other, IsLiveGCThing, typeObjectsGCHeap) \ 1.412 + macro(Other, NotLiveGCThing, typeObjectsMallocHeap) \ 1.413 + macro(Other, NotLiveGCThing, typePool) \ 1.414 + macro(Other, NotLiveGCThing, baselineStubsOptimized) \ 1.415 + 1.416 + ZoneStats() 1.417 + : FOR_EACH_SIZE(ZERO_SIZE) 1.418 + stringInfo(), 1.419 + extra(), 1.420 + allStrings(nullptr), 1.421 + notableStrings(), 1.422 + isTotals(true) 1.423 + {} 1.424 + 1.425 + ZoneStats(ZoneStats &&other) 1.426 + : FOR_EACH_SIZE(COPY_OTHER_SIZE) 1.427 + stringInfo(mozilla::Move(other.stringInfo)), 1.428 + extra(other.extra), 1.429 + allStrings(other.allStrings), 1.430 + notableStrings(mozilla::Move(other.notableStrings)), 1.431 + isTotals(other.isTotals) 1.432 + { 1.433 + other.allStrings = nullptr; 1.434 + MOZ_ASSERT(!other.isTotals); 1.435 + } 1.436 + 1.437 + ~ZoneStats() { 1.438 + // |allStrings| is usually deleted and set to nullptr before this 1.439 + // destructor runs. But there are failure cases due to OOMs that may 1.440 + // prevent that, so it doesn't hurt to try again here. 1.441 + js_delete(allStrings); 1.442 + } 1.443 + 1.444 + bool initStrings(JSRuntime *rt); 1.445 + 1.446 + void addSizes(const ZoneStats &other) { 1.447 + MOZ_ASSERT(isTotals); 1.448 + FOR_EACH_SIZE(ADD_OTHER_SIZE) 1.449 + stringInfo.add(other.stringInfo); 1.450 + } 1.451 + 1.452 + size_t sizeOfLiveGCThings() const { 1.453 + MOZ_ASSERT(isTotals); 1.454 + size_t n = 0; 1.455 + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) 1.456 + n += stringInfo.sizeOfLiveGCThings(); 1.457 + return n; 1.458 + } 1.459 + 1.460 + void addToTabSizes(JS::TabSizes *sizes) const { 1.461 + MOZ_ASSERT(isTotals); 1.462 + FOR_EACH_SIZE(ADD_TO_TAB_SIZES) 1.463 + stringInfo.addToTabSizes(sizes); 1.464 + } 1.465 + 1.466 + // These string measurements are initially for all strings. At the end, 1.467 + // if the measurement granularity is FineGrained, we subtract the 1.468 + // measurements of the notable script sources and move them into 1.469 + // |notableStrings|. 1.470 + FOR_EACH_SIZE(DECL_SIZE) 1.471 + StringInfo stringInfo; 1.472 + void *extra; // This field can be used by embedders. 1.473 + 1.474 + typedef js::HashMap<JSString*, StringInfo, 1.475 + js::InefficientNonFlatteningStringHashPolicy, 1.476 + js::SystemAllocPolicy> StringsHashMap; 1.477 + 1.478 + // |allStrings| is only used transiently. During the zone traversal it is 1.479 + // filled with info about every string in the zone. It's then used to fill 1.480 + // in |notableStrings| (which actually gets reported), and immediately 1.481 + // discarded afterwards. 1.482 + StringsHashMap *allStrings; 1.483 + js::Vector<NotableStringInfo, 0, js::SystemAllocPolicy> notableStrings; 1.484 + bool isTotals; 1.485 + 1.486 +#undef FOR_EACH_SIZE 1.487 +}; 1.488 + 1.489 +struct CompartmentStats 1.490 +{ 1.491 +#define FOR_EACH_SIZE(macro) \ 1.492 + macro(Objects, IsLiveGCThing, objectsGCHeapOrdinary) \ 1.493 + macro(Objects, IsLiveGCThing, objectsGCHeapFunction) \ 1.494 + macro(Objects, IsLiveGCThing, objectsGCHeapDenseArray) \ 1.495 + macro(Objects, IsLiveGCThing, objectsGCHeapSlowArray) \ 1.496 + macro(Objects, IsLiveGCThing, objectsGCHeapCrossCompartmentWrapper) \ 1.497 + macro(Private, NotLiveGCThing, objectsPrivate) \ 1.498 + macro(Other, IsLiveGCThing, shapesGCHeapTreeGlobalParented) \ 1.499 + macro(Other, IsLiveGCThing, shapesGCHeapTreeNonGlobalParented) \ 1.500 + macro(Other, IsLiveGCThing, shapesGCHeapDict) \ 1.501 + macro(Other, IsLiveGCThing, shapesGCHeapBase) \ 1.502 + macro(Other, NotLiveGCThing, shapesMallocHeapTreeTables) \ 1.503 + macro(Other, NotLiveGCThing, shapesMallocHeapDictTables) \ 1.504 + macro(Other, NotLiveGCThing, shapesMallocHeapTreeShapeKids) \ 1.505 + macro(Other, NotLiveGCThing, shapesMallocHeapCompartmentTables) \ 1.506 + macro(Other, IsLiveGCThing, scriptsGCHeap) \ 1.507 + macro(Other, NotLiveGCThing, scriptsMallocHeapData) \ 1.508 + macro(Other, NotLiveGCThing, baselineData) \ 1.509 + macro(Other, NotLiveGCThing, baselineStubsFallback) \ 1.510 + macro(Other, NotLiveGCThing, ionData) \ 1.511 + macro(Other, NotLiveGCThing, typeInferenceTypeScripts) \ 1.512 + macro(Other, NotLiveGCThing, typeInferenceAllocationSiteTables) \ 1.513 + macro(Other, NotLiveGCThing, typeInferenceArrayTypeTables) \ 1.514 + macro(Other, NotLiveGCThing, typeInferenceObjectTypeTables) \ 1.515 + macro(Other, NotLiveGCThing, compartmentObject) \ 1.516 + macro(Other, NotLiveGCThing, crossCompartmentWrappersTable) \ 1.517 + macro(Other, NotLiveGCThing, regexpCompartment) \ 1.518 + macro(Other, NotLiveGCThing, debuggeesSet) \ 1.519 + macro(Other, NotLiveGCThing, savedStacksSet) 1.520 + 1.521 + CompartmentStats() 1.522 + : FOR_EACH_SIZE(ZERO_SIZE) 1.523 + objectsExtra(), 1.524 + extra() 1.525 + {} 1.526 + 1.527 + CompartmentStats(const CompartmentStats &other) 1.528 + : FOR_EACH_SIZE(COPY_OTHER_SIZE) 1.529 + objectsExtra(other.objectsExtra), 1.530 + extra(other.extra) 1.531 + {} 1.532 + 1.533 + void add(const CompartmentStats &other) { 1.534 + FOR_EACH_SIZE(ADD_OTHER_SIZE) 1.535 + objectsExtra.add(other.objectsExtra); 1.536 + // Do nothing with |extra|. 1.537 + } 1.538 + 1.539 + size_t sizeOfLiveGCThings() const { 1.540 + size_t n = 0; 1.541 + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) 1.542 + n += objectsExtra.sizeOfLiveGCThings(); 1.543 + // Do nothing with |extra|. 1.544 + return n; 1.545 + } 1.546 + 1.547 + void addToTabSizes(TabSizes *sizes) const { 1.548 + FOR_EACH_SIZE(ADD_TO_TAB_SIZES); 1.549 + objectsExtra.addToTabSizes(sizes); 1.550 + // Do nothing with |extra|. 1.551 + } 1.552 + 1.553 + FOR_EACH_SIZE(DECL_SIZE) 1.554 + ObjectsExtraSizes objectsExtra; 1.555 + void *extra; // This field can be used by embedders. 1.556 + 1.557 +#undef FOR_EACH_SIZE 1.558 +}; 1.559 + 1.560 +typedef js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> CompartmentStatsVector; 1.561 +typedef js::Vector<ZoneStats, 0, js::SystemAllocPolicy> ZoneStatsVector; 1.562 + 1.563 +struct RuntimeStats 1.564 +{ 1.565 +#define FOR_EACH_SIZE(macro) \ 1.566 + macro(_, _, gcHeapChunkTotal) \ 1.567 + macro(_, _, gcHeapDecommittedArenas) \ 1.568 + macro(_, _, gcHeapUnusedChunks) \ 1.569 + macro(_, _, gcHeapUnusedArenas) \ 1.570 + macro(_, _, gcHeapChunkAdmin) \ 1.571 + macro(_, _, gcHeapGCThings) \ 1.572 + 1.573 + RuntimeStats(mozilla::MallocSizeOf mallocSizeOf) 1.574 + : FOR_EACH_SIZE(ZERO_SIZE) 1.575 + runtime(), 1.576 + cTotals(), 1.577 + zTotals(), 1.578 + compartmentStatsVector(), 1.579 + zoneStatsVector(), 1.580 + currZoneStats(nullptr), 1.581 + mallocSizeOf_(mallocSizeOf) 1.582 + {} 1.583 + 1.584 + // Here's a useful breakdown of the GC heap. 1.585 + // 1.586 + // - rtStats.gcHeapChunkTotal 1.587 + // - decommitted bytes 1.588 + // - rtStats.gcHeapDecommittedArenas (decommitted arenas in non-empty chunks) 1.589 + // - unused bytes 1.590 + // - rtStats.gcHeapUnusedChunks (empty chunks) 1.591 + // - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks) 1.592 + // - rtStats.zTotals.unusedGCThings (empty GC thing slots within non-empty arenas) 1.593 + // - used bytes 1.594 + // - rtStats.gcHeapChunkAdmin 1.595 + // - rtStats.zTotals.gcHeapArenaAdmin 1.596 + // - rtStats.gcHeapGCThings (in-use GC things) 1.597 + // == rtStats.zTotals.sizeOfLiveGCThings() + rtStats.cTotals.sizeOfLiveGCThings() 1.598 + // 1.599 + // It's possible that some arenas in empty chunks may be decommitted, but 1.600 + // we don't count those under rtStats.gcHeapDecommittedArenas because (a) 1.601 + // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a 1.602 + // multiple of the chunk size, which is good. 1.603 + 1.604 + FOR_EACH_SIZE(DECL_SIZE) 1.605 + 1.606 + RuntimeSizes runtime; 1.607 + 1.608 + CompartmentStats cTotals; // The sum of this runtime's compartments' measurements. 1.609 + ZoneStats zTotals; // The sum of this runtime's zones' measurements. 1.610 + 1.611 + CompartmentStatsVector compartmentStatsVector; 1.612 + ZoneStatsVector zoneStatsVector; 1.613 + 1.614 + ZoneStats *currZoneStats; 1.615 + 1.616 + mozilla::MallocSizeOf mallocSizeOf_; 1.617 + 1.618 + virtual void initExtraCompartmentStats(JSCompartment *c, CompartmentStats *cstats) = 0; 1.619 + virtual void initExtraZoneStats(JS::Zone *zone, ZoneStats *zstats) = 0; 1.620 + 1.621 +#undef FOR_EACH_SIZE 1.622 +}; 1.623 + 1.624 +class ObjectPrivateVisitor 1.625 +{ 1.626 + public: 1.627 + // Within CollectRuntimeStats, this method is called for each JS object 1.628 + // that has an nsISupports pointer. 1.629 + virtual size_t sizeOfIncludingThis(nsISupports *aSupports) = 0; 1.630 + 1.631 + // A callback that gets a JSObject's nsISupports pointer, if it has one. 1.632 + // Note: this function does *not* addref |iface|. 1.633 + typedef bool(*GetISupportsFun)(JSObject *obj, nsISupports **iface); 1.634 + GetISupportsFun getISupports_; 1.635 + 1.636 + ObjectPrivateVisitor(GetISupportsFun getISupports) 1.637 + : getISupports_(getISupports) 1.638 + {} 1.639 +}; 1.640 + 1.641 +extern JS_PUBLIC_API(bool) 1.642 +CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisitor *opv); 1.643 + 1.644 +extern JS_PUBLIC_API(size_t) 1.645 +SystemCompartmentCount(JSRuntime *rt); 1.646 + 1.647 +extern JS_PUBLIC_API(size_t) 1.648 +UserCompartmentCount(JSRuntime *rt); 1.649 + 1.650 +extern JS_PUBLIC_API(size_t) 1.651 +PeakSizeOfTemporary(const JSRuntime *rt); 1.652 + 1.653 +extern JS_PUBLIC_API(bool) 1.654 +AddSizeOfTab(JSRuntime *rt, JS::HandleObject obj, mozilla::MallocSizeOf mallocSizeOf, 1.655 + ObjectPrivateVisitor *opv, TabSizes *sizes); 1.656 + 1.657 +} // namespace JS 1.658 + 1.659 +#undef DECL_SIZE 1.660 +#undef ZERO_SIZE 1.661 +#undef COPY_OTHER_SIZE 1.662 +#undef ADD_OTHER_SIZE 1.663 +#undef SUB_OTHER_SIZE 1.664 +#undef ADD_SIZE_TO_N 1.665 +#undef ADD_SIZE_TO_N_IF_LIVE_GC_THING 1.666 +#undef ADD_TO_TAB_SIZES 1.667 + 1.668 +#endif /* js_MemoryMetrics_h */