Bug 1437978 - Add memory reporting for scriptCountsMap. r=nbp
MozReview-Commit-ID: 1AJHhJDJerr
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -771,17 +771,18 @@ struct CompartmentStats
macro(Other, MallocHeap, lazyArrayBuffersTable) \
macro(Other, MallocHeap, objectMetadataTable) \
macro(Other, MallocHeap, crossCompartmentWrappersTable) \
macro(Other, MallocHeap, savedStacksSet) \
macro(Other, MallocHeap, varNamesSet) \
macro(Other, MallocHeap, nonSyntacticLexicalScopesTable) \
macro(Other, MallocHeap, templateLiteralMap) \
macro(Other, MallocHeap, jitCompartment) \
- macro(Other, MallocHeap, privateData)
+ macro(Other, MallocHeap, privateData) \
+ macro(Other, MallocHeap, scriptCountsMap)
CompartmentStats()
: FOR_EACH_SIZE(ZERO_SIZE)
classInfo(),
extra(),
allClasses(nullptr),
notableClasses(),
isTotals(true)
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -678,16 +678,21 @@ struct IonBlockCounts
strcpy(ncode, code);
code_ = ncode;
}
}
const char* code() const {
return code_;
}
+
+ size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+ return mallocSizeOf(description_) + mallocSizeOf(successors_) +
+ mallocSizeOf(code_);
+ }
};
// Execution information for a compiled script which may persist after the
// IonScript is destroyed, for use during profiling.
struct IonScriptCounts
{
private:
// Any previous invalidated compilation(s) for the script.
@@ -738,16 +743,35 @@ struct IonScriptCounts
void setPrevious(IonScriptCounts* previous) {
previous_ = previous;
}
IonScriptCounts* previous() const {
return previous_;
}
+
+ size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+ size_t size = 0;
+ auto currCounts = this;
+ while (currCounts) {
+ const IonScriptCounts* currCount = currCounts;
+ currCounts = currCount->previous_;
+ size += currCount->sizeOfOneIncludingThis(mallocSizeOf);
+ }
+ return size;
+ }
+
+ size_t sizeOfOneIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+ size_t size = mallocSizeOf(this) + mallocSizeOf(blocks_);
+ for (size_t i = 0; i < numBlocks_; i++)
+ blocks_[i].sizeOfExcludingThis(mallocSizeOf);
+ return size;
+ }
+
};
struct VMFunction;
struct AutoFlushICache
{
private:
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -1378,24 +1378,26 @@ JSCompartment::addSizeOfIncludingThis(mo
size_t* lazyArrayBuffersArg,
size_t* objectMetadataTablesArg,
size_t* crossCompartmentWrappersArg,
size_t* savedStacksSet,
size_t* varNamesSet,
size_t* nonSyntacticLexicalEnvironmentsArg,
size_t* templateLiteralMap,
size_t* jitCompartment,
- size_t* privateData)
+ size_t* privateData,
+ size_t* scriptCountsMapArg)
{
*compartmentObject += mallocSizeOf(this);
objectGroups.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables,
tiArrayTypeTables, tiObjectTypeTables,
compartmentTables);
wasm.addSizeOfExcludingThis(mallocSizeOf, compartmentTables);
*innerViewsArg += innerViews.sizeOfExcludingThis(mallocSizeOf);
+
if (lazyArrayBuffers)
*lazyArrayBuffersArg += lazyArrayBuffers->sizeOfIncludingThis(mallocSizeOf);
if (objectMetadataTable)
*objectMetadataTablesArg += objectMetadataTable->sizeOfIncludingThis(mallocSizeOf);
*crossCompartmentWrappersArg += crossCompartmentWrappers.sizeOfExcludingThis(mallocSizeOf);
*savedStacksSet += savedStacks_.sizeOfExcludingThis(mallocSizeOf);
*varNamesSet += varNames_.sizeOfExcludingThis(mallocSizeOf);
if (nonSyntacticLexicalEnvironments_)
@@ -1403,16 +1405,23 @@ JSCompartment::addSizeOfIncludingThis(mo
nonSyntacticLexicalEnvironments_->sizeOfIncludingThis(mallocSizeOf);
*templateLiteralMap += templateLiteralMap_.sizeOfExcludingThis(mallocSizeOf);
if (jitCompartment_)
*jitCompartment += jitCompartment_->sizeOfIncludingThis(mallocSizeOf);
auto callback = runtime_->sizeOfIncludingThisCompartmentCallback;
if (callback)
*privateData += callback(mallocSizeOf, this);
+
+ if (scriptCountsMap) {
+ *scriptCountsMapArg += scriptCountsMap->sizeOfIncludingThis(mallocSizeOf);
+ for (auto r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
+ *scriptCountsMapArg += r.front().value()->sizeOfIncludingThis(mallocSizeOf);
+ }
+ }
}
void
JSCompartment::reportTelemetry()
{
// Only report telemetry for web content, not add-ons or chrome JS.
if (creationOptions_.addonIdOrNull() || isSystem_)
return;
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -776,17 +776,18 @@ struct JSCompartment
size_t* lazyArrayBuffers,
size_t* objectMetadataTables,
size_t* crossCompartmentWrappers,
size_t* savedStacksSet,
size_t* varNamesSet,
size_t* nonSyntacticLexicalScopes,
size_t* templateLiteralMap,
size_t* jitCompartment,
- size_t* privateData);
+ size_t* privateData,
+ size_t* scriptCountsMapArg);
// Object group tables and other state in the compartment.
js::ObjectGroupCompartment objectGroups;
#ifdef JSGC_HASH_TABLE_CHECKS
void checkWrapperMapAfterMovingGC();
void checkScriptMapsAfterMovingGC();
#endif
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1257,16 +1257,24 @@ js::PCCounts*
ScriptCounts::getThrowCounts(size_t offset) {
PCCounts searched = PCCounts(offset);
PCCounts* elem = std::lower_bound(throwCounts_.begin(), throwCounts_.end(), searched);
if (elem == throwCounts_.end() || elem->pcOffset() != offset)
elem = throwCounts_.insert(elem, searched);
return elem;
}
+size_t
+ScriptCounts::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) {
+ return mallocSizeOf(this) +
+ pcCounts_.sizeOfExcludingThis(mallocSizeOf) +
+ throwCounts_.sizeOfExcludingThis(mallocSizeOf) +
+ ionCounts_->sizeOfIncludingThis(mallocSizeOf);
+}
+
void
JSScript::setIonScript(JSRuntime* rt, js::jit::IonScript* ionScript)
{
MOZ_ASSERT_IF(ionScript != ION_DISABLED_SCRIPT, !baselineScript()->hasPendingIonBuilder());
if (hasIonScript())
js::jit::IonScript::writeBarrierPre(zone(), ion);
ion = ionScript;
MOZ_ASSERT_IF(hasIonScript(), hasBaselineScript());
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -210,16 +210,18 @@ class ScriptCounts
// the immediate preceding PCCount, then this throw happened in the same
// basic block.
const PCCounts* getImmediatePrecedingThrowCounts(size_t offset) const;
// Return the counter used to count the number of throws. Allocate it if
// none exists yet. Returns null if the allocation failed.
PCCounts* getThrowCounts(size_t offset);
+ size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
+
private:
friend class ::JSScript;
friend struct ScriptAndCounts;
// This sorted array is used to map an offset to the number of times a
// branch got visited.
PCCountsVector pcCounts_;
--- a/js/src/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -357,17 +357,18 @@ StatsCompartmentCallback(JSContext* cx,
&cStats.lazyArrayBuffersTable,
&cStats.objectMetadataTable,
&cStats.crossCompartmentWrappersTable,
&cStats.savedStacksSet,
&cStats.varNamesSet,
&cStats.nonSyntacticLexicalScopesTable,
&cStats.templateLiteralMap,
&cStats.jitCompartment,
- &cStats.privateData);
+ &cStats.privateData,
+ &cStats.scriptCountsMap);
}
static void
StatsArenaCallback(JSRuntime* rt, void* data, gc::Arena* arena,
JS::TraceKind traceKind, size_t thingSize)
{
RuntimeStats* rtStats = static_cast<StatsClosure*>(data)->rtStats;
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1838,16 +1838,20 @@ ReportCompartmentStats(const JS::Compart
cStats.jitCompartment,
"The JIT compartment.");
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("private-data"),
cStats.privateData,
"Extra data attached to the compartment by XPConnect, including "
"its wrapped-js.");
+ ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("script-counts-map"),
+ cStats.scriptCountsMap,
+ "Profiling-related information for scripts.");
+
if (sundriesGCHeap > 0) {
// We deliberately don't use ZCREPORT_GC_BYTES here.
REPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("sundries/gc-heap"),
sundriesGCHeap,
"The sum of all 'gc-heap' measurements that are too small to be "
"worth showing individually.");
}