mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
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:
parent
d4b26e602c
commit
12f9b52d1e
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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()!
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -19,6 +19,7 @@ EXPORTS = \
|
||||
qsObjectHelper.h \
|
||||
xpcObjectHelper.h \
|
||||
xpcpublic.h \
|
||||
XPCJSMemoryReporter.h \
|
||||
dombindings.h \
|
||||
dombindings_gen.h
|
||||
|
||||
|
33
js/xpconnect/src/XPCJSMemoryReporter.h
Normal file
33
js/xpconnect/src/XPCJSMemoryReporter.h
Normal 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
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user