mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1181452 - Add memory reporting infrastructure for Servo to SpiderMonkey. r=till.
Basically, this change is all about aggregating SpiderMonkey's fine-grained measurements into the new set of coarse-grained measurements, called ServoSizes (which is similar to the existing TabSizes). The change utilizes and extends the existing macro machinery to do this in a way that has some chance to maintaining correctness over the long-term despite the fact that this code is so fiddly.
This commit is contained in:
parent
ffe648a61f
commit
3a776e8b2d
@ -54,6 +54,43 @@ struct TabSizes
|
|||||||
size_t other;
|
size_t other;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// These are the measurements used by Servo. It's important that this is a POD
|
||||||
|
// struct so that Servo can have a parallel |repr(C)| Rust equivalent.
|
||||||
|
struct ServoSizes
|
||||||
|
{
|
||||||
|
enum Kind {
|
||||||
|
GCHeapUsed,
|
||||||
|
GCHeapUnused,
|
||||||
|
GCHeapAdmin,
|
||||||
|
GCHeapDecommitted,
|
||||||
|
MallocHeap,
|
||||||
|
NonHeap,
|
||||||
|
Ignore
|
||||||
|
};
|
||||||
|
|
||||||
|
ServoSizes() { mozilla::PodZero(this); }
|
||||||
|
|
||||||
|
void add(Kind kind, size_t n) {
|
||||||
|
switch (kind) {
|
||||||
|
case GCHeapUsed: gcHeapUsed += n; break;
|
||||||
|
case GCHeapUnused: gcHeapUnused += n; break;
|
||||||
|
case GCHeapAdmin: gcHeapAdmin += n; break;
|
||||||
|
case GCHeapDecommitted: gcHeapDecommitted += n; break;
|
||||||
|
case MallocHeap: mallocHeap += n; break;
|
||||||
|
case NonHeap: nonHeap += n; break;
|
||||||
|
case Ignore: /* do nothing */ break;
|
||||||
|
default: MOZ_CRASH("bad ServoSizes kind");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t gcHeapUsed;
|
||||||
|
size_t gcHeapUnused;
|
||||||
|
size_t gcHeapAdmin;
|
||||||
|
size_t gcHeapDecommitted;
|
||||||
|
size_t mallocHeap;
|
||||||
|
size_t nonHeap;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace JS
|
} // namespace JS
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
@ -92,24 +129,24 @@ struct CStringHashPolicy
|
|||||||
// 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.
|
||||||
//
|
//
|
||||||
|
// - The |tabKind| value is used when measuring TabSizes.
|
||||||
|
//
|
||||||
|
// - The |servoKind| value is used when measuring ServoSizes and also for
|
||||||
|
// the various sizeOfLiveGCThings() methods.
|
||||||
|
//
|
||||||
// In some classes, one or more of the macro arguments aren't used. We use '_'
|
// In some classes, one or more of the macro arguments aren't used. We use '_'
|
||||||
// for those.
|
// for those.
|
||||||
//
|
//
|
||||||
#define DECL_SIZE(kind, gc, mSize) size_t mSize;
|
#define DECL_SIZE(tabKind, servoKind, mSize) size_t mSize;
|
||||||
#define ZERO_SIZE(kind, gc, mSize) mSize(0),
|
#define ZERO_SIZE(tabKind, servoKind, mSize) mSize(0),
|
||||||
#define COPY_OTHER_SIZE(kind, gc, mSize) mSize(other.mSize),
|
#define COPY_OTHER_SIZE(tabKind, servoKind, mSize) mSize(other.mSize),
|
||||||
#define ADD_OTHER_SIZE(kind, gc, mSize) mSize += other.mSize;
|
#define ADD_OTHER_SIZE(tabKind, servoKind, mSize) mSize += other.mSize;
|
||||||
#define SUB_OTHER_SIZE(kind, gc, mSize) MOZ_ASSERT(mSize >= other.mSize); \
|
#define SUB_OTHER_SIZE(tabKind, servoKind, mSize) MOZ_ASSERT(mSize >= other.mSize); \
|
||||||
mSize -= other.mSize;
|
mSize -= other.mSize;
|
||||||
#define ADD_SIZE_TO_N(kind, gc, mSize) n += mSize;
|
#define ADD_SIZE_TO_N(tabKind, servoKind, mSize) n += mSize;
|
||||||
#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(kind, gc, mSize) n += (js::gc) ? mSize : 0;
|
#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) n += (ServoSizes::servoKind == ServoSizes::GCHeapUsed) ? mSize : 0;
|
||||||
#define ADD_TO_TAB_SIZES(kind, gc, mSize) sizes->add(JS::TabSizes::kind, mSize);
|
#define ADD_TO_TAB_SIZES(tabKind, servoKind, mSize) sizes->add(JS::TabSizes::tabKind, mSize);
|
||||||
|
#define ADD_TO_SERVO_SIZES(tabKind, servoKind, mSize) sizes->add(JS::ServoSizes::servoKind, mSize);
|
||||||
// Used to annotate which size_t fields measure live GC things and which don't.
|
|
||||||
enum {
|
|
||||||
NotLiveGCThing = false,
|
|
||||||
IsLiveGCThing = true
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
@ -118,21 +155,21 @@ namespace JS {
|
|||||||
struct ClassInfo
|
struct ClassInfo
|
||||||
{
|
{
|
||||||
#define FOR_EACH_SIZE(macro) \
|
#define FOR_EACH_SIZE(macro) \
|
||||||
macro(Objects, IsLiveGCThing, objectsGCHeap) \
|
macro(Objects, GCHeapUsed, objectsGCHeap) \
|
||||||
macro(Objects, NotLiveGCThing, objectsMallocHeapSlots) \
|
macro(Objects, MallocHeap, objectsMallocHeapSlots) \
|
||||||
macro(Objects, NotLiveGCThing, objectsMallocHeapElementsNonAsmJS) \
|
macro(Objects, MallocHeap, objectsMallocHeapElementsNonAsmJS) \
|
||||||
macro(Objects, NotLiveGCThing, objectsMallocHeapElementsAsmJS) \
|
macro(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \
|
||||||
macro(Objects, NotLiveGCThing, objectsNonHeapElementsAsmJS) \
|
macro(Objects, NonHeap, objectsNonHeapElementsAsmJS) \
|
||||||
macro(Objects, NotLiveGCThing, objectsNonHeapElementsMapped) \
|
macro(Objects, NonHeap, objectsNonHeapElementsMapped) \
|
||||||
macro(Objects, NotLiveGCThing, objectsNonHeapCodeAsmJS) \
|
macro(Objects, NonHeap, objectsNonHeapCodeAsmJS) \
|
||||||
macro(Objects, NotLiveGCThing, objectsMallocHeapMisc) \
|
macro(Objects, MallocHeap, objectsMallocHeapMisc) \
|
||||||
\
|
\
|
||||||
macro(Other, IsLiveGCThing, shapesGCHeapTree) \
|
macro(Other, GCHeapUsed, shapesGCHeapTree) \
|
||||||
macro(Other, IsLiveGCThing, shapesGCHeapDict) \
|
macro(Other, GCHeapUsed, shapesGCHeapDict) \
|
||||||
macro(Other, IsLiveGCThing, shapesGCHeapBase) \
|
macro(Other, GCHeapUsed, shapesGCHeapBase) \
|
||||||
macro(Other, NotLiveGCThing, shapesMallocHeapTreeTables) \
|
macro(Other, MallocHeap, shapesMallocHeapTreeTables) \
|
||||||
macro(Other, NotLiveGCThing, shapesMallocHeapDictTables) \
|
macro(Other, MallocHeap, shapesMallocHeapDictTables) \
|
||||||
macro(Other, NotLiveGCThing, shapesMallocHeapTreeKids) \
|
macro(Other, MallocHeap, shapesMallocHeapTreeKids)
|
||||||
|
|
||||||
ClassInfo()
|
ClassInfo()
|
||||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
@ -168,6 +205,10 @@ struct ClassInfo
|
|||||||
FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
|
FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addToServoSizes(ServoSizes *sizes) const {
|
||||||
|
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
|
||||||
|
}
|
||||||
|
|
||||||
FOR_EACH_SIZE(DECL_SIZE)
|
FOR_EACH_SIZE(DECL_SIZE)
|
||||||
int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
|
int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
|
|
||||||
@ -201,17 +242,21 @@ struct NotableClassInfo : public ClassInfo
|
|||||||
struct CodeSizes
|
struct CodeSizes
|
||||||
{
|
{
|
||||||
#define FOR_EACH_SIZE(macro) \
|
#define FOR_EACH_SIZE(macro) \
|
||||||
macro(_, _, ion) \
|
macro(_, NonHeap, ion) \
|
||||||
macro(_, _, baseline) \
|
macro(_, NonHeap, baseline) \
|
||||||
macro(_, _, regexp) \
|
macro(_, NonHeap, regexp) \
|
||||||
macro(_, _, other) \
|
macro(_, NonHeap, other) \
|
||||||
macro(_, _, unused)
|
macro(_, NonHeap, unused)
|
||||||
|
|
||||||
CodeSizes()
|
CodeSizes()
|
||||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
dummy()
|
dummy()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
void addToServoSizes(ServoSizes *sizes) const {
|
||||||
|
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
|
||||||
|
}
|
||||||
|
|
||||||
FOR_EACH_SIZE(DECL_SIZE)
|
FOR_EACH_SIZE(DECL_SIZE)
|
||||||
int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
|
int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
|
|
||||||
@ -221,24 +266,30 @@ struct CodeSizes
|
|||||||
// Data for tracking GC memory usage.
|
// Data for tracking GC memory usage.
|
||||||
struct GCSizes
|
struct GCSizes
|
||||||
{
|
{
|
||||||
|
// |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted
|
||||||
|
// 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(_, _, marker) \
|
macro(_, MallocHeap, marker) \
|
||||||
macro(_, _, nurseryCommitted) \
|
macro(_, NonHeap, nurseryCommitted) \
|
||||||
macro(_, _, nurseryDecommitted) \
|
macro(_, NonHeap, nurseryDecommitted) \
|
||||||
macro(_, _, nurseryMallocedBuffers) \
|
macro(_, MallocHeap, nurseryMallocedBuffers) \
|
||||||
macro(_, _, storeBufferVals) \
|
macro(_, MallocHeap, storeBufferVals) \
|
||||||
macro(_, _, storeBufferCells) \
|
macro(_, MallocHeap, storeBufferCells) \
|
||||||
macro(_, _, storeBufferSlots) \
|
macro(_, MallocHeap, storeBufferSlots) \
|
||||||
macro(_, _, storeBufferWholeCells) \
|
macro(_, MallocHeap, storeBufferWholeCells) \
|
||||||
macro(_, _, storeBufferRelocVals) \
|
macro(_, MallocHeap, storeBufferRelocVals) \
|
||||||
macro(_, _, storeBufferRelocCells) \
|
macro(_, MallocHeap, storeBufferRelocCells) \
|
||||||
macro(_, _, storeBufferGenerics)
|
macro(_, MallocHeap, storeBufferGenerics)
|
||||||
|
|
||||||
GCSizes()
|
GCSizes()
|
||||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
dummy()
|
dummy()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
void addToServoSizes(ServoSizes *sizes) const {
|
||||||
|
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
|
||||||
|
}
|
||||||
|
|
||||||
FOR_EACH_SIZE(DECL_SIZE)
|
FOR_EACH_SIZE(DECL_SIZE)
|
||||||
int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
|
int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
|
|
||||||
@ -253,10 +304,10 @@ struct GCSizes
|
|||||||
struct StringInfo
|
struct StringInfo
|
||||||
{
|
{
|
||||||
#define FOR_EACH_SIZE(macro) \
|
#define FOR_EACH_SIZE(macro) \
|
||||||
macro(Strings, IsLiveGCThing, gcHeapLatin1) \
|
macro(Strings, GCHeapUsed, gcHeapLatin1) \
|
||||||
macro(Strings, IsLiveGCThing, gcHeapTwoByte) \
|
macro(Strings, GCHeapUsed, gcHeapTwoByte) \
|
||||||
macro(Strings, NotLiveGCThing, mallocHeapLatin1) \
|
macro(Strings, MallocHeap, mallocHeapLatin1) \
|
||||||
macro(Strings, NotLiveGCThing, mallocHeapTwoByte)
|
macro(Strings, MallocHeap, mallocHeapTwoByte)
|
||||||
|
|
||||||
StringInfo()
|
StringInfo()
|
||||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
@ -290,6 +341,10 @@ struct StringInfo
|
|||||||
FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
|
FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addToServoSizes(ServoSizes *sizes) const {
|
||||||
|
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
|
||||||
|
}
|
||||||
|
|
||||||
FOR_EACH_SIZE(DECL_SIZE)
|
FOR_EACH_SIZE(DECL_SIZE)
|
||||||
uint32_t numCopies; // How many copies of the string have we seen?
|
uint32_t numCopies; // How many copies of the string have we seen?
|
||||||
|
|
||||||
@ -326,9 +381,9 @@ struct NotableStringInfo : public StringInfo
|
|||||||
struct ScriptSourceInfo
|
struct ScriptSourceInfo
|
||||||
{
|
{
|
||||||
#define FOR_EACH_SIZE(macro) \
|
#define FOR_EACH_SIZE(macro) \
|
||||||
macro(_, _, compressed) \
|
macro(_, MallocHeap, compressed) \
|
||||||
macro(_, _, uncompressed) \
|
macro(_, MallocHeap, uncompressed) \
|
||||||
macro(_, _, misc)
|
macro(_, MallocHeap, misc)
|
||||||
|
|
||||||
ScriptSourceInfo()
|
ScriptSourceInfo()
|
||||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
@ -345,6 +400,10 @@ struct ScriptSourceInfo
|
|||||||
numScripts--;
|
numScripts--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addToServoSizes(ServoSizes *sizes) const {
|
||||||
|
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
|
||||||
|
}
|
||||||
|
|
||||||
bool isNotable() const {
|
bool isNotable() const {
|
||||||
static const size_t NotabilityThreshold = 16 * 1024;
|
static const size_t NotabilityThreshold = 16 * 1024;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
@ -387,16 +446,16 @@ struct NotableScriptSourceInfo : public ScriptSourceInfo
|
|||||||
struct RuntimeSizes
|
struct RuntimeSizes
|
||||||
{
|
{
|
||||||
#define FOR_EACH_SIZE(macro) \
|
#define FOR_EACH_SIZE(macro) \
|
||||||
macro(_, _, object) \
|
macro(_, MallocHeap, object) \
|
||||||
macro(_, _, atomsTable) \
|
macro(_, MallocHeap, atomsTable) \
|
||||||
macro(_, _, contexts) \
|
macro(_, MallocHeap, contexts) \
|
||||||
macro(_, _, dtoa) \
|
macro(_, MallocHeap, dtoa) \
|
||||||
macro(_, _, temporary) \
|
macro(_, MallocHeap, temporary) \
|
||||||
macro(_, _, interpreterStack) \
|
macro(_, MallocHeap, interpreterStack) \
|
||||||
macro(_, _, mathCache) \
|
macro(_, MallocHeap, mathCache) \
|
||||||
macro(_, _, uncompressedSourceCache) \
|
macro(_, MallocHeap, uncompressedSourceCache) \
|
||||||
macro(_, _, compressedSourceSet) \
|
macro(_, MallocHeap, compressedSourceSet) \
|
||||||
macro(_, _, scriptData) \
|
macro(_, MallocHeap, scriptData)
|
||||||
|
|
||||||
RuntimeSizes()
|
RuntimeSizes()
|
||||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
@ -417,14 +476,21 @@ struct RuntimeSizes
|
|||||||
js_delete(allScriptSources);
|
js_delete(allScriptSources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addToServoSizes(ServoSizes *sizes) const {
|
||||||
|
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
|
||||||
|
scriptSourceInfo.addToServoSizes(sizes);
|
||||||
|
code.addToServoSizes(sizes);
|
||||||
|
gc.addToServoSizes(sizes);
|
||||||
|
}
|
||||||
|
|
||||||
// The script source measurements in |scriptSourceInfo| are initially for
|
// The script source measurements in |scriptSourceInfo| are initially for
|
||||||
// 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,
|
typedef js::HashMap<const char*, ScriptSourceInfo,
|
||||||
js::CStringHashPolicy,
|
js::CStringHashPolicy,
|
||||||
@ -440,25 +506,25 @@ struct RuntimeSizes
|
|||||||
#undef FOR_EACH_SIZE
|
#undef FOR_EACH_SIZE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GCThingSizes
|
struct UnusedGCThingSizes
|
||||||
{
|
{
|
||||||
#define FOR_EACH_SIZE(macro) \
|
#define FOR_EACH_SIZE(macro) \
|
||||||
macro(_, _, object) \
|
macro(Other, GCHeapUnused, object) \
|
||||||
macro(_, _, script) \
|
macro(Other, GCHeapUnused, script) \
|
||||||
macro(_, _, lazyScript) \
|
macro(Other, GCHeapUnused, lazyScript) \
|
||||||
macro(_, _, shape) \
|
macro(Other, GCHeapUnused, shape) \
|
||||||
macro(_, _, baseShape) \
|
macro(Other, GCHeapUnused, baseShape) \
|
||||||
macro(_, _, objectGroup) \
|
macro(Other, GCHeapUnused, objectGroup) \
|
||||||
macro(_, _, string) \
|
macro(Other, GCHeapUnused, string) \
|
||||||
macro(_, _, symbol) \
|
macro(Other, GCHeapUnused, symbol) \
|
||||||
macro(_, _, jitcode) \
|
macro(Other, GCHeapUnused, jitcode) \
|
||||||
|
|
||||||
GCThingSizes()
|
UnusedGCThingSizes()
|
||||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
dummy()
|
dummy()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
GCThingSizes(GCThingSizes&& other)
|
UnusedGCThingSizes(UnusedGCThingSizes&& other)
|
||||||
: FOR_EACH_SIZE(COPY_OTHER_SIZE)
|
: FOR_EACH_SIZE(COPY_OTHER_SIZE)
|
||||||
dummy()
|
dummy()
|
||||||
{}
|
{}
|
||||||
@ -475,11 +541,11 @@ struct GCThingSizes
|
|||||||
case JS::TraceKind::LazyScript: lazyScript += n; break;
|
case JS::TraceKind::LazyScript: lazyScript += n; break;
|
||||||
case JS::TraceKind::ObjectGroup: objectGroup += n; break;
|
case JS::TraceKind::ObjectGroup: objectGroup += n; break;
|
||||||
default:
|
default:
|
||||||
MOZ_CRASH("Bad trace kind for GCThingSizes");
|
MOZ_CRASH("Bad trace kind for UnusedGCThingSizes");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addSizes(const GCThingSizes& other) {
|
void addSizes(const UnusedGCThingSizes& other) {
|
||||||
FOR_EACH_SIZE(ADD_OTHER_SIZE)
|
FOR_EACH_SIZE(ADD_OTHER_SIZE)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,6 +555,14 @@ struct GCThingSizes
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addToTabSizes(JS::TabSizes *sizes) const {
|
||||||
|
FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
|
||||||
|
}
|
||||||
|
|
||||||
|
void addToServoSizes(JS::ServoSizes *sizes) const {
|
||||||
|
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
|
||||||
|
}
|
||||||
|
|
||||||
FOR_EACH_SIZE(DECL_SIZE)
|
FOR_EACH_SIZE(DECL_SIZE)
|
||||||
int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
|
int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
|
|
||||||
@ -498,15 +572,15 @@ struct GCThingSizes
|
|||||||
struct ZoneStats
|
struct ZoneStats
|
||||||
{
|
{
|
||||||
#define FOR_EACH_SIZE(macro) \
|
#define FOR_EACH_SIZE(macro) \
|
||||||
macro(Other, IsLiveGCThing, symbolsGCHeap) \
|
macro(Other, GCHeapUsed, symbolsGCHeap) \
|
||||||
macro(Other, NotLiveGCThing, gcHeapArenaAdmin) \
|
macro(Other, GCHeapAdmin, gcHeapArenaAdmin) \
|
||||||
macro(Other, IsLiveGCThing, lazyScriptsGCHeap) \
|
macro(Other, GCHeapUsed, lazyScriptsGCHeap) \
|
||||||
macro(Other, NotLiveGCThing, lazyScriptsMallocHeap) \
|
macro(Other, MallocHeap, lazyScriptsMallocHeap) \
|
||||||
macro(Other, IsLiveGCThing, jitCodesGCHeap) \
|
macro(Other, GCHeapUsed, jitCodesGCHeap) \
|
||||||
macro(Other, IsLiveGCThing, objectGroupsGCHeap) \
|
macro(Other, GCHeapUsed, objectGroupsGCHeap) \
|
||||||
macro(Other, NotLiveGCThing, objectGroupsMallocHeap) \
|
macro(Other, MallocHeap, objectGroupsMallocHeap) \
|
||||||
macro(Other, NotLiveGCThing, typePool) \
|
macro(Other, MallocHeap, typePool) \
|
||||||
macro(Other, NotLiveGCThing, baselineStubsOptimized) \
|
macro(Other, MallocHeap, baselineStubsOptimized)
|
||||||
|
|
||||||
ZoneStats()
|
ZoneStats()
|
||||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
@ -558,16 +632,23 @@ struct ZoneStats
|
|||||||
void addToTabSizes(JS::TabSizes* sizes) const {
|
void addToTabSizes(JS::TabSizes* sizes) const {
|
||||||
MOZ_ASSERT(isTotals);
|
MOZ_ASSERT(isTotals);
|
||||||
FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
|
FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
|
||||||
sizes->add(JS::TabSizes::Other, unusedGCThings.totalSize());
|
unusedGCThings.addToTabSizes(sizes);
|
||||||
stringInfo.addToTabSizes(sizes);
|
stringInfo.addToTabSizes(sizes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addToServoSizes(JS::ServoSizes *sizes) const {
|
||||||
|
MOZ_ASSERT(isTotals);
|
||||||
|
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
|
||||||
|
unusedGCThings.addToServoSizes(sizes);
|
||||||
|
stringInfo.addToServoSizes(sizes);
|
||||||
|
}
|
||||||
|
|
||||||
// These string measurements are initially for all strings. At the end,
|
// These string measurements are initially for all strings. At the end,
|
||||||
// if the measurement granularity is FineGrained, we subtract the
|
// if the measurement granularity is FineGrained, we subtract the
|
||||||
// measurements of the notable script sources and move them into
|
// measurements of the notable script sources and move them into
|
||||||
// |notableStrings|.
|
// |notableStrings|.
|
||||||
FOR_EACH_SIZE(DECL_SIZE)
|
FOR_EACH_SIZE(DECL_SIZE)
|
||||||
GCThingSizes unusedGCThings;
|
UnusedGCThingSizes unusedGCThings;
|
||||||
StringInfo stringInfo;
|
StringInfo stringInfo;
|
||||||
void* extra; // This field can be used by embedders.
|
void* extra; // This field can be used by embedders.
|
||||||
|
|
||||||
@ -588,25 +669,29 @@ struct ZoneStats
|
|||||||
|
|
||||||
struct CompartmentStats
|
struct CompartmentStats
|
||||||
{
|
{
|
||||||
|
// 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
|
||||||
|
// it doesn't provide an ObjectPrivateVisitor so the value will always be
|
||||||
|
// zero.
|
||||||
#define FOR_EACH_SIZE(macro) \
|
#define FOR_EACH_SIZE(macro) \
|
||||||
macro(Private, NotLiveGCThing, objectsPrivate) \
|
macro(Private, MallocHeap, objectsPrivate) \
|
||||||
macro(Other, IsLiveGCThing, scriptsGCHeap) \
|
macro(Other, GCHeapUsed, scriptsGCHeap) \
|
||||||
macro(Other, NotLiveGCThing, scriptsMallocHeapData) \
|
macro(Other, MallocHeap, scriptsMallocHeapData) \
|
||||||
macro(Other, NotLiveGCThing, baselineData) \
|
macro(Other, MallocHeap, baselineData) \
|
||||||
macro(Other, NotLiveGCThing, baselineStubsFallback) \
|
macro(Other, MallocHeap, baselineStubsFallback) \
|
||||||
macro(Other, NotLiveGCThing, ionData) \
|
macro(Other, MallocHeap, ionData) \
|
||||||
macro(Other, NotLiveGCThing, typeInferenceTypeScripts) \
|
macro(Other, MallocHeap, typeInferenceTypeScripts) \
|
||||||
macro(Other, NotLiveGCThing, typeInferenceAllocationSiteTables) \
|
macro(Other, MallocHeap, typeInferenceAllocationSiteTables) \
|
||||||
macro(Other, NotLiveGCThing, typeInferenceArrayTypeTables) \
|
macro(Other, MallocHeap, typeInferenceArrayTypeTables) \
|
||||||
macro(Other, NotLiveGCThing, typeInferenceObjectTypeTables) \
|
macro(Other, MallocHeap, typeInferenceObjectTypeTables) \
|
||||||
macro(Other, NotLiveGCThing, compartmentObject) \
|
macro(Other, MallocHeap, compartmentObject) \
|
||||||
macro(Other, NotLiveGCThing, compartmentTables) \
|
macro(Other, MallocHeap, compartmentTables) \
|
||||||
macro(Other, NotLiveGCThing, innerViewsTable) \
|
macro(Other, MallocHeap, innerViewsTable) \
|
||||||
macro(Other, NotLiveGCThing, lazyArrayBuffersTable) \
|
macro(Other, MallocHeap, lazyArrayBuffersTable) \
|
||||||
macro(Other, NotLiveGCThing, objectMetadataTable) \
|
macro(Other, MallocHeap, objectMetadataTable) \
|
||||||
macro(Other, NotLiveGCThing, crossCompartmentWrappersTable) \
|
macro(Other, MallocHeap, crossCompartmentWrappersTable) \
|
||||||
macro(Other, NotLiveGCThing, regexpCompartment) \
|
macro(Other, MallocHeap, regexpCompartment) \
|
||||||
macro(Other, NotLiveGCThing, savedStacksSet)
|
macro(Other, MallocHeap, savedStacksSet)
|
||||||
|
|
||||||
CompartmentStats()
|
CompartmentStats()
|
||||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
@ -658,12 +743,18 @@ struct CompartmentStats
|
|||||||
classInfo.addToTabSizes(sizes);
|
classInfo.addToTabSizes(sizes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addToServoSizes(ServoSizes *sizes) const {
|
||||||
|
MOZ_ASSERT(isTotals);
|
||||||
|
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES);
|
||||||
|
classInfo.addToServoSizes(sizes);
|
||||||
|
}
|
||||||
|
|
||||||
// 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,
|
typedef js::HashMap<const char*, ClassInfo,
|
||||||
js::CStringHashPolicy,
|
js::CStringHashPolicy,
|
||||||
@ -682,13 +773,18 @@ typedef js::Vector<ZoneStats, 0, js::SystemAllocPolicy> ZoneStatsVector;
|
|||||||
|
|
||||||
struct RuntimeStats
|
struct RuntimeStats
|
||||||
{
|
{
|
||||||
|
// |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 from the zones and compartments. Both of those values are not
|
||||||
|
// reported directly, but are just present for sanity-checking other
|
||||||
|
// values.
|
||||||
#define FOR_EACH_SIZE(macro) \
|
#define FOR_EACH_SIZE(macro) \
|
||||||
macro(_, _, gcHeapChunkTotal) \
|
macro(_, Ignore, gcHeapChunkTotal) \
|
||||||
macro(_, _, gcHeapDecommittedArenas) \
|
macro(_, GCHeapDecommitted, gcHeapDecommittedArenas) \
|
||||||
macro(_, _, gcHeapUnusedChunks) \
|
macro(_, GCHeapUnused, gcHeapUnusedChunks) \
|
||||||
macro(_, _, gcHeapUnusedArenas) \
|
macro(_, GCHeapUnused, gcHeapUnusedArenas) \
|
||||||
macro(_, _, gcHeapChunkAdmin) \
|
macro(_, GCHeapAdmin, gcHeapChunkAdmin) \
|
||||||
macro(_, _, gcHeapGCThings) \
|
macro(_, Ignore, gcHeapGCThings)
|
||||||
|
|
||||||
explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf)
|
explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf)
|
||||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||||
@ -709,7 +805,7 @@ struct RuntimeStats
|
|||||||
// - unused bytes
|
// - unused bytes
|
||||||
// - rtStats.gcHeapUnusedChunks (empty chunks)
|
// - rtStats.gcHeapUnusedChunks (empty chunks)
|
||||||
// - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks)
|
// - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks)
|
||||||
// - rtStats.zTotals.unusedGCThings (empty GC thing slots within non-empty arenas)
|
// - rtStats.zTotals.unusedGCThings.totalSize() (empty GC thing slots within non-empty arenas)
|
||||||
// - used bytes
|
// - used bytes
|
||||||
// - rtStats.gcHeapChunkAdmin
|
// - rtStats.gcHeapChunkAdmin
|
||||||
// - rtStats.zTotals.gcHeapArenaAdmin
|
// - rtStats.zTotals.gcHeapArenaAdmin
|
||||||
@ -721,6 +817,11 @@ struct RuntimeStats
|
|||||||
// it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a
|
// it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a
|
||||||
// multiple of the chunk size, which is good.
|
// multiple of the chunk size, which is good.
|
||||||
|
|
||||||
|
void addToServoSizes(ServoSizes *sizes) const {
|
||||||
|
FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)
|
||||||
|
runtime.addToServoSizes(sizes);
|
||||||
|
}
|
||||||
|
|
||||||
FOR_EACH_SIZE(DECL_SIZE)
|
FOR_EACH_SIZE(DECL_SIZE)
|
||||||
|
|
||||||
RuntimeSizes runtime;
|
RuntimeSizes runtime;
|
||||||
@ -774,6 +875,10 @@ extern JS_PUBLIC_API(bool)
|
|||||||
AddSizeOfTab(JSRuntime* rt, JS::HandleObject obj, mozilla::MallocSizeOf mallocSizeOf,
|
AddSizeOfTab(JSRuntime* rt, JS::HandleObject obj, mozilla::MallocSizeOf mallocSizeOf,
|
||||||
ObjectPrivateVisitor* opv, TabSizes* sizes);
|
ObjectPrivateVisitor* opv, TabSizes* sizes);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(bool)
|
||||||
|
AddServoSizeOf(JSRuntime *rt, mozilla::MallocSizeOf mallocSizeOf,
|
||||||
|
ObjectPrivateVisitor *opv, ServoSizes *sizes);
|
||||||
|
|
||||||
} // namespace JS
|
} // namespace JS
|
||||||
|
|
||||||
#undef DECL_SIZE
|
#undef DECL_SIZE
|
||||||
|
@ -693,9 +693,9 @@ FindNotableScriptSources(JS::RuntimeSizes& runtime)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(bool)
|
static bool
|
||||||
JS::CollectRuntimeStats(JSRuntime* rt, RuntimeStats* rtStats, ObjectPrivateVisitor* opv,
|
CollectRuntimeStatsHelper(JSRuntime* rt, RuntimeStats* rtStats, ObjectPrivateVisitor* opv,
|
||||||
bool anonymize)
|
bool anonymize, IterateCellCallback statsCellCallback)
|
||||||
{
|
{
|
||||||
if (!rtStats->compartmentStatsVector.reserve(rt->numCompartments))
|
if (!rtStats->compartmentStatsVector.reserve(rt->numCompartments))
|
||||||
return false;
|
return false;
|
||||||
@ -720,7 +720,7 @@ JS::CollectRuntimeStats(JSRuntime* rt, RuntimeStats* rtStats, ObjectPrivateVisit
|
|||||||
StatsZoneCallback,
|
StatsZoneCallback,
|
||||||
StatsCompartmentCallback,
|
StatsCompartmentCallback,
|
||||||
StatsArenaCallback,
|
StatsArenaCallback,
|
||||||
StatsCellCallback<FineGrained>);
|
statsCellCallback);
|
||||||
|
|
||||||
// Take the "explicit/js/runtime/" measurements.
|
// Take the "explicit/js/runtime/" measurements.
|
||||||
rt->addSizeOfIncludingThis(rtStats->mallocSizeOf_, &rtStats->runtime);
|
rt->addSizeOfIncludingThis(rtStats->mallocSizeOf_, &rtStats->runtime);
|
||||||
@ -728,7 +728,7 @@ JS::CollectRuntimeStats(JSRuntime* rt, RuntimeStats* rtStats, ObjectPrivateVisit
|
|||||||
if (!FindNotableScriptSources(rtStats->runtime))
|
if (!FindNotableScriptSources(rtStats->runtime))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ZoneStatsVector& zs = rtStats->zoneStatsVector;
|
JS::ZoneStatsVector& zs = rtStats->zoneStatsVector;
|
||||||
ZoneStats& zTotals = rtStats->zTotals;
|
ZoneStats& zTotals = rtStats->zTotals;
|
||||||
|
|
||||||
// We don't look for notable strings for zTotals. So we first sum all the
|
// We don't look for notable strings for zTotals. So we first sum all the
|
||||||
@ -743,7 +743,7 @@ JS::CollectRuntimeStats(JSRuntime* rt, RuntimeStats* rtStats, ObjectPrivateVisit
|
|||||||
|
|
||||||
MOZ_ASSERT(!zTotals.allStrings);
|
MOZ_ASSERT(!zTotals.allStrings);
|
||||||
|
|
||||||
CompartmentStatsVector& cs = rtStats->compartmentStatsVector;
|
JS::CompartmentStatsVector& cs = rtStats->compartmentStatsVector;
|
||||||
CompartmentStats& cTotals = rtStats->cTotals;
|
CompartmentStats& cTotals = rtStats->cTotals;
|
||||||
|
|
||||||
// As with the zones, we sum all compartments first, and then get the
|
// As with the zones, we sum all compartments first, and then get the
|
||||||
@ -790,6 +790,13 @@ JS::CollectRuntimeStats(JSRuntime* rt, RuntimeStats* rtStats, ObjectPrivateVisit
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(bool)
|
||||||
|
JS::CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisitor *opv,
|
||||||
|
bool anonymize)
|
||||||
|
{
|
||||||
|
return CollectRuntimeStatsHelper(rt, rtStats, opv, anonymize, StatsCellCallback<FineGrained>);
|
||||||
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(size_t)
|
JS_PUBLIC_API(size_t)
|
||||||
JS::SystemCompartmentCount(JSRuntime* rt)
|
JS::SystemCompartmentCount(JSRuntime* rt)
|
||||||
{
|
{
|
||||||
@ -820,26 +827,26 @@ JS::PeakSizeOfTemporary(const JSRuntime* rt)
|
|||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
|
class SimpleJSRuntimeStats : public JS::RuntimeStats
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SimpleJSRuntimeStats(MallocSizeOf mallocSizeOf)
|
||||||
|
: JS::RuntimeStats(mallocSizeOf)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual void initExtraZoneStats(JS::Zone* zone, JS::ZoneStats* zStats)
|
||||||
|
override
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual void initExtraCompartmentStats(
|
||||||
|
JSCompartment* c, JS::CompartmentStats* cStats) override
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
JS_PUBLIC_API(bool)
|
JS_PUBLIC_API(bool)
|
||||||
AddSizeOfTab(JSRuntime* rt, HandleObject obj, MallocSizeOf mallocSizeOf, ObjectPrivateVisitor* opv,
|
AddSizeOfTab(JSRuntime* rt, HandleObject obj, MallocSizeOf mallocSizeOf, ObjectPrivateVisitor* opv,
|
||||||
TabSizes* sizes)
|
TabSizes* sizes)
|
||||||
{
|
{
|
||||||
class SimpleJSRuntimeStats : public JS::RuntimeStats
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit SimpleJSRuntimeStats(MallocSizeOf mallocSizeOf)
|
|
||||||
: JS::RuntimeStats(mallocSizeOf)
|
|
||||||
{}
|
|
||||||
|
|
||||||
virtual void initExtraZoneStats(JS::Zone* zone, JS::ZoneStats* zStats)
|
|
||||||
override
|
|
||||||
{}
|
|
||||||
|
|
||||||
virtual void initExtraCompartmentStats(
|
|
||||||
JSCompartment* c, JS::CompartmentStats* cStats) override
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
SimpleJSRuntimeStats rtStats(mallocSizeOf);
|
SimpleJSRuntimeStats rtStats(mallocSizeOf);
|
||||||
|
|
||||||
JS::Zone* zone = GetObjectZone(obj);
|
JS::Zone* zone = GetObjectZone(obj);
|
||||||
@ -855,8 +862,10 @@ AddSizeOfTab(JSRuntime* rt, HandleObject obj, MallocSizeOf mallocSizeOf, ObjectP
|
|||||||
StatsClosure closure(&rtStats, opv, /* anonymize = */ false);
|
StatsClosure closure(&rtStats, opv, /* anonymize = */ false);
|
||||||
if (!closure.init())
|
if (!closure.init())
|
||||||
return false;
|
return false;
|
||||||
IterateZoneCompartmentsArenasCells(rt, zone, &closure, StatsZoneCallback,
|
IterateZoneCompartmentsArenasCells(rt, zone, &closure,
|
||||||
StatsCompartmentCallback, StatsArenaCallback,
|
StatsZoneCallback,
|
||||||
|
StatsCompartmentCallback,
|
||||||
|
StatsArenaCallback,
|
||||||
StatsCellCallback<CoarseGrained>);
|
StatsCellCallback<CoarseGrained>);
|
||||||
|
|
||||||
MOZ_ASSERT(rtStats.zoneStatsVector.length() == 1);
|
MOZ_ASSERT(rtStats.zoneStatsVector.length() == 1);
|
||||||
@ -874,5 +883,38 @@ AddSizeOfTab(JSRuntime* rt, HandleObject obj, MallocSizeOf mallocSizeOf, ObjectP
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(bool)
|
||||||
|
AddServoSizeOf(JSRuntime *rt, MallocSizeOf mallocSizeOf, ObjectPrivateVisitor *opv,
|
||||||
|
ServoSizes *sizes)
|
||||||
|
{
|
||||||
|
SimpleJSRuntimeStats rtStats(mallocSizeOf);
|
||||||
|
|
||||||
|
// No need to anonymize because the results will be aggregated.
|
||||||
|
if (!CollectRuntimeStatsHelper(rt, &rtStats, opv, /* anonymize = */ false,
|
||||||
|
StatsCellCallback<CoarseGrained>))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
size_t gcHeapTotalOriginal = sizes->gcHeapUsed +
|
||||||
|
sizes->gcHeapUnused +
|
||||||
|
sizes->gcHeapAdmin +
|
||||||
|
sizes->gcHeapDecommitted;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rtStats.addToServoSizes(sizes);
|
||||||
|
rtStats.zTotals.addToServoSizes(sizes);
|
||||||
|
rtStats.cTotals.addToServoSizes(sizes);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
size_t gcHeapTotal = sizes->gcHeapUsed +
|
||||||
|
sizes->gcHeapUnused +
|
||||||
|
sizes->gcHeapAdmin +
|
||||||
|
sizes->gcHeapDecommitted;
|
||||||
|
MOZ_ASSERT(rtStats.gcHeapChunkTotal == gcHeapTotal - gcHeapTotalOriginal);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace JS
|
} // namespace JS
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user