Differential D3143 Diff 14286 ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/MemoryMetrics.h
Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/MemoryMetrics.h
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- | ||||
* vim: set ts=8 sts=4 et sw=4 tw=99: | * vim: set ts=8 sts=2 et sw=2 tw=80: | ||||
* This Source Code Form is subject to the terms of the Mozilla Public | * 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 | * 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/. */ | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
#ifndef js_MemoryMetrics_h | #ifndef js_MemoryMetrics_h | ||||
#define js_MemoryMetrics_h | #define js_MemoryMetrics_h | ||||
// These declarations are highly likely to change in the future. Depend on them | // These declarations are highly likely to change in the future. Depend on them | ||||
// at your own risk. | // at your own risk. | ||||
#include "mozilla/MemoryReporting.h" | #include "mozilla/MemoryReporting.h" | ||||
#include "mozilla/PodOperations.h" | |||||
#include "mozilla/TypeTraits.h" | #include "mozilla/TypeTraits.h" | ||||
#include <string.h> | #include <string.h> | ||||
#include "jspubtd.h" | #include "jspubtd.h" | ||||
#include "js/AllocPolicy.h" | #include "js/AllocPolicy.h" | ||||
#include "js/HashTable.h" | #include "js/HashTable.h" | ||||
#include "js/TracingAPI.h" | #include "js/TracingAPI.h" | ||||
#include "js/Utility.h" | #include "js/Utility.h" | ||||
#include "js/Vector.h" | #include "js/Vector.h" | ||||
class nsISupports; // Needed for ObjectPrivateVisitor. | class nsISupports; // Needed for ObjectPrivateVisitor. | ||||
namespace JS { | namespace JS { | ||||
struct TabSizes { | struct TabSizes { | ||||
enum Kind { Objects, Strings, Private, Other }; | enum Kind { Objects, Strings, Private, Other }; | ||||
TabSizes() { mozilla::PodZero(this); } | TabSizes() : objects(0), strings(0), private_(0), other(0) {} | ||||
void add(Kind kind, size_t n) { | void add(Kind kind, size_t n) { | ||||
switch (kind) { | switch (kind) { | ||||
case Objects: | case Objects: | ||||
objects += n; | objects += n; | ||||
break; | break; | ||||
case Strings: | case Strings: | ||||
strings += n; | strings += n; | ||||
Show All 22 Lines | enum Kind { | ||||
GCHeapUnused, | GCHeapUnused, | ||||
GCHeapAdmin, | GCHeapAdmin, | ||||
GCHeapDecommitted, | GCHeapDecommitted, | ||||
MallocHeap, | MallocHeap, | ||||
NonHeap, | NonHeap, | ||||
Ignore | Ignore | ||||
}; | }; | ||||
ServoSizes() { mozilla::PodZero(this); } | ServoSizes() = default; | ||||
void add(Kind kind, size_t n) { | void add(Kind kind, size_t n) { | ||||
switch (kind) { | switch (kind) { | ||||
case GCHeapUsed: | case GCHeapUsed: | ||||
gcHeapUsed += n; | gcHeapUsed += n; | ||||
break; | break; | ||||
case GCHeapUnused: | case GCHeapUnused: | ||||
gcHeapUnused += n; | gcHeapUnused += n; | ||||
Show All 12 Lines | switch (kind) { | ||||
break; | break; | ||||
case Ignore: /* do nothing */ | case Ignore: /* do nothing */ | ||||
break; | break; | ||||
default: | default: | ||||
MOZ_CRASH("bad ServoSizes kind"); | MOZ_CRASH("bad ServoSizes kind"); | ||||
} | } | ||||
} | } | ||||
size_t gcHeapUsed; | size_t gcHeapUsed = 0; | ||||
size_t gcHeapUnused; | size_t gcHeapUnused = 0; | ||||
size_t gcHeapAdmin; | size_t gcHeapAdmin = 0; | ||||
size_t gcHeapDecommitted; | size_t gcHeapDecommitted = 0; | ||||
size_t mallocHeap; | size_t mallocHeap = 0; | ||||
size_t nonHeap; | size_t nonHeap = 0; | ||||
}; | }; | ||||
} // namespace JS | } // namespace JS | ||||
namespace js { | namespace js { | ||||
/** | /** | ||||
* In memory reporting, we have concept of "sundries", line items which are too | * In memory reporting, we have concept of "sundries", line items which are too | ||||
Show All 12 Lines | |||||
* on every hash and match! Beware. | * on every hash and match! Beware. | ||||
*/ | */ | ||||
struct InefficientNonFlatteningStringHashPolicy { | struct InefficientNonFlatteningStringHashPolicy { | ||||
typedef JSString* Lookup; | typedef JSString* Lookup; | ||||
static HashNumber hash(const Lookup& l); | static HashNumber hash(const Lookup& l); | ||||
static bool match(const JSString* const& k, const Lookup& l); | static bool match(const JSString* const& k, const Lookup& l); | ||||
}; | }; | ||||
struct CStringHashPolicy { | |||||
typedef const char* Lookup; | |||||
static HashNumber hash(const Lookup& l); | |||||
static bool match(const char* const& k, const Lookup& l); | |||||
}; | |||||
// This file features many classes with numerous size_t fields, and each such | // This file features many classes with numerous size_t fields, and each such | ||||
// class has one or more methods that need to operate on all of these fields. | // class has one or more methods that need to operate on all of these fields. | ||||
// Writing these individually is error-prone -- it's easy to add a new field | // Writing these individually is error-prone -- it's easy to add a new field | ||||
// without updating all the required methods. So we define a single macro list | // without updating all the required methods. So we define a single macro list | ||||
// in each class to name the fields (and notable characteristics of them), and | // in each class to name the fields (and notable characteristics of them), and | ||||
// then use the following macros to transform those lists into the required | // then use the following macros to transform those lists into the required | ||||
// methods. | // methods. | ||||
// | // | ||||
▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | #define FOR_EACH_SIZE(MACRO) \ | ||||
FOR_EACH_SIZE(DECL_SIZE) int dummy; // present just to absorb the trailing | FOR_EACH_SIZE(DECL_SIZE) int dummy; // present just to absorb the trailing | ||||
// comma from FOR_EACH_SIZE(ZERO_SIZE) | // comma from FOR_EACH_SIZE(ZERO_SIZE) | ||||
#undef FOR_EACH_SIZE | #undef FOR_EACH_SIZE | ||||
}; | }; | ||||
/** Data for tracking GC memory usage. */ | /** Data for tracking GC memory usage. */ | ||||
struct GCSizes { | struct GCSizes { | ||||
// |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted | // |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted | ||||
// because we don't consider the nursery to be part of the GC heap. | // because we don't consider the nursery to be part of the GC heap. | ||||
#define FOR_EACH_SIZE(MACRO) \ | #define FOR_EACH_SIZE(MACRO) \ | ||||
MACRO(_, MallocHeap, marker) \ | MACRO(_, MallocHeap, marker) \ | ||||
MACRO(_, NonHeap, nurseryCommitted) \ | MACRO(_, NonHeap, nurseryCommitted) \ | ||||
MACRO(_, MallocHeap, nurseryMallocedBuffers) \ | MACRO(_, MallocHeap, nurseryMallocedBuffers) \ | ||||
MACRO(_, MallocHeap, storeBufferVals) \ | MACRO(_, MallocHeap, storeBufferVals) \ | ||||
MACRO(_, MallocHeap, storeBufferCells) \ | MACRO(_, MallocHeap, storeBufferCells) \ | ||||
MACRO(_, MallocHeap, storeBufferSlots) \ | MACRO(_, MallocHeap, storeBufferSlots) \ | ||||
MACRO(_, MallocHeap, storeBufferWholeCells) \ | MACRO(_, MallocHeap, storeBufferWholeCells) \ | ||||
▲ Show 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | struct NotableScriptSourceInfo : public ScriptSourceInfo { | ||||
~NotableScriptSourceInfo() { js_free(filename_); } | ~NotableScriptSourceInfo() { js_free(filename_); } | ||||
char* filename_; | char* filename_; | ||||
private: | private: | ||||
NotableScriptSourceInfo(const NotableScriptSourceInfo& info) = delete; | NotableScriptSourceInfo(const NotableScriptSourceInfo& info) = delete; | ||||
}; | }; | ||||
struct HelperThreadStats { | |||||
#define FOR_EACH_SIZE(MACRO) \ | |||||
MACRO(_, MallocHeap, stateData) \ | |||||
MACRO(_, MallocHeap, parseTask) \ | |||||
MACRO(_, MallocHeap, ionBuilder) \ | |||||
MACRO(_, MallocHeap, wasmCompile) | |||||
explicit HelperThreadStats() | |||||
: FOR_EACH_SIZE(ZERO_SIZE) idleThreadCount(0), activeThreadCount(0) {} | |||||
FOR_EACH_SIZE(DECL_SIZE) | |||||
unsigned idleThreadCount; | |||||
unsigned activeThreadCount; | |||||
#undef FOR_EACH_SIZE | |||||
}; | |||||
/** | |||||
* Measurements that not associated with any individual runtime. | |||||
*/ | |||||
struct GlobalStats { | |||||
#define FOR_EACH_SIZE(MACRO) MACRO(_, MallocHeap, tracelogger) | |||||
explicit GlobalStats(mozilla::MallocSizeOf mallocSizeOf) | |||||
: FOR_EACH_SIZE(ZERO_SIZE) mallocSizeOf_(mallocSizeOf) {} | |||||
FOR_EACH_SIZE(DECL_SIZE) | |||||
HelperThreadStats helperThread; | |||||
mozilla::MallocSizeOf mallocSizeOf_; | |||||
#undef FOR_EACH_SIZE | |||||
}; | |||||
/** | /** | ||||
* These measurements relate directly to the JSRuntime, and not to zones, | * These measurements relate directly to the JSRuntime, and not to zones, | ||||
* compartments, and realms within it. | * compartments, and realms within it. | ||||
*/ | */ | ||||
struct RuntimeSizes { | struct RuntimeSizes { | ||||
#define FOR_EACH_SIZE(MACRO) \ | #define FOR_EACH_SIZE(MACRO) \ | ||||
MACRO(_, MallocHeap, object) \ | MACRO(_, MallocHeap, object) \ | ||||
MACRO(_, MallocHeap, atomsTable) \ | MACRO(_, MallocHeap, atomsTable) \ | ||||
MACRO(_, MallocHeap, atomsMarkBitmaps) \ | MACRO(_, MallocHeap, atomsMarkBitmaps) \ | ||||
MACRO(_, MallocHeap, contexts) \ | MACRO(_, MallocHeap, contexts) \ | ||||
MACRO(_, MallocHeap, temporary) \ | MACRO(_, MallocHeap, temporary) \ | ||||
MACRO(_, MallocHeap, interpreterStack) \ | MACRO(_, MallocHeap, interpreterStack) \ | ||||
MACRO(_, MallocHeap, mathCache) \ | |||||
MACRO(_, MallocHeap, sharedImmutableStringsCache) \ | MACRO(_, MallocHeap, sharedImmutableStringsCache) \ | ||||
MACRO(_, MallocHeap, sharedIntlData) \ | MACRO(_, MallocHeap, sharedIntlData) \ | ||||
MACRO(_, MallocHeap, uncompressedSourceCache) \ | MACRO(_, MallocHeap, uncompressedSourceCache) \ | ||||
MACRO(_, MallocHeap, scriptData) \ | MACRO(_, MallocHeap, scriptData) \ | ||||
MACRO(_, MallocHeap, tracelogger) | MACRO(_, MallocHeap, tracelogger) \ | ||||
MACRO(_, MallocHeap, wasmRuntime) \ | |||||
MACRO(_, MallocHeap, jitLazyLink) | |||||
RuntimeSizes() | RuntimeSizes() | ||||
: FOR_EACH_SIZE(ZERO_SIZE) scriptSourceInfo(), | : FOR_EACH_SIZE(ZERO_SIZE) scriptSourceInfo(), | ||||
code(), | code(), | ||||
gc(), | gc(), | ||||
notableScriptSources() { | notableScriptSources() { | ||||
allScriptSources = js_new<ScriptSourcesHashMap>(); | allScriptSources = js_new<ScriptSourcesHashMap>(); | ||||
if (!allScriptSources || !allScriptSources->init()) MOZ_CRASH("oom"); | if (!allScriptSources) { | ||||
MOZ_CRASH("oom"); | |||||
} | |||||
} | } | ||||
~RuntimeSizes() { | ~RuntimeSizes() { | ||||
// |allScriptSources| is usually deleted and set to nullptr before this | // |allScriptSources| is usually deleted and set to nullptr before this | ||||
// destructor runs. But there are failure cases due to OOMs that may | // destructor runs. But there are failure cases due to OOMs that may | ||||
// prevent that, so it doesn't hurt to try again here. | // prevent that, so it doesn't hurt to try again here. | ||||
js_delete(allScriptSources); | js_delete(allScriptSources); | ||||
} | } | ||||
Show All 9 Lines | #define FOR_EACH_SIZE(MACRO) \ | ||||
// all script sources. At the end, if the measurement granularity is | // all script sources. At the end, if the measurement granularity is | ||||
// FineGrained, we subtract the measurements of the notable script sources | // FineGrained, we subtract the measurements of the notable script sources | ||||
// and move them into |notableScriptSources|. | // and move them into |notableScriptSources|. | ||||
FOR_EACH_SIZE(DECL_SIZE) | FOR_EACH_SIZE(DECL_SIZE) | ||||
ScriptSourceInfo scriptSourceInfo; | ScriptSourceInfo scriptSourceInfo; | ||||
CodeSizes code; | CodeSizes code; | ||||
GCSizes gc; | GCSizes gc; | ||||
typedef js::HashMap<const char*, ScriptSourceInfo, js::CStringHashPolicy, | typedef js::HashMap<const char*, ScriptSourceInfo, mozilla::CStringHasher, | ||||
js::SystemAllocPolicy> | js::SystemAllocPolicy> | ||||
ScriptSourcesHashMap; | ScriptSourcesHashMap; | ||||
// |allScriptSources| is only used transiently. During the reporting phase | // |allScriptSources| is only used transiently. During the reporting phase | ||||
// it is filled with info about every script source in the runtime. It's | // it is filled with info about every script source in the runtime. It's | ||||
// then used to fill in |notableScriptSources| (which actually gets | // then used to fill in |notableScriptSources| (which actually gets | ||||
// reported), and immediately discarded afterwards. | // reported), and immediately discarded afterwards. | ||||
ScriptSourcesHashMap* allScriptSources; | ScriptSourcesHashMap* allScriptSources; | ||||
js::Vector<NotableScriptSourceInfo, 0, js::SystemAllocPolicy> | js::Vector<NotableScriptSourceInfo, 0, js::SystemAllocPolicy> | ||||
notableScriptSources; | notableScriptSources; | ||||
#undef FOR_EACH_SIZE | #undef FOR_EACH_SIZE | ||||
}; | }; | ||||
struct UnusedGCThingSizes { | struct UnusedGCThingSizes { | ||||
#define FOR_EACH_SIZE(MACRO) \ | #define FOR_EACH_SIZE(MACRO) \ | ||||
MACRO(Other, GCHeapUnused, object) \ | MACRO(Other, GCHeapUnused, object) \ | ||||
MACRO(Other, GCHeapUnused, script) \ | MACRO(Other, GCHeapUnused, script) \ | ||||
MACRO(Other, GCHeapUnused, lazyScript) \ | MACRO(Other, GCHeapUnused, lazyScript) \ | ||||
MACRO(Other, GCHeapUnused, shape) \ | MACRO(Other, GCHeapUnused, shape) \ | ||||
MACRO(Other, GCHeapUnused, baseShape) \ | MACRO(Other, GCHeapUnused, baseShape) \ | ||||
MACRO(Other, GCHeapUnused, objectGroup) \ | MACRO(Other, GCHeapUnused, objectGroup) \ | ||||
MACRO(Other, GCHeapUnused, string) \ | MACRO(Other, GCHeapUnused, string) \ | ||||
MACRO(Other, GCHeapUnused, symbol) \ | MACRO(Other, GCHeapUnused, symbol) \ | ||||
MACRO(Other, GCHeapUnused, bigInt) \ | |||||
MACRO(Other, GCHeapUnused, jitcode) \ | MACRO(Other, GCHeapUnused, jitcode) \ | ||||
MACRO(Other, GCHeapUnused, scope) \ | MACRO(Other, GCHeapUnused, scope) \ | ||||
MACRO(Other, GCHeapUnused, regExpShared) | MACRO(Other, GCHeapUnused, regExpShared) | ||||
UnusedGCThingSizes() : FOR_EACH_SIZE(ZERO_SIZE) dummy() {} | UnusedGCThingSizes() : FOR_EACH_SIZE(ZERO_SIZE) dummy() {} | ||||
UnusedGCThingSizes(UnusedGCThingSizes&& other) | UnusedGCThingSizes(UnusedGCThingSizes&& other) | ||||
: FOR_EACH_SIZE(COPY_OTHER_SIZE) dummy() {} | : FOR_EACH_SIZE(COPY_OTHER_SIZE) dummy() {} | ||||
void addToKind(JS::TraceKind kind, intptr_t n) { | void addToKind(JS::TraceKind kind, intptr_t n) { | ||||
switch (kind) { | switch (kind) { | ||||
case JS::TraceKind::Object: | case JS::TraceKind::Object: | ||||
object += n; | object += n; | ||||
break; | break; | ||||
case JS::TraceKind::String: | case JS::TraceKind::String: | ||||
string += n; | string += n; | ||||
break; | break; | ||||
case JS::TraceKind::Symbol: | case JS::TraceKind::Symbol: | ||||
symbol += n; | symbol += n; | ||||
break; | break; | ||||
case JS::TraceKind::BigInt: | |||||
bigInt += n; | |||||
break; | |||||
case JS::TraceKind::Script: | case JS::TraceKind::Script: | ||||
script += n; | script += n; | ||||
break; | break; | ||||
case JS::TraceKind::Shape: | case JS::TraceKind::Shape: | ||||
shape += n; | shape += n; | ||||
break; | break; | ||||
case JS::TraceKind::BaseShape: | case JS::TraceKind::BaseShape: | ||||
baseShape += n; | baseShape += n; | ||||
Show All 35 Lines | #define FOR_EACH_SIZE(MACRO) \ | ||||
FOR_EACH_SIZE(DECL_SIZE) int dummy; // present just to absorb the trailing | FOR_EACH_SIZE(DECL_SIZE) int dummy; // present just to absorb the trailing | ||||
// comma from FOR_EACH_SIZE(ZERO_SIZE) | // comma from FOR_EACH_SIZE(ZERO_SIZE) | ||||
#undef FOR_EACH_SIZE | #undef FOR_EACH_SIZE | ||||
}; | }; | ||||
struct ZoneStats { | struct ZoneStats { | ||||
#define FOR_EACH_SIZE(MACRO) \ | #define FOR_EACH_SIZE(MACRO) \ | ||||
MACRO(Other, GCHeapUsed, symbolsGCHeap) \ | MACRO(Other, GCHeapUsed, symbolsGCHeap) \ | ||||
MACRO(Other, GCHeapUsed, bigIntsGCHeap) \ | |||||
MACRO(Other, MallocHeap, bigIntsMallocHeap) \ | |||||
MACRO(Other, GCHeapAdmin, gcHeapArenaAdmin) \ | MACRO(Other, GCHeapAdmin, gcHeapArenaAdmin) \ | ||||
MACRO(Other, GCHeapUsed, lazyScriptsGCHeap) \ | MACRO(Other, GCHeapUsed, lazyScriptsGCHeap) \ | ||||
MACRO(Other, MallocHeap, lazyScriptsMallocHeap) \ | MACRO(Other, MallocHeap, lazyScriptsMallocHeap) \ | ||||
MACRO(Other, GCHeapUsed, jitCodesGCHeap) \ | MACRO(Other, GCHeapUsed, jitCodesGCHeap) \ | ||||
MACRO(Other, GCHeapUsed, objectGroupsGCHeap) \ | MACRO(Other, GCHeapUsed, objectGroupsGCHeap) \ | ||||
MACRO(Other, MallocHeap, objectGroupsMallocHeap) \ | MACRO(Other, MallocHeap, objectGroupsMallocHeap) \ | ||||
MACRO(Other, GCHeapUsed, scopesGCHeap) \ | MACRO(Other, GCHeapUsed, scopesGCHeap) \ | ||||
MACRO(Other, MallocHeap, scopesMallocHeap) \ | MACRO(Other, MallocHeap, scopesMallocHeap) \ | ||||
MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \ | MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \ | ||||
MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \ | MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \ | ||||
MACRO(Other, MallocHeap, typePool) \ | MACRO(Other, MallocHeap, typePool) \ | ||||
MACRO(Other, MallocHeap, regexpZone) \ | MACRO(Other, MallocHeap, regexpZone) \ | ||||
MACRO(Other, MallocHeap, jitZone) \ | MACRO(Other, MallocHeap, jitZone) \ | ||||
MACRO(Other, MallocHeap, baselineStubsOptimized) \ | MACRO(Other, MallocHeap, baselineStubsOptimized) \ | ||||
MACRO(Other, MallocHeap, cachedCFG) \ | MACRO(Other, MallocHeap, cachedCFG) \ | ||||
MACRO(Other, MallocHeap, uniqueIdMap) \ | MACRO(Other, MallocHeap, uniqueIdMap) \ | ||||
MACRO(Other, MallocHeap, shapeTables) | MACRO(Other, MallocHeap, shapeTables) \ | ||||
MACRO(Other, MallocHeap, compartmentObjects) \ | |||||
MACRO(Other, MallocHeap, crossCompartmentWrappersTables) \ | |||||
MACRO(Other, MallocHeap, compartmentsPrivateData) | |||||
ZoneStats() | ZoneStats() | ||||
: FOR_EACH_SIZE(ZERO_SIZE) unusedGCThings(), | : FOR_EACH_SIZE(ZERO_SIZE) unusedGCThings(), | ||||
stringInfo(), | stringInfo(), | ||||
shapeInfo(), | shapeInfo(), | ||||
extra(), | extra(), | ||||
allStrings(nullptr), | allStrings(nullptr), | ||||
notableStrings(), | notableStrings(), | ||||
isTotals(true) {} | isTotals(true) {} | ||||
ZoneStats(ZoneStats&& other) | ZoneStats(ZoneStats&& other) | ||||
: FOR_EACH_SIZE(COPY_OTHER_SIZE) | : FOR_EACH_SIZE(COPY_OTHER_SIZE) | ||||
unusedGCThings(mozilla::Move(other.unusedGCThings)), | unusedGCThings(std::move(other.unusedGCThings)), | ||||
stringInfo(mozilla::Move(other.stringInfo)), | stringInfo(std::move(other.stringInfo)), | ||||
shapeInfo(mozilla::Move(other.shapeInfo)), | shapeInfo(std::move(other.shapeInfo)), | ||||
extra(other.extra), | extra(other.extra), | ||||
allStrings(other.allStrings), | allStrings(other.allStrings), | ||||
notableStrings(mozilla::Move(other.notableStrings)), | notableStrings(std::move(other.notableStrings)), | ||||
isTotals(other.isTotals) { | isTotals(other.isTotals) { | ||||
other.allStrings = nullptr; | other.allStrings = nullptr; | ||||
MOZ_ASSERT(!other.isTotals); | MOZ_ASSERT(!other.isTotals); | ||||
} | } | ||||
~ZoneStats() { | ~ZoneStats() { | ||||
// |allStrings| is usually deleted and set to nullptr before this | // |allStrings| is usually deleted and set to nullptr before this | ||||
// destructor runs. But there are failure cases due to OOMs that may | // destructor runs. But there are failure cases due to OOMs that may | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | #define FOR_EACH_SIZE(MACRO) \ | ||||
// discarded afterwards. | // discarded afterwards. | ||||
StringsHashMap* allStrings; | StringsHashMap* allStrings; | ||||
js::Vector<NotableStringInfo, 0, js::SystemAllocPolicy> notableStrings; | js::Vector<NotableStringInfo, 0, js::SystemAllocPolicy> notableStrings; | ||||
bool isTotals; | bool isTotals; | ||||
#undef FOR_EACH_SIZE | #undef FOR_EACH_SIZE | ||||
}; | }; | ||||
struct CompartmentStats { | struct RealmStats { | ||||
// We assume that |objectsPrivate| is on the malloc heap, but it's not | // We assume that |objectsPrivate| is on the malloc heap, but it's not | ||||
// actually guaranteed. But for Servo, at least, it's a moot point because | // actually guaranteed. But for Servo, at least, it's a moot point because | ||||
// it doesn't provide an ObjectPrivateVisitor so the value will always be | // it doesn't provide an ObjectPrivateVisitor so the value will always be | ||||
// zero. | // zero. | ||||
#define FOR_EACH_SIZE(MACRO) \ | #define FOR_EACH_SIZE(MACRO) \ | ||||
MACRO(Private, MallocHeap, objectsPrivate) \ | MACRO(Private, MallocHeap, objectsPrivate) \ | ||||
MACRO(Other, GCHeapUsed, scriptsGCHeap) \ | MACRO(Other, GCHeapUsed, scriptsGCHeap) \ | ||||
MACRO(Other, MallocHeap, scriptsMallocHeapData) \ | MACRO(Other, MallocHeap, scriptsMallocHeapData) \ | ||||
MACRO(Other, MallocHeap, baselineData) \ | MACRO(Other, MallocHeap, baselineData) \ | ||||
MACRO(Other, MallocHeap, baselineStubsFallback) \ | MACRO(Other, MallocHeap, baselineStubsFallback) \ | ||||
MACRO(Other, MallocHeap, ionData) \ | MACRO(Other, MallocHeap, ionData) \ | ||||
MACRO(Other, MallocHeap, typeInferenceTypeScripts) \ | MACRO(Other, MallocHeap, typeInferenceTypeScripts) \ | ||||
MACRO(Other, MallocHeap, typeInferenceAllocationSiteTables) \ | MACRO(Other, MallocHeap, typeInferenceAllocationSiteTables) \ | ||||
MACRO(Other, MallocHeap, typeInferenceArrayTypeTables) \ | MACRO(Other, MallocHeap, typeInferenceArrayTypeTables) \ | ||||
MACRO(Other, MallocHeap, typeInferenceObjectTypeTables) \ | MACRO(Other, MallocHeap, typeInferenceObjectTypeTables) \ | ||||
MACRO(Other, MallocHeap, compartmentObject) \ | MACRO(Other, MallocHeap, realmObject) \ | ||||
MACRO(Other, MallocHeap, compartmentTables) \ | MACRO(Other, MallocHeap, realmTables) \ | ||||
MACRO(Other, MallocHeap, innerViewsTable) \ | MACRO(Other, MallocHeap, innerViewsTable) \ | ||||
MACRO(Other, MallocHeap, lazyArrayBuffersTable) \ | MACRO(Other, MallocHeap, lazyArrayBuffersTable) \ | ||||
MACRO(Other, MallocHeap, objectMetadataTable) \ | MACRO(Other, MallocHeap, objectMetadataTable) \ | ||||
MACRO(Other, MallocHeap, crossCompartmentWrappersTable) \ | |||||
MACRO(Other, MallocHeap, savedStacksSet) \ | MACRO(Other, MallocHeap, savedStacksSet) \ | ||||
MACRO(Other, MallocHeap, varNamesSet) \ | MACRO(Other, MallocHeap, varNamesSet) \ | ||||
MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable) \ | MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable) \ | ||||
MACRO(Other, MallocHeap, jitCompartment) \ | MACRO(Other, MallocHeap, jitRealm) \ | ||||
MACRO(Other, MallocHeap, privateData) \ | |||||
MACRO(Other, MallocHeap, scriptCountsMap) | MACRO(Other, MallocHeap, scriptCountsMap) | ||||
CompartmentStats() | RealmStats() | ||||
: FOR_EACH_SIZE(ZERO_SIZE) classInfo(), | : FOR_EACH_SIZE(ZERO_SIZE) classInfo(), | ||||
extra(), | extra(), | ||||
allClasses(nullptr), | allClasses(nullptr), | ||||
notableClasses(), | notableClasses(), | ||||
isTotals(true) {} | isTotals(true) {} | ||||
CompartmentStats(CompartmentStats&& other) | RealmStats(RealmStats&& other) | ||||
: FOR_EACH_SIZE(COPY_OTHER_SIZE) | : FOR_EACH_SIZE(COPY_OTHER_SIZE) classInfo(std::move(other.classInfo)), | ||||
classInfo(mozilla::Move(other.classInfo)), | |||||
extra(other.extra), | extra(other.extra), | ||||
allClasses(other.allClasses), | allClasses(other.allClasses), | ||||
notableClasses(mozilla::Move(other.notableClasses)), | notableClasses(std::move(other.notableClasses)), | ||||
isTotals(other.isTotals) { | isTotals(other.isTotals) { | ||||
other.allClasses = nullptr; | other.allClasses = nullptr; | ||||
MOZ_ASSERT(!other.isTotals); | MOZ_ASSERT(!other.isTotals); | ||||
} | } | ||||
CompartmentStats(const CompartmentStats&) = delete; // disallow copying | RealmStats(const RealmStats&) = delete; // disallow copying | ||||
~CompartmentStats() { | ~RealmStats() { | ||||
// |allClasses| is usually deleted and set to nullptr before this | // |allClasses| is usually deleted and set to nullptr before this | ||||
// destructor runs. But there are failure cases due to OOMs that may | // destructor runs. But there are failure cases due to OOMs that may | ||||
// prevent that, so it doesn't hurt to try again here. | // prevent that, so it doesn't hurt to try again here. | ||||
js_delete(allClasses); | js_delete(allClasses); | ||||
} | } | ||||
bool initClasses(); | bool initClasses(); | ||||
void addSizes(const CompartmentStats& other) { | void addSizes(const RealmStats& other) { | ||||
MOZ_ASSERT(isTotals); | MOZ_ASSERT(isTotals); | ||||
FOR_EACH_SIZE(ADD_OTHER_SIZE) | FOR_EACH_SIZE(ADD_OTHER_SIZE) | ||||
classInfo.add(other.classInfo); | classInfo.add(other.classInfo); | ||||
} | } | ||||
size_t sizeOfLiveGCThings() const { | size_t sizeOfLiveGCThings() const { | ||||
MOZ_ASSERT(isTotals); | MOZ_ASSERT(isTotals); | ||||
size_t n = 0; | size_t n = 0; | ||||
Show All 16 Lines | #define FOR_EACH_SIZE(MACRO) \ | ||||
// The class measurements in |classInfo| are initially for all classes. At | // The class measurements in |classInfo| are initially for all classes. At | ||||
// the end, if the measurement granularity is FineGrained, we subtract the | // the end, if the measurement granularity is FineGrained, we subtract the | ||||
// measurements of the notable classes and move them into |notableClasses|. | // measurements of the notable classes and move them into |notableClasses|. | ||||
FOR_EACH_SIZE(DECL_SIZE) | FOR_EACH_SIZE(DECL_SIZE) | ||||
ClassInfo classInfo; | ClassInfo classInfo; | ||||
void* extra; // This field can be used by embedders. | void* extra; // This field can be used by embedders. | ||||
typedef js::HashMap<const char*, ClassInfo, js::CStringHashPolicy, | typedef js::HashMap<const char*, ClassInfo, mozilla::CStringHasher, | ||||
js::SystemAllocPolicy> | js::SystemAllocPolicy> | ||||
ClassesHashMap; | ClassesHashMap; | ||||
// These are similar to |allStrings| and |notableStrings| in ZoneStats. | // These are similar to |allStrings| and |notableStrings| in ZoneStats. | ||||
ClassesHashMap* allClasses; | ClassesHashMap* allClasses; | ||||
js::Vector<NotableClassInfo, 0, js::SystemAllocPolicy> notableClasses; | js::Vector<NotableClassInfo, 0, js::SystemAllocPolicy> notableClasses; | ||||
bool isTotals; | bool isTotals; | ||||
#undef FOR_EACH_SIZE | #undef FOR_EACH_SIZE | ||||
}; | }; | ||||
typedef js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> | typedef js::Vector<RealmStats, 0, js::SystemAllocPolicy> RealmStatsVector; | ||||
CompartmentStatsVector; | |||||
typedef js::Vector<ZoneStats, 0, js::SystemAllocPolicy> ZoneStatsVector; | typedef js::Vector<ZoneStats, 0, js::SystemAllocPolicy> ZoneStatsVector; | ||||
struct RuntimeStats { | struct RuntimeStats { | ||||
// |gcHeapChunkTotal| is ignored because it's the sum of all the other | // |gcHeapChunkTotal| is ignored because it's the sum of all the other | ||||
// values. |gcHeapGCThings| is ignored because it's the sum of some of the | // values. |gcHeapGCThings| is ignored because it's the sum of some of the | ||||
// values from the zones and compartments. Both of those values are not | // values from the zones and compartments. Both of those values are not | ||||
// reported directly, but are just present for sanity-checking other | // reported directly, but are just present for sanity-checking other | ||||
// values. | // values. | ||||
#define FOR_EACH_SIZE(MACRO) \ | #define FOR_EACH_SIZE(MACRO) \ | ||||
MACRO(_, Ignore, gcHeapChunkTotal) \ | MACRO(_, Ignore, gcHeapChunkTotal) \ | ||||
MACRO(_, GCHeapDecommitted, gcHeapDecommittedArenas) \ | MACRO(_, GCHeapDecommitted, gcHeapDecommittedArenas) \ | ||||
MACRO(_, GCHeapUnused, gcHeapUnusedChunks) \ | MACRO(_, GCHeapUnused, gcHeapUnusedChunks) \ | ||||
MACRO(_, GCHeapUnused, gcHeapUnusedArenas) \ | MACRO(_, GCHeapUnused, gcHeapUnusedArenas) \ | ||||
MACRO(_, GCHeapAdmin, gcHeapChunkAdmin) \ | MACRO(_, GCHeapAdmin, gcHeapChunkAdmin) \ | ||||
MACRO(_, Ignore, gcHeapGCThings) | MACRO(_, Ignore, gcHeapGCThings) | ||||
explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf) | explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf) | ||||
: FOR_EACH_SIZE(ZERO_SIZE) runtime(), | : FOR_EACH_SIZE(ZERO_SIZE) runtime(), | ||||
cTotals(), | realmTotals(), | ||||
zTotals(), | zTotals(), | ||||
compartmentStatsVector(), | realmStatsVector(), | ||||
zoneStatsVector(), | zoneStatsVector(), | ||||
currZoneStats(nullptr), | currZoneStats(nullptr), | ||||
mallocSizeOf_(mallocSizeOf) {} | mallocSizeOf_(mallocSizeOf) {} | ||||
// Here's a useful breakdown of the GC heap. | // Here's a useful breakdown of the GC heap. | ||||
// | // | ||||
// - rtStats.gcHeapChunkTotal | // - rtStats.gcHeapChunkTotal | ||||
// - decommitted bytes | // - decommitted bytes | ||||
Show All 20 Lines | void addToServoSizes(ServoSizes* sizes) const { | ||||
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) | FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) | ||||
runtime.addToServoSizes(sizes); | runtime.addToServoSizes(sizes); | ||||
} | } | ||||
FOR_EACH_SIZE(DECL_SIZE) | FOR_EACH_SIZE(DECL_SIZE) | ||||
RuntimeSizes runtime; | RuntimeSizes runtime; | ||||
CompartmentStats | RealmStats realmTotals; // The sum of this runtime's realms' measurements. | ||||
cTotals; // The sum of this runtime's compartments' measurements. | |||||
ZoneStats zTotals; // The sum of this runtime's zones' measurements. | ZoneStats zTotals; // The sum of this runtime's zones' measurements. | ||||
CompartmentStatsVector compartmentStatsVector; | RealmStatsVector realmStatsVector; | ||||
ZoneStatsVector zoneStatsVector; | ZoneStatsVector zoneStatsVector; | ||||
ZoneStats* currZoneStats; | ZoneStats* currZoneStats; | ||||
mozilla::MallocSizeOf mallocSizeOf_; | mozilla::MallocSizeOf mallocSizeOf_; | ||||
virtual void initExtraCompartmentStats(JSCompartment* c, | virtual void initExtraRealmStats(JS::Handle<JS::Realm*> realm, | ||||
CompartmentStats* cstats) = 0; | RealmStats* rstats) = 0; | ||||
virtual void initExtraZoneStats(JS::Zone* zone, ZoneStats* zstats) = 0; | virtual void initExtraZoneStats(JS::Zone* zone, ZoneStats* zstats) = 0; | ||||
#undef FOR_EACH_SIZE | #undef FOR_EACH_SIZE | ||||
}; | }; | ||||
class ObjectPrivateVisitor { | class ObjectPrivateVisitor { | ||||
public: | public: | ||||
// Within CollectRuntimeStats, this method is called for each JS object | // Within CollectRuntimeStats, this method is called for each JS object | ||||
// that has an nsISupports pointer. | // that has an nsISupports pointer. | ||||
virtual size_t sizeOfIncludingThis(nsISupports* aSupports) = 0; | virtual size_t sizeOfIncludingThis(nsISupports* aSupports) = 0; | ||||
// A callback that gets a JSObject's nsISupports pointer, if it has one. | // A callback that gets a JSObject's nsISupports pointer, if it has one. | ||||
// Note: this function does *not* addref |iface|. | // Note: this function does *not* addref |iface|. | ||||
typedef bool (*GetISupportsFun)(JSObject* obj, nsISupports** iface); | typedef bool (*GetISupportsFun)(JSObject* obj, nsISupports** iface); | ||||
GetISupportsFun getISupports_; | GetISupportsFun getISupports_; | ||||
explicit ObjectPrivateVisitor(GetISupportsFun getISupports) | explicit ObjectPrivateVisitor(GetISupportsFun getISupports) | ||||
: getISupports_(getISupports) {} | : getISupports_(getISupports) {} | ||||
}; | }; | ||||
extern JS_PUBLIC_API bool CollectGlobalStats(GlobalStats* gStats); | |||||
extern JS_PUBLIC_API bool CollectRuntimeStats(JSContext* cx, | extern JS_PUBLIC_API bool CollectRuntimeStats(JSContext* cx, | ||||
RuntimeStats* rtStats, | RuntimeStats* rtStats, | ||||
ObjectPrivateVisitor* opv, | ObjectPrivateVisitor* opv, | ||||
bool anonymize); | bool anonymize); | ||||
extern JS_PUBLIC_API size_t SystemCompartmentCount(JSContext* cx); | extern JS_PUBLIC_API size_t SystemCompartmentCount(JSContext* cx); | ||||
extern JS_PUBLIC_API size_t UserCompartmentCount(JSContext* cx); | extern JS_PUBLIC_API size_t UserCompartmentCount(JSContext* cx); | ||||
extern JS_PUBLIC_API size_t SystemRealmCount(JSContext* cx); | |||||
extern JS_PUBLIC_API size_t UserRealmCount(JSContext* cx); | |||||
extern JS_PUBLIC_API size_t PeakSizeOfTemporary(const JSContext* cx); | extern JS_PUBLIC_API size_t PeakSizeOfTemporary(const JSContext* cx); | ||||
extern JS_PUBLIC_API bool AddSizeOfTab(JSContext* cx, JS::HandleObject obj, | extern JS_PUBLIC_API bool AddSizeOfTab(JSContext* cx, JS::HandleObject obj, | ||||
mozilla::MallocSizeOf mallocSizeOf, | mozilla::MallocSizeOf mallocSizeOf, | ||||
ObjectPrivateVisitor* opv, | ObjectPrivateVisitor* opv, | ||||
TabSizes* sizes); | TabSizes* sizes); | ||||
extern JS_PUBLIC_API bool AddServoSizeOf(JSContext* cx, | extern JS_PUBLIC_API bool AddServoSizeOf(JSContext* cx, | ||||
mozilla::MallocSizeOf mallocSizeOf, | mozilla::MallocSizeOf mallocSizeOf, | ||||
ObjectPrivateVisitor* opv, | ObjectPrivateVisitor* opv, | ||||
ServoSizes* sizes); | ServoSizes* sizes); | ||||
extern JS_PUBLIC_API void CollectTraceLoggerStateStats(RuntimeStats* rtStats); | |||||
} // namespace JS | } // namespace JS | ||||
#undef DECL_SIZE | #undef DECL_SIZE | ||||
#undef ZERO_SIZE | #undef ZERO_SIZE | ||||
#undef COPY_OTHER_SIZE | #undef COPY_OTHER_SIZE | ||||
#undef ADD_OTHER_SIZE | #undef ADD_OTHER_SIZE | ||||
#undef SUB_OTHER_SIZE | #undef SUB_OTHER_SIZE | ||||
#undef ADD_SIZE_TO_N | #undef ADD_SIZE_TO_N | ||||
#undef ADD_SIZE_TO_N_IF_LIVE_GC_THING | #undef ADD_SIZE_TO_N_IF_LIVE_GC_THING | ||||
#undef ADD_TO_TAB_SIZES | #undef ADD_TO_TAB_SIZES | ||||
#endif /* js_MemoryMetrics_h */ | #endif /* js_MemoryMetrics_h */ |
Wildfire Games · Phabricator