Bug 687724 (part 3) - Report JS memory consumption for compartments that are associated with |window| objects under "window-objects". r=bholley,jlebar,luke.

--HG--
extra : rebase_source : 20329a698154ef61cea74247d3dccc9f01899829
This commit is contained in:
Nicholas Nethercote 2012-07-05 21:12:37 -07:00
parent d4b26e602c
commit 12f9b52d1e
11 changed files with 225 additions and 98 deletions

View File

@ -10,6 +10,7 @@
#include "mozilla/Preferences.h"
#include "nsNetCID.h"
#include "nsPrintfCString.h"
#include "XPCJSMemoryReporter.h"
using namespace mozilla;
@ -101,10 +102,14 @@ AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr)
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(DOMStyleMallocSizeOf, "windows")
// The key is the window ID.
typedef nsDataHashtable<nsUint64HashKey, nsCString> WindowPaths;
static nsresult
CollectWindowReports(nsGlobalWindow *aWindow,
nsWindowSizes *aWindowTotalSizes,
nsTHashtable<nsUint64HashKey> *aGhostWindowIDs,
WindowPaths *aWindowPaths,
nsIMemoryMultiReporterCallback *aCb,
nsISupports *aClosure)
{
@ -140,6 +145,9 @@ CollectWindowReports(nsGlobalWindow *aWindow,
AppendWindowURI(aWindow, windowPath);
windowPath += NS_LITERAL_CSTRING(")");
// Remember the path for later.
aWindowPaths->Put(aWindow->WindowID(), windowPath);
#define REPORT(_pathTail, _amount, _desc) \
do { \
if (_amount > 0) { \
@ -294,14 +302,23 @@ nsWindowMemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
NS_EFFECTIVETLDSERVICE_CONTRACTID);
NS_ENSURE_STATE(tldService);
WindowPaths windowPaths;
windowPaths.Init();
// Collect window memory usage.
nsWindowSizes windowTotalSizes(NULL);
for (PRUint32 i = 0; i < windows.Length(); i++) {
nsresult rv = CollectWindowReports(windows[i], &windowTotalSizes,
&ghostWindows, aCb, aClosure);
&ghostWindows, &windowPaths,
aCb, aClosure);
NS_ENSURE_SUCCESS(rv, rv);
}
// Report JS memory usage. We do this from here because the JS memory
// multi-reporter needs to be passed |windowPaths|.
nsresult rv = xpc::JSMemoryMultiReporter::CollectReports(&windowPaths, aCb, aClosure);
NS_ENSURE_SUCCESS(rv, rv);
#define REPORT(_path, _amount, _desc) \
do { \
nsresult rv; \
@ -392,9 +409,9 @@ nsWindowMemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
NS_IMETHODIMP
nsWindowMemoryReporter::GetExplicitNonHeap(PRInt64* aAmount)
{
// This reporter only measures heap memory.
*aAmount = 0;
return NS_OK;
// This reporter only measures heap memory, so we don't need to report any
// bytes for it. However, the JS multi-reporter needs to be invoked.
return xpc::JSMemoryMultiReporter::GetExplicitNonHeap(aAmount);
}
PRUint32

View File

@ -133,11 +133,19 @@ struct WorkerJSRuntimeStats : public JS::RuntimeStats
virtual void initExtraCompartmentStats(JSCompartment *c,
JS::CompartmentStats *cstats) MOZ_OVERRIDE
{
MOZ_ASSERT(!cstats->extra);
MOZ_ASSERT(!cstats->extra1);
MOZ_ASSERT(!cstats->extra2);
// ReportJSRuntimeExplicitTreeStats expects that cstats->extra is a char pointer
const char *name = js::IsAtomsCompartment(c) ? "Web Worker Atoms" : "Web Worker";
cstats->extra = const_cast<char *>(name);
// ReportJSRuntimeExplicitTreeStats expects that cstats->{extra1,extra2}
// are char pointers.
// This is the |cPathPrefix|. Using NULL here means that we'll end up
// using WorkerMemoryReporter::mRtPath as the path prefix for each
// compartment. See xpc::ReportJSRuntimeExplicitTreeStats().
cstats->extra1 = NULL;
// This is the |cName|.
cstats->extra2 = (void *)(js::IsAtomsCompartment(c) ? "Web Worker Atoms" : "Web Worker");
}
};
@ -145,7 +153,7 @@ class WorkerMemoryReporter MOZ_FINAL : public nsIMemoryMultiReporter
{
WorkerPrivate* mWorkerPrivate;
nsCString mAddressString;
nsCString mPathPrefix;
nsCString mRtPath;
public:
NS_DECL_ISUPPORTS
@ -175,10 +183,10 @@ public:
}
}
mPathPrefix = NS_LITERAL_CSTRING("explicit/dom/workers(") +
escapedDomain + NS_LITERAL_CSTRING(")/worker(") +
escapedURL + NS_LITERAL_CSTRING(", ") + mAddressString +
NS_LITERAL_CSTRING(")/");
mRtPath = NS_LITERAL_CSTRING("explicit/workers/workers(") +
escapedDomain + NS_LITERAL_CSTRING(")/worker(") +
escapedURL + NS_LITERAL_CSTRING(", ") + mAddressString +
NS_LITERAL_CSTRING(")/");
}
nsresult
@ -232,7 +240,7 @@ public:
// Always report, even if we're disabled, so that we at least get an entry
// in about::memory.
return xpc::ReportJSRuntimeExplicitTreeStats(rtStats, mPathPrefix,
return xpc::ReportJSRuntimeExplicitTreeStats(rtStats, mRtPath,
aCallback, aClosure);
}

