diff --git a/dom/base/nsDOMMemoryReporter.cpp b/dom/base/nsDOMMemoryReporter.cpp index ce30eb4e720..2d3a27fe1bd 100644 --- a/dom/base/nsDOMMemoryReporter.cpp +++ b/dom/base/nsDOMMemoryReporter.cpp @@ -235,6 +235,13 @@ GetWindows(const PRUint64& aId, nsGlobalWindow*& aWindow, void* aClosure) return PL_DHASH_NEXT; } +NS_IMETHODIMP +nsDOMMemoryMultiReporter::GetName(nsACString &aName) +{ + aName.AssignLiteral("dom+style"); + return NS_OK; +} + NS_IMETHODIMP nsDOMMemoryMultiReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb, nsISupports* aClosure) diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 14cd5bca434..24abe21bc47 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -228,6 +228,12 @@ public: return NS_OK; } + NS_IMETHOD GetName(nsACString &aName) + { + aName.AssignLiteral("workers"); + return NS_OK; + } + NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback* aCallback, nsISupports* aClosure) diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index fefc1e32541..7a600479c2d 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -1711,6 +1711,12 @@ class XPConnectJSCompartmentsMultiReporter : public nsIMemoryMultiReporter public: NS_DECL_ISUPPORTS + NS_IMETHOD GetName(nsACString &name) + { + name.AssignLiteral("js"); + return NS_OK; + } + NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *callback, nsISupports *closure) { diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 84f63089141..606c92add15 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -690,6 +690,13 @@ PresShell::MemoryReporter::SizeEnumerator(PresShellPtrKey *aEntry, NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(GfxTextrunWordCacheMallocSizeOf, "gfx/textrun-word-cache") +NS_IMETHODIMP +PresShell::MemoryReporter::GetName(nsACString &aName) +{ + aName.AssignLiteral("layout"); + return NS_OK; +} + NS_IMETHODIMP PresShell::MemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb, nsISupports* aClosure) diff --git a/storage/src/mozStorageService.cpp b/storage/src/mozStorageService.cpp index 4bcc807f965..4988ede95de 100644 --- a/storage/src/mozStorageService.cpp +++ b/storage/src/mozStorageService.cpp @@ -182,6 +182,12 @@ public: "associated with connections to this database."); } + NS_IMETHOD GetName(nsACString &aName) + { + aName.AssignLiteral("storage-sqlite"); + return NS_OK; + } + // Warning: To get a Connection's measurements requires holding its lock. // There may be a delay getting the lock if another thread is accessing the // Connection. This isn't very nice if CollectReports is called from the diff --git a/toolkit/components/aboutmemory/content/aboutMemory.js b/toolkit/components/aboutmemory/content/aboutMemory.js index 43fc42ca9d5..9c70be2700e 100644 --- a/toolkit/components/aboutmemory/content/aboutMemory.js +++ b/toolkit/components/aboutmemory/content/aboutMemory.js @@ -121,7 +121,8 @@ const kTreeNames = { 'other': 'Other Measurements' }; -const kMapTreePaths = ['map/resident', 'map/pss', 'map/vsize', 'map/swap']; +const kMapTreePaths = + ['smaps/resident', 'smaps/pss', 'smaps/vsize', 'smaps/swap']; function onLoad() { @@ -283,6 +284,11 @@ function getReportersByProcess(aMgr) var e = aMgr.enumerateMultiReporters(); while (e.hasMoreElements()) { var mrOrig = e.getNext().QueryInterface(Ci.nsIMemoryMultiReporter); + // Ignore the "smaps" reporters in non-verbose mode. + if (!gVerbose && mrOrig.name === "smaps") { + continue; + } + try { mrOrig.collectReports(addReporter, null); } @@ -453,7 +459,7 @@ function buildTree(aReporters, aTreeName) // traversal. // There should always be at least one matching reporter when |aTreeName| is - // "explicit". But there may be zero for "map" trees; if that happens, + // "explicit". But there may be zero for "smaps" trees; if that happens, // bail. var foundReporter = false; for (var unsafePath in aReporters) { @@ -552,19 +558,17 @@ function buildTree(aReporters, aTreeName) } /** - * Ignore all the memory reporters that belong to a tree; this involves + * Ignore all the memory reports that belong to a "smaps" tree; this involves * explicitly marking them as done. * * @param aReporters * The table of Reporters, indexed by _unsafePath. - * @param aTreeName - * The name of the tree being built. */ -function ignoreTree(aReporters, aTreeName) +function ignoreSmapsTrees(aReporters) { for (var unsafePath in aReporters) { var r = aReporters[unsafePath]; - if (r.treeNameMatches(aTreeName)) { + if (r.treeNameMatches("smaps")) { var dummy = getBytes(aReporters, unsafePath); } } @@ -785,21 +789,24 @@ function appendProcessElements(aP, aProcess, aReporters, appendTreeElements(aP, explicitTree, aProcess); // We only show these breakdown trees in verbose mode. - kMapTreePaths.forEach(function(t) { - if (gVerbose) { + if (gVerbose) { + kMapTreePaths.forEach(function(t) { var tree = buildTree(aReporters, t); // |tree| will be null if we don't have any reporters for the given // unsafePath. if (tree) { sortTreeAndInsertAggregateNodes(tree._amount, tree); - tree._hideKids = true; // map trees are always initially collapsed + tree._hideKids = true; // smaps trees are always initially collapsed appendTreeElements(aP, tree, aProcess); } - } else { - ignoreTree(aReporters, t); - } - }); + }); + } else { + // Although we skip the "smaps" multi-reporter in getReportersByProcess(), + // we might get some smaps reports from a child process, and they must be + // explicitly ignored. + ignoreSmapsTrees(aReporters); + } // We have to call appendOtherElements after we process all the trees, // because it looks at all the reporters which aren't part of a tree. diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul index 8489d6f7951..d6a3d58db47 100644 --- a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul @@ -92,7 +92,8 @@ f2("", "other4", OTHER, COUNT_CUMULATIVE, 888) ]; var fakeMultiReporters = [ - { collectReports: function(cbObj, closure) { + { name: "fake1", + collectReports: function(cbObj, closure) { function f(p, k, u, a) { cbObj.callback("", p, k, u, a, "(desc)", closure); } f("explicit/c/d", NONHEAP, BYTES, 13 * MB), f("explicit/c/d", NONHEAP, BYTES, 10 * MB), // dup @@ -105,7 +106,8 @@ }, explicitNonHeap: (100 + 13 + 10)*MB + (499 + 100)*KB }, - { collectReports: function(cbObj, closure) { + { name: "fake2", + collectReports: function(cbObj, closure) { function f(p, k, u, a) { cbObj.callback("", p, k, u, a, "(desc)", closure); } f("other3", OTHER, COUNT, 777); f("other2", OTHER, BYTES, 222 * MB); @@ -114,16 +116,17 @@ }, explicitNonHeap: 0 }, - { collectReports: function(cbObj, closure) { + { name: "smaps", + collectReports: function(cbObj, closure) { // The amounts are given in pages, so multiply here by 4kb. function f(p, a) { cbObj.callback("", p, NONHEAP, BYTES, a * 4 * KB, "(desc)", closure); } - f("map/vsize/a", 24); - f("map/swap/a", 1); - f("map/swap/a", 2); - f("map/vsize/a", 19); - f("map/swap/b/c", 10); - f("map/resident/a", 42); - f("map/pss/a", 43); + f("smaps/vsize/a", 24); + f("smaps/swap/a", 1); + f("smaps/swap/a", 2); + f("smaps/vsize/a", 19); + f("smaps/swap/b/c", 10); + f("smaps/resident/a", 42); + f("smaps/pss/a", 43); }, explicitNonHeap: 0 } @@ -197,10 +200,28 @@ f("5th", "explicit/a/neg1", NONHEAP, -20 * KB), f("5th", "explicit/a/neg2", NONHEAP, -10 * KB) ]; + var fakeMultiReporters2 = [ + // Because this multi-reporter is in a child process, the fact that we + // skip the "smaps" multi-reporter in the parent process won't cause + // these to be skipped; the fall-back skipping will be hit instead. + { name: "smaps", + collectReports: function(cbObj, closure) { + // The amounts are given in pages, so multiply here by 4kb. + function f(p, a) { cbObj.callback("2nd", p, NONHEAP, BYTES, a * 4 * KB, "(desc)", closure); } + f("smaps/vsize/a", 24); + f("smaps/vsize/b", 24); + }, + explicitNonHeap: 0 + } + ]; for (var i = 0; i < fakeReporters2.length; i++) { mgr.registerReporter(fakeReporters2[i]); } + for (var i = 0; i < fakeMultiReporters2.length; i++) { + mgr.registerMultiReporter(fakeMultiReporters2[i]); + } fakeReporters = fakeReporters.concat(fakeReporters2); + fakeMultiReporters = fakeMultiReporters.concat(fakeMultiReporters2); ]]> @@ -393,6 +414,9 @@ Explicit Allocations\n\ ├────209,715,200 B (20.00%) ── compartment(compartment-url)\n\ └────105,906,176 B (10.10%) ── heap-unclassified\n\ \n\ +Virtual Size Breakdown\n\ +196,608 B (100.0%) ++ vsize\n\ +\n\ Other Measurements\n\ 698,351,616 B ── danger\n\ 1,048,576,000 B ── heap-allocated\n\ diff --git a/xpcom/base/MapsMemoryReporter.cpp b/xpcom/base/MapsMemoryReporter.cpp index 1851fad440f..7d4482f84b6 100644 --- a/xpcom/base/MapsMemoryReporter.cpp +++ b/xpcom/base/MapsMemoryReporter.cpp @@ -123,7 +123,8 @@ void GetBasename(const nsCString &aPath, nsACString &aOut) } // MapsReporter::CollectReports uses this stuct to keep track of whether it's -// seen a mapping under 'map/resident', 'map/vsize', and 'map/swap'. +// seen a mapping under 'smaps/resident', 'smaps/pss', 'smaps/vsize', and +// 'smaps/swap'. struct CategoriesSeen { CategoriesSeen() : mSeenResident(false), @@ -148,6 +149,12 @@ public: NS_DECL_ISUPPORTS + NS_IMETHOD GetName(nsACString &aName) + { + aName.AssignLiteral("smaps"); + return NS_OK; + } + NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *aCallback, nsISupports *aClosure); @@ -221,16 +228,16 @@ MapsReporter::CollectReports(nsIMemoryMultiReporterCallback *aCallback, fclose(f); - // For sure we should have created some node under 'map/resident' and - // 'map/vsize'; otherwise we're probably not reading smaps correctly. If we - // didn't create a node under 'map/swap', create one here so about:memory - // knows to create an empty 'map/swap' tree. See also bug 682735. + // For sure we should have created some node under 'smaps/resident' and + // 'smaps/vsize'; otherwise we're probably not reading smaps correctly. If we + // didn't create a node under 'smaps/swap', create one here so about:memory + // knows to create an empty 'smaps/swap' tree. See also bug 682735. NS_ASSERTION(categoriesSeen.mSeenVsize, "Didn't create a vsize node?"); NS_ASSERTION(categoriesSeen.mSeenVsize, "Didn't create a resident node?"); if (!categoriesSeen.mSeenSwap) { aCallback->Callback(NS_LITERAL_CSTRING(""), - NS_LITERAL_CSTRING("map/swap/total"), + NS_LITERAL_CSTRING("smaps/swap/total"), nsIMemoryReporter::KIND_NONHEAP, nsIMemoryReporter::UNITS_BYTES, 0, @@ -510,7 +517,7 @@ MapsReporter::ParseMapBody( } nsCAutoString path; - path.Append("map/"); + path.Append("smaps/"); path.Append(category); path.Append("/"); path.Append(aName); diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index e3485a9e216..cfd510582f2 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -216,6 +216,16 @@ interface nsIMemoryMultiReporterCallback : nsISupports [scriptable, uuid(61d498d5-b460-4398-a8ea-7f75208534b4)] interface nsIMemoryMultiReporter : nsISupports { + /* + * The name of the multi-reporter. Useful when only one multi-reporter + * needs to be run. Must be unique; if multi-reporters share names it's + * likely the wrong one will be called in certain circumstances. + */ + readonly attribute ACString name; + + /* + * Run the multi-reporter. + */ void collectReports(in nsIMemoryMultiReporterCallback callback, in nsISupports closure);