diff --git a/js/public/MemoryMetrics.h b/js/public/MemoryMetrics.h index 08a43a2e017..a58d2df627d 100644 --- a/js/public/MemoryMetrics.h +++ b/js/public/MemoryMetrics.h @@ -64,6 +64,35 @@ struct TypeInferenceSizes size_t temporary; }; +// These measurements relate directly to the JSRuntime, and not to +// compartments within it. +struct RuntimeSizes +{ + RuntimeSizes() + : object(0) + , atomsTable(0) + , contexts(0) + , dtoa(0) + , temporary(0) + , mjitCode(0) + , regexpCode(0) + , unusedCodeMemory(0) + , stackCommitted(0) + , gcMarker(0) + {} + + size_t object; + size_t atomsTable; + size_t contexts; + size_t dtoa; + size_t temporary; + size_t mjitCode; + size_t regexpCode; + size_t unusedCodeMemory; + size_t stackCommitted; + size_t gcMarker; +}; + struct CompartmentStats { CompartmentStats() { @@ -102,16 +131,7 @@ struct CompartmentStats struct RuntimeStats { RuntimeStats(JSMallocSizeOfFun mallocSizeOf) - : runtimeObject(0) - , runtimeAtomsTable(0) - , runtimeContexts(0) - , runtimeDtoa(0) - , runtimeTemporary(0) - , runtimeMjitCode(0) - , runtimeRegexpCode(0) - , runtimeUnusedCodeMemory(0) - , runtimeStackCommitted(0) - , runtimeGCMarker(0) + : runtime() , gcHeapChunkTotal(0) , gcHeapCommitted(0) , gcHeapUnused(0) @@ -133,16 +153,8 @@ struct RuntimeStats , mallocSizeOf(mallocSizeOf) {} - size_t runtimeObject; - size_t runtimeAtomsTable; - size_t runtimeContexts; - size_t runtimeDtoa; - size_t runtimeTemporary; - size_t runtimeMjitCode; - size_t runtimeRegexpCode; - size_t runtimeUnusedCodeMemory; - size_t runtimeStackCommitted; - size_t runtimeGCMarker; + js::RuntimeSizes runtime; + size_t gcHeapChunkTotal; size_t gcHeapCommitted; size_t gcHeapUnused; diff --git a/js/src/MemoryMetrics.cpp b/js/src/MemoryMetrics.cpp index f3e27e84f38..95207d327b3 100644 --- a/js/src/MemoryMetrics.cpp +++ b/js/src/MemoryMetrics.cpp @@ -195,23 +195,8 @@ CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats) StatsArenaCallback, StatsCellCallback); IterateChunks(rt, rtStats, StatsChunkCallback); - rtStats->runtimeObject = rtStats->mallocSizeOf(rt); + rt->sizeOfIncludingThis(rtStats->mallocSizeOf, &rtStats->runtime); - rt->sizeOfExcludingThis(rtStats->mallocSizeOf, - &rtStats->runtimeDtoa, - &rtStats->runtimeTemporary, - &rtStats->runtimeMjitCode, - &rtStats->runtimeRegexpCode, - &rtStats->runtimeUnusedCodeMemory, - &rtStats->runtimeStackCommitted, - &rtStats->runtimeGCMarker); - - rtStats->runtimeAtomsTable = - rt->atomState.atoms.sizeOfExcludingThis(rtStats->mallocSizeOf); - - for (ContextIter acx(rt); !acx.done(); acx.next()) - rtStats->runtimeContexts += acx->sizeOfIncludingThis(rtStats->mallocSizeOf); - // This is initialized to all bytes stored in used chunks, and then we // subtract used space from it each time around the loop. rtStats->gcHeapChunkDirtyUnused = rtStats->gcHeapChunkTotal - @@ -219,7 +204,7 @@ CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats) rtStats->gcHeapChunkCleanDecommitted - rtStats->gcHeapChunkDirtyDecommitted; - rtStats->totalMjit = rtStats->runtimeMjitCode; + rtStats->totalMjit = rtStats->runtime.mjitCode; for (size_t index = 0; index < rtStats->compartmentStatsVector.length(); @@ -293,19 +278,7 @@ GetExplicitNonHeapForRuntime(JSRuntime *rt, JSMallocSizeOfFun mallocSizeOf) // explicit/runtime/regexp-code // explicit/runtime/stack-committed // explicit/runtime/unused-code-memory - size_t dummy, mjitCode, regexpCode, unusedCodeMemory, stackCommitted; - rt->sizeOfExcludingThis(mallocSizeOf, - &dummy, - &dummy, - &mjitCode, - ®expCode, - &unusedCodeMemory, - &stackCommitted, - NULL); - n += mjitCode; - n += regexpCode; - n += unusedCodeMemory; - n += stackCommitted; + n += rt->sizeOfExplicitNonHeap(); return int64_t(n); } diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 82d07c97be7..d15bd3c2cee 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -81,6 +81,7 @@ # include "methodjit/MethodJIT.h" #endif #include "gc/Marking.h" +#include "js/MemoryMetrics.h" #include "frontend/TokenStream.h" #include "frontend/ParseMaps.h" #include "yarr/BumpPointerAllocator.h" @@ -94,26 +95,40 @@ using namespace js; using namespace js::gc; void -JSRuntime::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *dtoa, size_t *temporary, - size_t *mjitCode, size_t *regexpCode, size_t *unusedCodeMemory, - size_t *stackCommitted, size_t *gcMarkerSize) +JSRuntime::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, RuntimeSizes *runtime) { - if (dtoa) - *dtoa = mallocSizeOf(dtoaState); + runtime->object = mallocSizeOf(this); + + runtime->atomsTable = atomState.atoms.sizeOfExcludingThis(mallocSizeOf); + + runtime->contexts = 0; + for (ContextIter acx(this); !acx.done(); acx.next()) + runtime->contexts += acx->sizeOfIncludingThis(mallocSizeOf); - if (temporary) - *temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf); + runtime->dtoa = mallocSizeOf(dtoaState); + + runtime->temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf); if (execAlloc_) - execAlloc_->sizeOfCode(mjitCode, regexpCode, unusedCodeMemory); + execAlloc_->sizeOfCode(&runtime->mjitCode, &runtime->regexpCode, + &runtime->unusedCodeMemory); else - *mjitCode = *regexpCode = *unusedCodeMemory = 0; + runtime->mjitCode = runtime->regexpCode = runtime->unusedCodeMemory = 0; - if (stackCommitted) - *stackCommitted = stackSpace.sizeOfCommitted(); + runtime->stackCommitted = stackSpace.sizeOfCommitted(); - if (gcMarkerSize) - *gcMarkerSize = gcMarker.sizeOfExcludingThis(mallocSizeOf); + runtime->gcMarker = gcMarker.sizeOfExcludingThis(mallocSizeOf); +} + +size_t +JSRuntime::sizeOfExplicitNonHeap() +{ + if (!execAlloc_) + return 0; + + size_t mjitCode, regexpCode, unusedCodeMemory; + execAlloc_->sizeOfCode(&mjitCode, ®expCode, &unusedCodeMemory); + return mjitCode + regexpCode + unusedCodeMemory + stackSpace.sizeOfCommitted(); } void diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 15ca0267514..dde06589b89 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -376,6 +376,10 @@ class FreeOp : public JSFreeOp { } /* namespace js */ +namespace JS { +struct RuntimeSizes; +} + struct JSRuntime : js::RuntimeFriendFields { /* Default compartment. */ @@ -880,9 +884,8 @@ struct JSRuntime : js::RuntimeFriendFields return jitHardening; } - void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *dtoa, size_t *temporary, - size_t *mjitCode, size_t *regexpCode, size_t *unusedCodeMemory, - size_t *stackCommitted, size_t *gcMarker); + void sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, js::RuntimeSizes *runtime); + size_t sizeOfExplicitNonHeap(); }; /* Common macros to access thread-local caches in JSRuntime. */ diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 93c7c4b97bd..c8fcaebc639 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -1533,50 +1533,50 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats, } REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/runtime-object"), - nsIMemoryReporter::KIND_HEAP, rtStats.runtimeObject, + nsIMemoryReporter::KIND_HEAP, rtStats.runtime.object, "Memory used by the JSRuntime object."); REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/atoms-table"), - nsIMemoryReporter::KIND_HEAP, rtStats.runtimeAtomsTable, + nsIMemoryReporter::KIND_HEAP, rtStats.runtime.atomsTable, "Memory used by the atoms table."); REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/contexts"), - nsIMemoryReporter::KIND_HEAP, rtStats.runtimeContexts, + nsIMemoryReporter::KIND_HEAP, rtStats.runtime.contexts, "Memory used by JSContext objects and certain structures " "hanging off them."); REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/dtoa"), - nsIMemoryReporter::KIND_HEAP, rtStats.runtimeDtoa, + nsIMemoryReporter::KIND_HEAP, rtStats.runtime.dtoa, "Memory used by DtoaState, which is used for converting " "strings to numbers and vice versa."); REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/temporary"), - nsIMemoryReporter::KIND_HEAP, rtStats.runtimeTemporary, + nsIMemoryReporter::KIND_HEAP, rtStats.runtime.temporary, "Memory held transiently in JSRuntime and used during " "compilation. It mostly holds parse nodes."); REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/mjit-code"), - nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeMjitCode, + nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.mjitCode, "Memory used by the method JIT to hold the runtime's " "generated code."); REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/regexp-code"), - nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeRegexpCode, + nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.regexpCode, "Memory used by the regexp JIT to hold generated code."); REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/unused-code-memory"), - nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeUnusedCodeMemory, + nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.unusedCodeMemory, "Memory allocated by the method and/or regexp JIT to hold the " "runtime's code, but which is currently unused."); REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/stack-committed"), - nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeStackCommitted, + nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.stackCommitted, "Memory used for the JS call stack. This is the committed " "portion of the stack; the uncommitted portion is not " "measured because it hardly costs anything."); REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/gc-marker"), - nsIMemoryReporter::KIND_HEAP, rtStats.runtimeGCMarker, + nsIMemoryReporter::KIND_HEAP, rtStats.runtime.gcMarker, "Memory used for the GC mark stack and gray roots."); REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap-chunk-dirty-unused"),