1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/MemoryMetrics.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,703 @@ 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 +#include "js/MemoryMetrics.h" 1.11 + 1.12 +#include "mozilla/DebugOnly.h" 1.13 + 1.14 +#include "jsapi.h" 1.15 +#include "jscompartment.h" 1.16 +#include "jsgc.h" 1.17 +#include "jsobj.h" 1.18 +#include "jsscript.h" 1.19 + 1.20 +#include "jit/BaselineJIT.h" 1.21 +#include "jit/Ion.h" 1.22 +#include "vm/ArrayObject.h" 1.23 +#include "vm/Runtime.h" 1.24 +#include "vm/Shape.h" 1.25 +#include "vm/String.h" 1.26 +#include "vm/WrapperObject.h" 1.27 + 1.28 +using mozilla::DebugOnly; 1.29 +using mozilla::MallocSizeOf; 1.30 +using mozilla::Move; 1.31 +using mozilla::PodCopy; 1.32 +using mozilla::PodEqual; 1.33 + 1.34 +using namespace js; 1.35 + 1.36 +using JS::RuntimeStats; 1.37 +using JS::ObjectPrivateVisitor; 1.38 +using JS::ZoneStats; 1.39 +using JS::CompartmentStats; 1.40 + 1.41 +namespace js { 1.42 + 1.43 +JS_FRIEND_API(size_t) 1.44 +MemoryReportingSundriesThreshold() 1.45 +{ 1.46 + return 8 * 1024; 1.47 +} 1.48 + 1.49 +/* static */ HashNumber 1.50 +InefficientNonFlatteningStringHashPolicy::hash(const Lookup &l) 1.51 +{ 1.52 + ScopedJSFreePtr<jschar> ownedChars; 1.53 + const jschar *chars; 1.54 + if (l->hasPureChars()) { 1.55 + chars = l->pureChars(); 1.56 + } else { 1.57 + // Slowest hash function evar! 1.58 + if (!l->copyNonPureChars(/* tcx */ nullptr, ownedChars)) 1.59 + MOZ_CRASH("oom"); 1.60 + chars = ownedChars; 1.61 + } 1.62 + 1.63 + return mozilla::HashString(chars, l->length()); 1.64 +} 1.65 + 1.66 +/* static */ bool 1.67 +InefficientNonFlatteningStringHashPolicy::match(const JSString *const &k, const Lookup &l) 1.68 +{ 1.69 + // We can't use js::EqualStrings, because that flattens our strings. 1.70 + if (k->length() != l->length()) 1.71 + return false; 1.72 + 1.73 + const jschar *c1; 1.74 + ScopedJSFreePtr<jschar> ownedChars1; 1.75 + if (k->hasPureChars()) { 1.76 + c1 = k->pureChars(); 1.77 + } else { 1.78 + if (!k->copyNonPureChars(/* tcx */ nullptr, ownedChars1)) 1.79 + MOZ_CRASH("oom"); 1.80 + c1 = ownedChars1; 1.81 + } 1.82 + 1.83 + const jschar *c2; 1.84 + ScopedJSFreePtr<jschar> ownedChars2; 1.85 + if (l->hasPureChars()) { 1.86 + c2 = l->pureChars(); 1.87 + } else { 1.88 + if (!l->copyNonPureChars(/* tcx */ nullptr, ownedChars2)) 1.89 + MOZ_CRASH("oom"); 1.90 + c2 = ownedChars2; 1.91 + } 1.92 + 1.93 + return PodEqual(c1, c2, k->length()); 1.94 +} 1.95 + 1.96 +/* static */ HashNumber 1.97 +CStringHashPolicy::hash(const Lookup &l) 1.98 +{ 1.99 + return mozilla::HashString(l); 1.100 +} 1.101 + 1.102 +/* static */ bool 1.103 +CStringHashPolicy::match(const char *const &k, const Lookup &l) 1.104 +{ 1.105 + return strcmp(k, l) == 0; 1.106 +} 1.107 + 1.108 +} // namespace js 1.109 + 1.110 +namespace JS { 1.111 + 1.112 +NotableStringInfo::NotableStringInfo() 1.113 + : StringInfo(), 1.114 + buffer(0), 1.115 + length(0) 1.116 +{ 1.117 +} 1.118 + 1.119 +NotableStringInfo::NotableStringInfo(JSString *str, const StringInfo &info) 1.120 + : StringInfo(info), 1.121 + length(str->length()) 1.122 +{ 1.123 + size_t bufferSize = Min(str->length() + 1, size_t(MAX_SAVED_CHARS)); 1.124 + buffer = js_pod_malloc<char>(bufferSize); 1.125 + if (!buffer) { 1.126 + MOZ_CRASH("oom"); 1.127 + } 1.128 + 1.129 + const jschar* chars; 1.130 + ScopedJSFreePtr<jschar> ownedChars; 1.131 + if (str->hasPureChars()) { 1.132 + chars = str->pureChars(); 1.133 + } else { 1.134 + if (!str->copyNonPureChars(/* tcx */ nullptr, ownedChars)) 1.135 + MOZ_CRASH("oom"); 1.136 + chars = ownedChars; 1.137 + } 1.138 + 1.139 + // We might truncate |str| even if it's much shorter than 1024 chars, if 1.140 + // |str| contains unicode chars. Since this is just for a memory reporter, 1.141 + // we don't care. 1.142 + PutEscapedString(buffer, bufferSize, chars, str->length(), /* quote */ 0); 1.143 +} 1.144 + 1.145 +NotableStringInfo::NotableStringInfo(NotableStringInfo &&info) 1.146 + : StringInfo(Move(info)), 1.147 + length(info.length) 1.148 +{ 1.149 + buffer = info.buffer; 1.150 + info.buffer = nullptr; 1.151 +} 1.152 + 1.153 +NotableStringInfo &NotableStringInfo::operator=(NotableStringInfo &&info) 1.154 +{ 1.155 + MOZ_ASSERT(this != &info, "self-move assignment is prohibited"); 1.156 + this->~NotableStringInfo(); 1.157 + new (this) NotableStringInfo(Move(info)); 1.158 + return *this; 1.159 +} 1.160 + 1.161 +NotableScriptSourceInfo::NotableScriptSourceInfo() 1.162 + : ScriptSourceInfo(), 1.163 + filename_(nullptr) 1.164 +{ 1.165 +} 1.166 + 1.167 +NotableScriptSourceInfo::NotableScriptSourceInfo(const char *filename, const ScriptSourceInfo &info) 1.168 + : ScriptSourceInfo(info) 1.169 +{ 1.170 + size_t bytes = strlen(filename) + 1; 1.171 + filename_ = js_pod_malloc<char>(bytes); 1.172 + if (!filename_) 1.173 + MOZ_CRASH("oom"); 1.174 + PodCopy(filename_, filename, bytes); 1.175 +} 1.176 + 1.177 +NotableScriptSourceInfo::NotableScriptSourceInfo(NotableScriptSourceInfo &&info) 1.178 + : ScriptSourceInfo(Move(info)) 1.179 +{ 1.180 + filename_ = info.filename_; 1.181 + info.filename_ = nullptr; 1.182 +} 1.183 + 1.184 +NotableScriptSourceInfo &NotableScriptSourceInfo::operator=(NotableScriptSourceInfo &&info) 1.185 +{ 1.186 + MOZ_ASSERT(this != &info, "self-move assignment is prohibited"); 1.187 + this->~NotableScriptSourceInfo(); 1.188 + new (this) NotableScriptSourceInfo(Move(info)); 1.189 + return *this; 1.190 +} 1.191 + 1.192 + 1.193 +} // namespace JS 1.194 + 1.195 +typedef HashSet<ScriptSource *, DefaultHasher<ScriptSource *>, SystemAllocPolicy> SourceSet; 1.196 + 1.197 +struct StatsClosure 1.198 +{ 1.199 + RuntimeStats *rtStats; 1.200 + ObjectPrivateVisitor *opv; 1.201 + SourceSet seenSources; 1.202 + StatsClosure(RuntimeStats *rt, ObjectPrivateVisitor *v) : rtStats(rt), opv(v) {} 1.203 + bool init() { 1.204 + return seenSources.init(); 1.205 + } 1.206 +}; 1.207 + 1.208 +static void 1.209 +DecommittedArenasChunkCallback(JSRuntime *rt, void *data, gc::Chunk *chunk) 1.210 +{ 1.211 + // This case is common and fast to check. Do it first. 1.212 + if (chunk->decommittedArenas.isAllClear()) 1.213 + return; 1.214 + 1.215 + size_t n = 0; 1.216 + for (size_t i = 0; i < gc::ArenasPerChunk; i++) { 1.217 + if (chunk->decommittedArenas.get(i)) 1.218 + n += gc::ArenaSize; 1.219 + } 1.220 + JS_ASSERT(n > 0); 1.221 + *static_cast<size_t *>(data) += n; 1.222 +} 1.223 + 1.224 +static void 1.225 +StatsZoneCallback(JSRuntime *rt, void *data, Zone *zone) 1.226 +{ 1.227 + // Append a new CompartmentStats to the vector. 1.228 + RuntimeStats *rtStats = static_cast<StatsClosure *>(data)->rtStats; 1.229 + 1.230 + // CollectRuntimeStats reserves enough space. 1.231 + MOZ_ALWAYS_TRUE(rtStats->zoneStatsVector.growBy(1)); 1.232 + ZoneStats &zStats = rtStats->zoneStatsVector.back(); 1.233 + if (!zStats.initStrings(rt)) 1.234 + MOZ_CRASH("oom"); 1.235 + rtStats->initExtraZoneStats(zone, &zStats); 1.236 + rtStats->currZoneStats = &zStats; 1.237 + 1.238 + zone->addSizeOfIncludingThis(rtStats->mallocSizeOf_, 1.239 + &zStats.typePool, 1.240 + &zStats.baselineStubsOptimized); 1.241 +} 1.242 + 1.243 +static void 1.244 +StatsCompartmentCallback(JSRuntime *rt, void *data, JSCompartment *compartment) 1.245 +{ 1.246 + // Append a new CompartmentStats to the vector. 1.247 + RuntimeStats *rtStats = static_cast<StatsClosure *>(data)->rtStats; 1.248 + 1.249 + // CollectRuntimeStats reserves enough space. 1.250 + MOZ_ALWAYS_TRUE(rtStats->compartmentStatsVector.growBy(1)); 1.251 + CompartmentStats &cStats = rtStats->compartmentStatsVector.back(); 1.252 + rtStats->initExtraCompartmentStats(compartment, &cStats); 1.253 + 1.254 + compartment->compartmentStats = &cStats; 1.255 + 1.256 + // Measure the compartment object itself, and things hanging off it. 1.257 + compartment->addSizeOfIncludingThis(rtStats->mallocSizeOf_, 1.258 + &cStats.typeInferenceAllocationSiteTables, 1.259 + &cStats.typeInferenceArrayTypeTables, 1.260 + &cStats.typeInferenceObjectTypeTables, 1.261 + &cStats.compartmentObject, 1.262 + &cStats.shapesMallocHeapCompartmentTables, 1.263 + &cStats.crossCompartmentWrappersTable, 1.264 + &cStats.regexpCompartment, 1.265 + &cStats.debuggeesSet, 1.266 + &cStats.savedStacksSet); 1.267 +} 1.268 + 1.269 +static void 1.270 +StatsArenaCallback(JSRuntime *rt, void *data, gc::Arena *arena, 1.271 + JSGCTraceKind traceKind, size_t thingSize) 1.272 +{ 1.273 + RuntimeStats *rtStats = static_cast<StatsClosure *>(data)->rtStats; 1.274 + 1.275 + // The admin space includes (a) the header and (b) the padding between the 1.276 + // end of the header and the start of the first GC thing. 1.277 + size_t allocationSpace = arena->thingsSpan(thingSize); 1.278 + rtStats->currZoneStats->gcHeapArenaAdmin += gc::ArenaSize - allocationSpace; 1.279 + 1.280 + // We don't call the callback on unused things. So we compute the 1.281 + // unused space like this: arenaUnused = maxArenaUnused - arenaUsed. 1.282 + // We do this by setting arenaUnused to maxArenaUnused here, and then 1.283 + // subtracting thingSize for every used cell, in StatsCellCallback(). 1.284 + rtStats->currZoneStats->unusedGCThings += allocationSpace; 1.285 +} 1.286 + 1.287 +static CompartmentStats * 1.288 +GetCompartmentStats(JSCompartment *comp) 1.289 +{ 1.290 + return static_cast<CompartmentStats *>(comp->compartmentStats); 1.291 +} 1.292 + 1.293 +enum Granularity { 1.294 + FineGrained, // Corresponds to CollectRuntimeStats() 1.295 + CoarseGrained // Corresponds to AddSizeOfTab() 1.296 +}; 1.297 + 1.298 +// The various kinds of hashing are expensive, and the results are unused when 1.299 +// doing coarse-grained measurements. Skipping them more than doubles the 1.300 +// profile speed for complex pages such as gmail.com. 1.301 +template <Granularity granularity> 1.302 +static void 1.303 +StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKind, 1.304 + size_t thingSize) 1.305 +{ 1.306 + StatsClosure *closure = static_cast<StatsClosure *>(data); 1.307 + RuntimeStats *rtStats = closure->rtStats; 1.308 + ZoneStats *zStats = rtStats->currZoneStats; 1.309 + switch (traceKind) { 1.310 + case JSTRACE_OBJECT: { 1.311 + JSObject *obj = static_cast<JSObject *>(thing); 1.312 + CompartmentStats *cStats = GetCompartmentStats(obj->compartment()); 1.313 + if (obj->is<JSFunction>()) 1.314 + cStats->objectsGCHeapFunction += thingSize; 1.315 + else if (obj->is<ArrayObject>()) 1.316 + cStats->objectsGCHeapDenseArray += thingSize; 1.317 + else if (obj->is<CrossCompartmentWrapperObject>()) 1.318 + cStats->objectsGCHeapCrossCompartmentWrapper += thingSize; 1.319 + else 1.320 + cStats->objectsGCHeapOrdinary += thingSize; 1.321 + 1.322 + obj->addSizeOfExcludingThis(rtStats->mallocSizeOf_, &cStats->objectsExtra); 1.323 + 1.324 + if (ObjectPrivateVisitor *opv = closure->opv) { 1.325 + nsISupports *iface; 1.326 + if (opv->getISupports_(obj, &iface) && iface) 1.327 + cStats->objectsPrivate += opv->sizeOfIncludingThis(iface); 1.328 + } 1.329 + break; 1.330 + } 1.331 + 1.332 + case JSTRACE_STRING: { 1.333 + JSString *str = static_cast<JSString *>(thing); 1.334 + 1.335 + JS::StringInfo info; 1.336 + info.gcHeap = thingSize; 1.337 + info.mallocHeap = str->sizeOfExcludingThis(rtStats->mallocSizeOf_); 1.338 + info.numCopies = 1; 1.339 + 1.340 + zStats->stringInfo.add(info); 1.341 + 1.342 + if (granularity == FineGrained) { 1.343 + ZoneStats::StringsHashMap::AddPtr p = zStats->allStrings->lookupForAdd(str); 1.344 + if (!p) { 1.345 + // Ignore failure -- we just won't record the string as notable. 1.346 + (void)zStats->allStrings->add(p, str, info); 1.347 + } else { 1.348 + p->value().add(info); 1.349 + } 1.350 + } 1.351 + break; 1.352 + } 1.353 + 1.354 + case JSTRACE_SHAPE: { 1.355 + Shape *shape = static_cast<Shape *>(thing); 1.356 + CompartmentStats *cStats = GetCompartmentStats(shape->compartment()); 1.357 + if (shape->inDictionary()) { 1.358 + cStats->shapesGCHeapDict += thingSize; 1.359 + 1.360 + // nullptr because kidsSize shouldn't be incremented in this case. 1.361 + shape->addSizeOfExcludingThis(rtStats->mallocSizeOf_, 1.362 + &cStats->shapesMallocHeapDictTables, nullptr); 1.363 + } else { 1.364 + JSObject *parent = shape->base()->getObjectParent(); 1.365 + if (parent && parent->is<GlobalObject>()) 1.366 + cStats->shapesGCHeapTreeGlobalParented += thingSize; 1.367 + else 1.368 + cStats->shapesGCHeapTreeNonGlobalParented += thingSize; 1.369 + 1.370 + shape->addSizeOfExcludingThis(rtStats->mallocSizeOf_, 1.371 + &cStats->shapesMallocHeapTreeTables, 1.372 + &cStats->shapesMallocHeapTreeShapeKids); 1.373 + } 1.374 + break; 1.375 + } 1.376 + 1.377 + case JSTRACE_BASE_SHAPE: { 1.378 + BaseShape *base = static_cast<BaseShape *>(thing); 1.379 + CompartmentStats *cStats = GetCompartmentStats(base->compartment()); 1.380 + cStats->shapesGCHeapBase += thingSize; 1.381 + break; 1.382 + } 1.383 + 1.384 + case JSTRACE_SCRIPT: { 1.385 + JSScript *script = static_cast<JSScript *>(thing); 1.386 + CompartmentStats *cStats = GetCompartmentStats(script->compartment()); 1.387 + cStats->scriptsGCHeap += thingSize; 1.388 + cStats->scriptsMallocHeapData += script->sizeOfData(rtStats->mallocSizeOf_); 1.389 + cStats->typeInferenceTypeScripts += script->sizeOfTypeScript(rtStats->mallocSizeOf_); 1.390 +#ifdef JS_ION 1.391 + jit::AddSizeOfBaselineData(script, rtStats->mallocSizeOf_, &cStats->baselineData, 1.392 + &cStats->baselineStubsFallback); 1.393 + cStats->ionData += jit::SizeOfIonData(script, rtStats->mallocSizeOf_); 1.394 +#endif 1.395 + 1.396 + ScriptSource *ss = script->scriptSource(); 1.397 + SourceSet::AddPtr entry = closure->seenSources.lookupForAdd(ss); 1.398 + if (!entry) { 1.399 + (void)closure->seenSources.add(entry, ss); // Not much to be done on failure. 1.400 + 1.401 + JS::ScriptSourceInfo info; // This zeroes all the sizes. 1.402 + ss->addSizeOfIncludingThis(rtStats->mallocSizeOf_, &info); 1.403 + MOZ_ASSERT(info.compressed == 0 || info.uncompressed == 0); 1.404 + 1.405 + rtStats->runtime.scriptSourceInfo.add(info); 1.406 + 1.407 + if (granularity == FineGrained) { 1.408 + const char* filename = ss->filename(); 1.409 + if (!filename) 1.410 + filename = "<no filename>"; 1.411 + 1.412 + JS::RuntimeSizes::ScriptSourcesHashMap::AddPtr p = 1.413 + rtStats->runtime.allScriptSources->lookupForAdd(filename); 1.414 + if (!p) { 1.415 + // Ignore failure -- we just won't record the script source as notable. 1.416 + (void)rtStats->runtime.allScriptSources->add(p, filename, info); 1.417 + } else { 1.418 + p->value().add(info); 1.419 + } 1.420 + } 1.421 + } 1.422 + 1.423 + break; 1.424 + } 1.425 + 1.426 + case JSTRACE_LAZY_SCRIPT: { 1.427 + LazyScript *lazy = static_cast<LazyScript *>(thing); 1.428 + zStats->lazyScriptsGCHeap += thingSize; 1.429 + zStats->lazyScriptsMallocHeap += lazy->sizeOfExcludingThis(rtStats->mallocSizeOf_); 1.430 + break; 1.431 + } 1.432 + 1.433 + case JSTRACE_JITCODE: { 1.434 +#ifdef JS_ION 1.435 + zStats->jitCodesGCHeap += thingSize; 1.436 + // The code for a script is counted in ExecutableAllocator::sizeOfCode(). 1.437 +#endif 1.438 + break; 1.439 + } 1.440 + 1.441 + case JSTRACE_TYPE_OBJECT: { 1.442 + types::TypeObject *obj = static_cast<types::TypeObject *>(thing); 1.443 + zStats->typeObjectsGCHeap += thingSize; 1.444 + zStats->typeObjectsMallocHeap += obj->sizeOfExcludingThis(rtStats->mallocSizeOf_); 1.445 + break; 1.446 + } 1.447 + 1.448 + default: 1.449 + MOZ_ASSUME_UNREACHABLE("invalid traceKind"); 1.450 + } 1.451 + 1.452 + // Yes, this is a subtraction: see StatsArenaCallback() for details. 1.453 + zStats->unusedGCThings -= thingSize; 1.454 +} 1.455 + 1.456 +static bool 1.457 +FindNotableStrings(ZoneStats &zStats) 1.458 +{ 1.459 + using namespace JS; 1.460 + 1.461 + // We should only run FindNotableStrings once per ZoneStats object. 1.462 + MOZ_ASSERT(zStats.notableStrings.empty()); 1.463 + 1.464 + for (ZoneStats::StringsHashMap::Range r = zStats.allStrings->all(); !r.empty(); r.popFront()) { 1.465 + 1.466 + JSString *str = r.front().key(); 1.467 + StringInfo &info = r.front().value(); 1.468 + 1.469 + if (!info.isNotable()) 1.470 + continue; 1.471 + 1.472 + if (!zStats.notableStrings.growBy(1)) 1.473 + return false; 1.474 + 1.475 + zStats.notableStrings.back() = NotableStringInfo(str, info); 1.476 + 1.477 + // We're moving this string from a non-notable to a notable bucket, so 1.478 + // subtract it out of the non-notable tallies. 1.479 + zStats.stringInfo.subtract(info); 1.480 + } 1.481 + // Delete |allStrings| now, rather than waiting for zStats's destruction, 1.482 + // to reduce peak memory consumption during reporting. 1.483 + js_delete(zStats.allStrings); 1.484 + zStats.allStrings = nullptr; 1.485 + return true; 1.486 +} 1.487 + 1.488 +bool 1.489 +ZoneStats::initStrings(JSRuntime *rt) 1.490 +{ 1.491 + isTotals = false; 1.492 + allStrings = rt->new_<StringsHashMap>(); 1.493 + if (!allStrings) 1.494 + return false; 1.495 + if (!allStrings->init()) { 1.496 + js_delete(allStrings); 1.497 + allStrings = nullptr; 1.498 + return false; 1.499 + } 1.500 + return true; 1.501 +} 1.502 + 1.503 +static bool 1.504 +FindNotableScriptSources(JS::RuntimeSizes &runtime) 1.505 +{ 1.506 + using namespace JS; 1.507 + 1.508 + // We should only run FindNotableScriptSources once per RuntimeSizes. 1.509 + MOZ_ASSERT(runtime.notableScriptSources.empty()); 1.510 + 1.511 + for (RuntimeSizes::ScriptSourcesHashMap::Range r = runtime.allScriptSources->all(); 1.512 + !r.empty(); 1.513 + r.popFront()) 1.514 + { 1.515 + const char *filename = r.front().key(); 1.516 + ScriptSourceInfo &info = r.front().value(); 1.517 + 1.518 + if (!info.isNotable()) 1.519 + continue; 1.520 + 1.521 + if (!runtime.notableScriptSources.growBy(1)) 1.522 + return false; 1.523 + 1.524 + runtime.notableScriptSources.back() = NotableScriptSourceInfo(filename, info); 1.525 + 1.526 + // We're moving this script source from a non-notable to a notable 1.527 + // bucket, so subtract its sizes from the non-notable tallies. 1.528 + runtime.scriptSourceInfo.subtract(info); 1.529 + } 1.530 + // Delete |allScriptSources| now, rather than waiting for zStats's 1.531 + // destruction, to reduce peak memory consumption during reporting. 1.532 + js_delete(runtime.allScriptSources); 1.533 + runtime.allScriptSources = nullptr; 1.534 + return true; 1.535 +} 1.536 + 1.537 +JS_PUBLIC_API(bool) 1.538 +JS::CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisitor *opv) 1.539 +{ 1.540 + if (!rtStats->compartmentStatsVector.reserve(rt->numCompartments)) 1.541 + return false; 1.542 + 1.543 + if (!rtStats->zoneStatsVector.reserve(rt->zones.length())) 1.544 + return false; 1.545 + 1.546 + rtStats->gcHeapChunkTotal = 1.547 + size_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) * gc::ChunkSize; 1.548 + 1.549 + rtStats->gcHeapUnusedChunks = 1.550 + size_t(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) * gc::ChunkSize; 1.551 + 1.552 + IterateChunks(rt, &rtStats->gcHeapDecommittedArenas, 1.553 + DecommittedArenasChunkCallback); 1.554 + 1.555 + // Take the per-compartment measurements. 1.556 + StatsClosure closure(rtStats, opv); 1.557 + if (!closure.init()) 1.558 + return false; 1.559 + IterateZonesCompartmentsArenasCells(rt, &closure, StatsZoneCallback, StatsCompartmentCallback, 1.560 + StatsArenaCallback, StatsCellCallback<FineGrained>); 1.561 + 1.562 + // Take the "explicit/js/runtime/" measurements. 1.563 + rt->addSizeOfIncludingThis(rtStats->mallocSizeOf_, &rtStats->runtime); 1.564 + 1.565 + if (!FindNotableScriptSources(rtStats->runtime)) 1.566 + return false; 1.567 + 1.568 + ZoneStatsVector &zs = rtStats->zoneStatsVector; 1.569 + ZoneStats &zTotals = rtStats->zTotals; 1.570 + 1.571 + // We don't look for notable strings for zTotals. So we first sum all the 1.572 + // zones' measurements to get the totals. Then we find the notable strings 1.573 + // within each zone. 1.574 + for (size_t i = 0; i < zs.length(); i++) 1.575 + zTotals.addSizes(zs[i]); 1.576 + 1.577 + for (size_t i = 0; i < zs.length(); i++) 1.578 + if (!FindNotableStrings(zs[i])) 1.579 + return false; 1.580 + 1.581 + MOZ_ASSERT(!zTotals.allStrings); 1.582 + 1.583 + for (size_t i = 0; i < rtStats->compartmentStatsVector.length(); i++) { 1.584 + CompartmentStats &cStats = rtStats->compartmentStatsVector[i]; 1.585 + rtStats->cTotals.add(cStats); 1.586 + } 1.587 + 1.588 + rtStats->gcHeapGCThings = rtStats->zTotals.sizeOfLiveGCThings() + 1.589 + rtStats->cTotals.sizeOfLiveGCThings(); 1.590 + 1.591 +#ifdef DEBUG 1.592 + // Check that the in-arena measurements look ok. 1.593 + size_t totalArenaSize = rtStats->zTotals.gcHeapArenaAdmin + 1.594 + rtStats->zTotals.unusedGCThings + 1.595 + rtStats->gcHeapGCThings; 1.596 + JS_ASSERT(totalArenaSize % gc::ArenaSize == 0); 1.597 +#endif 1.598 + 1.599 + for (CompartmentsIter comp(rt, WithAtoms); !comp.done(); comp.next()) 1.600 + comp->compartmentStats = nullptr; 1.601 + 1.602 + size_t numDirtyChunks = 1.603 + (rtStats->gcHeapChunkTotal - rtStats->gcHeapUnusedChunks) / gc::ChunkSize; 1.604 + size_t perChunkAdmin = 1.605 + sizeof(gc::Chunk) - (sizeof(gc::Arena) * gc::ArenasPerChunk); 1.606 + rtStats->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin; 1.607 + 1.608 + // |gcHeapUnusedArenas| is the only thing left. Compute it in terms of 1.609 + // all the others. See the comment in RuntimeStats for explanation. 1.610 + rtStats->gcHeapUnusedArenas = rtStats->gcHeapChunkTotal - 1.611 + rtStats->gcHeapDecommittedArenas - 1.612 + rtStats->gcHeapUnusedChunks - 1.613 + rtStats->zTotals.unusedGCThings - 1.614 + rtStats->gcHeapChunkAdmin - 1.615 + rtStats->zTotals.gcHeapArenaAdmin - 1.616 + rtStats->gcHeapGCThings; 1.617 + return true; 1.618 +} 1.619 + 1.620 +JS_PUBLIC_API(size_t) 1.621 +JS::SystemCompartmentCount(JSRuntime *rt) 1.622 +{ 1.623 + size_t n = 0; 1.624 + for (CompartmentsIter comp(rt, WithAtoms); !comp.done(); comp.next()) { 1.625 + if (comp->isSystem) 1.626 + ++n; 1.627 + } 1.628 + return n; 1.629 +} 1.630 + 1.631 +JS_PUBLIC_API(size_t) 1.632 +JS::UserCompartmentCount(JSRuntime *rt) 1.633 +{ 1.634 + size_t n = 0; 1.635 + for (CompartmentsIter comp(rt, WithAtoms); !comp.done(); comp.next()) { 1.636 + if (!comp->isSystem) 1.637 + ++n; 1.638 + } 1.639 + return n; 1.640 +} 1.641 + 1.642 +JS_PUBLIC_API(size_t) 1.643 +JS::PeakSizeOfTemporary(const JSRuntime *rt) 1.644 +{ 1.645 + return rt->tempLifoAlloc.peakSizeOfExcludingThis(); 1.646 +} 1.647 + 1.648 +namespace JS { 1.649 + 1.650 +JS_PUBLIC_API(bool) 1.651 +AddSizeOfTab(JSRuntime *rt, HandleObject obj, MallocSizeOf mallocSizeOf, ObjectPrivateVisitor *opv, 1.652 + TabSizes *sizes) 1.653 +{ 1.654 + class SimpleJSRuntimeStats : public JS::RuntimeStats 1.655 + { 1.656 + public: 1.657 + SimpleJSRuntimeStats(MallocSizeOf mallocSizeOf) 1.658 + : JS::RuntimeStats(mallocSizeOf) 1.659 + {} 1.660 + 1.661 + virtual void initExtraZoneStats(JS::Zone *zone, JS::ZoneStats *zStats) 1.662 + MOZ_OVERRIDE 1.663 + {} 1.664 + 1.665 + virtual void initExtraCompartmentStats( 1.666 + JSCompartment *c, JS::CompartmentStats *cStats) MOZ_OVERRIDE 1.667 + {} 1.668 + }; 1.669 + 1.670 + SimpleJSRuntimeStats rtStats(mallocSizeOf); 1.671 + 1.672 + JS::Zone *zone = GetObjectZone(obj); 1.673 + 1.674 + if (!rtStats.compartmentStatsVector.reserve(zone->compartments.length())) 1.675 + return false; 1.676 + 1.677 + if (!rtStats.zoneStatsVector.reserve(1)) 1.678 + return false; 1.679 + 1.680 + // Take the per-compartment measurements. 1.681 + StatsClosure closure(&rtStats, opv); 1.682 + if (!closure.init()) 1.683 + return false; 1.684 + IterateZoneCompartmentsArenasCells(rt, zone, &closure, StatsZoneCallback, 1.685 + StatsCompartmentCallback, StatsArenaCallback, 1.686 + StatsCellCallback<CoarseGrained>); 1.687 + 1.688 + JS_ASSERT(rtStats.zoneStatsVector.length() == 1); 1.689 + rtStats.zTotals.addSizes(rtStats.zoneStatsVector[0]); 1.690 + 1.691 + for (size_t i = 0; i < rtStats.compartmentStatsVector.length(); i++) { 1.692 + CompartmentStats &cStats = rtStats.compartmentStatsVector[i]; 1.693 + rtStats.cTotals.add(cStats); 1.694 + } 1.695 + 1.696 + for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) 1.697 + comp->compartmentStats = nullptr; 1.698 + 1.699 + rtStats.zTotals.addToTabSizes(sizes); 1.700 + rtStats.cTotals.addToTabSizes(sizes); 1.701 + 1.702 + return true; 1.703 +} 1.704 + 1.705 +} // namespace JS 1.706 +