View File

@ -85,7 +85,9 @@ struct CompartmentStats
memset(this, 0, sizeof(*this));
}
void *extra;
// These fields can be used by embedders.
void *extra1;
void *extra2;
// If you add a new number, remember to update add() and maybe
// gcHeapThingsSize()!

View File

@ -196,7 +196,7 @@ CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats)
IterateCompartmentsArenasCells(rt, rtStats, StatsCompartmentCallback,
StatsArenaCallback, StatsCellCallback);
// Take the "explcit/js/runtime/" measurements.
// Take the "explicit/js/runtime/" measurements.
rt->sizeOfIncludingThis(rtStats->mallocSizeOf, &rtStats->runtime);
rtStats->gcHeapGcThings = 0;

View File

@ -229,6 +229,18 @@ AssertHeapIsIdle(JSContext *cx)
AssertHeapIsIdle(cx->runtime);
}
static void
AssertHeapIsIdleOrIterating(JSRuntime *rt)
{
JS_ASSERT(rt->heapState != JSRuntime::Collecting);
}
static void
AssertHeapIsIdleOrIterating(JSContext *cx)
{
AssertHeapIsIdleOrIterating(cx->runtime);
}
static void
AssertHeapIsIdleOrStringIsFlat(JSContext *cx, JSString *str)
{
@ -2167,6 +2179,14 @@ JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
return &obj->global();
}
JS_PUBLIC_API(JSObject *)
JS_GetGlobalForCompartmentOrNull(JSContext *cx, JSCompartment *c)
{
AssertHeapIsIdleOrIterating(cx);
assertSameCompartment(cx, c);
return c->maybeGlobal();
}
JS_PUBLIC_API(JSObject *)
JS_GetGlobalForScopeChain(JSContext *cx)
{
@ -5566,7 +5586,7 @@ JS_IsRunning(JSContext *cx)
JS_PUBLIC_API(JSBool)
JS_SaveFrameChain(JSContext *cx)
{
AssertHeapIsIdle(cx);
AssertHeapIsIdleOrIterating(cx);
CHECK_REQUEST(cx);
return cx->stack.saveFrameChain();
}
@ -5574,7 +5594,7 @@ JS_SaveFrameChain(JSContext *cx)
JS_PUBLIC_API(void)
JS_RestoreFrameChain(JSContext *cx)
{
AssertHeapIsIdle(cx);
AssertHeapIsIdleOrIterating(cx);
CHECK_REQUEST(cx);
cx->stack.restoreFrameChain();
}

View File

@ -3053,6 +3053,13 @@ JS_GetObjectPrototype(JSContext *cx, JSObject *forObj);
extern JS_PUBLIC_API(JSObject *)
JS_GetGlobalForObject(JSContext *cx, JSObject *obj);
/*
* May return NULL, if |c| never had a global (e.g. the atoms compartment), or
* if |c|'s global has been collected.
*/
extern JS_PUBLIC_API(JSObject *)
JS_GetGlobalForCompartmentOrNull(JSContext *cx, JSCompartment *c);
extern JS_PUBLIC_API(JSObject *)
JS_GetGlobalForScopeChain(JSContext *cx);

View File

@ -19,6 +19,7 @@ EXPORTS = \
qsObjectHelper.h \
xpcObjectHelper.h \
xpcpublic.h \
XPCJSMemoryReporter.h \
dombindings.h \
dombindings_gen.h

View File

@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=78:
*
* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef XPCJSMemoryReporter_h
#define XPCJSMemoryReporter_h
class nsISupports;
class nsIMemoryMultiReporterCallback;
namespace xpc {
// The key is the window ID.
typedef nsDataHashtable<nsUint64HashKey, nsCString> WindowPaths;
// This is very nearly an instance of nsIMemoryMultiReporter, but it's not,
// because it's invoked by nsWindowMemoryReporter in order to get |windowPaths|
// in CollectReports.
class JSMemoryMultiReporter
{
public:
static nsresult CollectReports(WindowPaths *windowPaths, nsIMemoryMultiReporterCallback *cb,
nsISupports *closure);
static nsresult GetExplicitNonHeap(PRInt64 *n);
};
}
#endif

View File

@ -10,10 +10,12 @@
#include "xpcprivate.h"
#include "xpcpublic.h"
#include "XPCJSMemoryReporter.h"
#include "WrapperFactory.h"
#include "dom_quickstubs.h"
#include "nsIMemoryReporter.h"
#include "nsPIDOMWindow.h"
#include "nsPrintfCString.h"
#include "mozilla/FunctionTimer.h"
#include "prsystem.h"
@ -1286,6 +1288,8 @@ static const size_t SUNDRIES_THRESHOLD = 8192;
rtTotal += amount; \
} while (0)
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsMallocSizeOf, "js")
namespace xpc {
static nsresult
@ -1472,7 +1476,7 @@ ReportCompartmentStats(const JS::CompartmentStats &cStats,
nsresult
ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
const nsACString &pathPrefix,
const nsACString &rtPath,
nsIMemoryMultiReporterCallback *cb,
nsISupports *closure, size_t *rtTotalOut)
{
@ -1483,11 +1487,21 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
size_t gcTotal = 0;
for (size_t i = 0; i < rtStats.compartmentStatsVector.length(); i++) {
JS::CompartmentStats cStats = rtStats.compartmentStatsVector[i];
const char *name = static_cast<char *>(cStats.extra);
nsCString pathPrefix2 = pathPrefix + NS_LITERAL_CSTRING("compartment(") +
nsDependentCString(name) + NS_LITERAL_CSTRING(")/");
const char *cPathPrefix = static_cast<char *>(cStats.extra1);
const char *cName = static_cast<char *>(cStats.extra2);
rv = ReportCompartmentStats(cStats, pathPrefix2, cb, closure, &gcTotal);
// If cPathPrefix is NULL, cPath is "<rtPath>compartment(<cName>)/"
// otherwise, cPath is "<cPathPrefix>compartment(<cName>)/"
nsCString cPath;
if (cPathPrefix) {
cPath.Assign(nsDependentCString(cPathPrefix));
} else {
cPath.Assign(rtPath);
}
cPath += NS_LITERAL_CSTRING("compartment(") +
nsDependentCString(cName) + NS_LITERAL_CSTRING(")/");
rv = ReportCompartmentStats(cStats, cPath, cb, closure, &gcTotal);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -1496,62 +1510,62 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
size_t rtTotal = 0;
RREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/runtime-object"),
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/runtime-object"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.object,
"Memory used by the JSRuntime object.");
RREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/atoms-table"),
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/atoms-table"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.atomsTable,
"Memory used by the atoms table.");
RREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/contexts"),
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/contexts"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.contexts,
"Memory used by JSContext objects and certain structures "
"hanging off them.");
RREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/dtoa"),
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/dtoa"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.dtoa,
"Memory used by DtoaState, which is used for converting "
"strings to numbers and vice versa.");
RREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/temporary"),
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/temporary"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.temporary,
"Memory held transiently in JSRuntime and used during "
"compilation. It mostly holds parse nodes.");
RREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/mjit-code"),
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/mjit-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.mjitCode,
"Memory used by the method JIT to hold the runtime's "
"generated code.");
RREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/regexp-code"),
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/regexp-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.regexpCode,
"Memory used by the regexp JIT to hold generated code.");
RREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/unused-code-memory"),
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/unused-code-memory"),
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.");
RREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/stack-committed"),
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/stack-committed"),
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.");
RREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/gc-marker"),
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc-marker"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.gcMarker,
"Memory used for the GC mark stack and gray roots.");
RREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/math-cache"),
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/math-cache"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.mathCache,
"Memory used for the math cache.");
RREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/script-filenames"),
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/script-filenames"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.scriptFilenames,
"Memory used for the table holding script filenames.");
RREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/compartment-objects"),
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/compartment-objects"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.compartmentObjects,
"Memory used for JSCompartment objects. These are fairly "
"small and all the same size, so they're not worth reporting "
@ -1563,25 +1577,25 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
// Report GC numbers that don't belong to a compartment.
REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap/unused-arenas"),
REPORT_GC_BYTES(rtPath + NS_LITERAL_CSTRING("gc-heap/unused-arenas"),
rtStats.gcHeapUnusedArenas,
"Memory on the garbage-collected JavaScript heap taken by "
"empty arenas within non-empty chunks.");
REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap/unused-chunks"),
REPORT_GC_BYTES(rtPath + NS_LITERAL_CSTRING("gc-heap/unused-chunks"),
rtStats.gcHeapUnusedChunks,
"Memory on the garbage-collected JavaScript heap taken by "
"empty chunks, which will soon be released unless claimed "
"for new allocations.");
REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap/decommitted-arenas"),
REPORT_GC_BYTES(rtPath + NS_LITERAL_CSTRING("gc-heap/decommitted-arenas"),
rtStats.gcHeapDecommittedArenas,
"Memory on the garbage-collected JavaScript heap, "
"in arenas in non-empty chunks, that is returned to the OS. "
"This means it takes up address space but no physical "
"memory or swap space.");
REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap/chunk-admin"),
REPORT_GC_BYTES(rtPath + NS_LITERAL_CSTRING("gc-heap/chunk-admin"),
rtStats.gcHeapChunkAdmin,
"Memory on the garbage-collected JavaScript heap, within "
"chunks, that is used to hold internal bookkeeping "
@ -1596,8 +1610,6 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
} // namespace xpc
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsMallocSizeOf, "js")
class JSCompartmentsMultiReporter MOZ_FINAL : public nsIMemoryMultiReporter
{
public:
@ -1661,36 +1673,64 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(JSCompartmentsMultiReporter
, nsIMemoryMultiReporter
)
struct XPCJSRuntimeStats : public JS::RuntimeStats {
XPCJSRuntimeStats()
: JS::RuntimeStats(JsMallocSizeOf) { }
namespace xpc {
class XPCJSRuntimeStats : public JS::RuntimeStats
{
JSContext *mCx;
WindowPaths *mWindowPaths;
public:
XPCJSRuntimeStats(WindowPaths *windowPaths)
: JS::RuntimeStats(JsMallocSizeOf), mCx(NULL), mWindowPaths(windowPaths)
{ }
bool init(XPCJSRuntime *xpcrt) {
mCx = JS_NewContext(xpcrt->GetJSRuntime(), 0);
return !!mCx;
}
~XPCJSRuntimeStats() {
for (size_t i = 0; i != compartmentStatsVector.length(); ++i)
free(compartmentStatsVector[i].extra);
JS_DestroyContextNoGC(mCx);
for (size_t i = 0; i != compartmentStatsVector.length(); ++i) {
free(compartmentStatsVector[i].extra1);
free(compartmentStatsVector[i].extra2);
}
}
virtual void initExtraCompartmentStats(JSCompartment *c,
JS::CompartmentStats *cstats) MOZ_OVERRIDE {
nsCAutoString name;
GetCompartmentName(c, name);
cstats->extra = strdup(name.get());
nsCAutoString cName, cPathPrefix;
GetCompartmentName(c, cName);
// Get the compartment's global.
if (JSObject *global = JS_GetGlobalForCompartmentOrNull(mCx, c)) {
nsISupports *native = nsXPConnect::GetXPConnect()->GetNativeOfWrapper(mCx, global);
if (nsCOMPtr<nsPIDOMWindow> piwindow = do_QueryInterface(native)) {
// The global is a |window| object. Use the path prefix that
// we should have already created for it.
if (mWindowPaths->Get(piwindow->WindowID(), &cPathPrefix)) {
cPathPrefix.AppendLiteral("/js/");
} else {
cPathPrefix.AssignLiteral("explicit/js-non-window/compartments/unknown-window-global/");
}
} else {
cPathPrefix.AssignLiteral("explicit/js-non-window/compartments/non-window-global/");
}
} else {
cPathPrefix.AssignLiteral("explicit/js-non-window/compartments/no-global/");
}
cstats->extra1 = strdup(cPathPrefix.get());
cstats->extra2 = strdup(cName.get());
}
};
class JSMemoryMultiReporter MOZ_FINAL : public nsIMemoryMultiReporter
{
public:
NS_DECL_ISUPPORTS
NS_IMETHOD GetName(nsACString &name)
{
name.AssignLiteral("js");
return NS_OK;
}
NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *cb,
nsISupports *closure)
nsresult
JSMemoryMultiReporter::CollectReports(WindowPaths *windowPaths,
nsIMemoryMultiReporterCallback *cb,
nsISupports *closure)
{
XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
@ -1699,7 +1739,11 @@ public:
// the callback. Separating these steps is important because the
// callback may be a JS function, and executing JS while getting these
// stats seems like a bad idea.
XPCJSRuntimeStats rtStats;
XPCJSRuntimeStats rtStats(windowPaths);
if (!rtStats.init(xpcrt))
return NS_ERROR_FAILURE;
if (!JS::CollectRuntimeStats(xpcrt->GetJSRuntime(), &rtStats))
return NS_ERROR_FAILURE;
@ -1707,15 +1751,14 @@ public:
xpcrt->SizeOfIncludingThis(JsMallocSizeOf) +
XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(JsMallocSizeOf);
NS_NAMED_LITERAL_CSTRING(explicitJs, "explicit/js/");
// This is the second step (see above). First we report stuff in the
// "explicit" tree, then we report other stuff.
nsresult rv;
size_t rtTotal = 0;
nsresult rv =
xpc::ReportJSRuntimeExplicitTreeStats(rtStats, explicitJs, cb,
closure, &rtTotal);
rv = xpc::ReportJSRuntimeExplicitTreeStats(rtStats,
NS_LITERAL_CSTRING("explicit/js-non-window/"),
cb, closure, &rtTotal);
NS_ENSURE_SUCCESS(rv, rv);
// Report the sums of the compartment numbers.
@ -1727,41 +1770,41 @@ public:
// Report the sum of the runtime/ numbers.
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime/runtime"),
nsIMemoryReporter::KIND_OTHER, rtTotal,
"The sum of all measurements under 'explicit/js/runtime/'.");
"The sum of all measurements under 'explicit/js-non-window/runtime/'.");
// Report the numbers for memory outside of compartments.
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime/gc-heap/decommitted-arenas"),
nsIMemoryReporter::KIND_OTHER,
rtStats.gcHeapDecommittedArenas,
"The same as 'explicit/js/gc-heap/decommitted-arenas'.");
"The same as 'explicit/js-non-window/gc-heap/decommitted-arenas'.");
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime/gc-heap/unused-chunks"),
nsIMemoryReporter::KIND_OTHER,
rtStats.gcHeapUnusedChunks,
"The same as 'explicit/js/gc-heap/unused-chunks'.");
"The same as 'explicit/js-non-window/gc-heap/unused-chunks'.");
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime/gc-heap/unused-arenas"),
nsIMemoryReporter::KIND_OTHER,
rtStats.gcHeapUnusedArenas,
"The same as 'explicit/js/gc-heap/unused-arenas'.");
"The same as 'explicit/js-non-window/gc-heap/unused-arenas'.");
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime/gc-heap/chunk-admin"),
nsIMemoryReporter::KIND_OTHER,
rtStats.gcHeapChunkAdmin,
"The same as 'explicit/js/gc-heap/chunk-admin'.");
"The same as 'explicit/js-non-window/gc-heap/chunk-admin'.");
// Report a breakdown of the committed GC space.
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/chunks"),
nsIMemoryReporter::KIND_OTHER,
rtStats.gcHeapUnusedChunks,
"The same as 'explicit/js/gc-heap/unused-chunks'.");
"The same as 'explicit/js-non-window/gc-heap/unused-chunks'.");
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/arenas"),
nsIMemoryReporter::KIND_OTHER,
rtStats.gcHeapUnusedArenas,
"The same as 'explicit/js/gc-heap/unused-arenas'.");
"The same as 'explicit/js-non-window/gc-heap/unused-arenas'.");
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/unused/gc-things"),
nsIMemoryReporter::KIND_OTHER,
@ -1771,7 +1814,7 @@ public:
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/chunk-admin"),
nsIMemoryReporter::KIND_OTHER,
rtStats.gcHeapChunkAdmin,
"The same as 'explicit/js/gc-heap/chunk-admin'.");
"The same as 'explicit/js-non-window/gc-heap/chunk-admin'.");
REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime-gc-heap-committed/used/arena-admin"),
nsIMemoryReporter::KIND_OTHER,
@ -1793,18 +1836,15 @@ public:
return NS_OK;
}
NS_IMETHOD
GetExplicitNonHeap(PRInt64 *n)
nsresult
JSMemoryMultiReporter::GetExplicitNonHeap(PRInt64 *n)
{
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
*reinterpret_cast<int64_t*>(n) = JS::GetExplicitNonHeapForRuntime(rt, JsMallocSizeOf);
return NS_OK;
}
};
NS_IMPL_THREADSAFE_ISUPPORTS1(JSMemoryMultiReporter
, nsIMemoryMultiReporter
)
} // namespace xpc
#ifdef MOZ_CRASHREPORTER
static JSBool
@ -1956,7 +1996,6 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount));
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount));
NS_RegisterMemoryMultiReporter(new JSMemoryMultiReporter);
NS_RegisterMemoryMultiReporter(new JSCompartmentsMultiReporter);
if (!JS_DHashTableInit(&mJSHolders, JS_DHashGetStubOps(), nsnull,

View File

@ -266,7 +266,7 @@ DOM_DefineQuickStubs(JSContext *cx, JSObject *proto, PRUint32 flags,
// (which isn't all of them).
nsresult
ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
const nsACString &pathPrefix,
const nsACString &rtPath,
nsIMemoryMultiReporterCallback *cb,
nsISupports *closure, size_t *rtTotal = NULL);

View File

@ -43,9 +43,9 @@
let heapAllocatedAmounts = [];
let storageSqliteAmounts = [];
let areJsCompartmentsPresent = false;
let areJsNonWindowCompartmentsPresent = false;
let areWindowObjectsJsCompartmentsPresent = false;
let isSandboxLocationShown = false;
let areWindowObjectsPresent = false;
let isPlacesPresent = false;
let isImagesPresent = false;
let isXptiWorkingSetPresent = false;
@ -71,10 +71,10 @@
storageSqliteAmounts.push(aAmount);
// Check the presence of some other notable reporters.
} else if (aPath.search(/^explicit\/js\/compartment\(/) >= 0) {
areJsCompartmentsPresent = true;
} else if (aPath.search(/^explicit\/window-objects\/top\(/) >= 0) {
areWindowObjectsPresent = true;
} else if (aPath.search(/^explicit\/js-non-window\/.*compartment\(/) >= 0) {
areJsNonWindowCompartmentsPresent = true;
} else if (aPath.search(/^explicit\/window-objects\/top\(.*\/js\/compartment\(/) >= 0) {
areWindowObjectsJsCompartmentsPresent = true;
} else if (aPath.search(/^explicit\/storage\/sqlite\/places.sqlite/) >= 0) {
isPlacesPresent = true;
} else if (aPath.search(/^explicit\/images/) >= 0) {
@ -144,13 +144,13 @@
checkSpecialReport("js-main-runtime-gc-heap-committed/used/gc-things", jsGcHeapAmounts);
checkSpecialReport("storage-sqlite", storageSqliteAmounts);
ok(areJsCompartmentsPresent, "js compartments are present");
ok(isSandboxLocationShown, "sandbox locations are present");
ok(areWindowObjectsPresent, "window objects are present");
ok(isPlacesPresent, "places is present");
ok(isImagesPresent, "images is present");
ok(isXptiWorkingSetPresent, "xpti-working-set is present");
ok(isAtomTablePresent, "atom-table is present");
ok(areJsNonWindowCompartmentsPresent, "js-non-window compartments are present");
ok(areWindowObjectsJsCompartmentsPresent, "window-objects/.../js compartments are present");
ok(isSandboxLocationShown, "sandbox locations are present");
ok(isPlacesPresent, "places is present");
ok(isImagesPresent, "images is present");
ok(isXptiWorkingSetPresent, "xpti-working-set is present");
ok(isAtomTablePresent, "atom-table is present");
]]>
</script>