Bug 689583 - Add names for memory multi-reporters. r=jlebar.

--HG--
extra : rebase_source : adb3fb2cbbb8a07b60edd48c7dc9a3a4a4763b79
This commit is contained in:
Nicholas Nethercote 2012-02-06 17:02:59 -08:00
parent 836b84312c
commit 610b65aebb
9 changed files with 111 additions and 31 deletions

View File

@ -235,6 +235,13 @@ GetWindows(const PRUint64& aId, nsGlobalWindow*& aWindow, void* aClosure)
return PL_DHASH_NEXT; return PL_DHASH_NEXT;
} }
NS_IMETHODIMP
nsDOMMemoryMultiReporter::GetName(nsACString &aName)
{
aName.AssignLiteral("dom+style");
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsDOMMemoryMultiReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb, nsDOMMemoryMultiReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
nsISupports* aClosure) nsISupports* aClosure)

View File

@ -228,6 +228,12 @@ public:
return NS_OK; return NS_OK;
} }
NS_IMETHOD GetName(nsACString &aName)
{
aName.AssignLiteral("workers");
return NS_OK;
}
NS_IMETHOD NS_IMETHOD
CollectReports(nsIMemoryMultiReporterCallback* aCallback, CollectReports(nsIMemoryMultiReporterCallback* aCallback,
nsISupports* aClosure) nsISupports* aClosure)

View File

@ -1711,6 +1711,12 @@ class XPConnectJSCompartmentsMultiReporter : public nsIMemoryMultiReporter
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_IMETHOD GetName(nsACString &name)
{
name.AssignLiteral("js");
return NS_OK;
}
NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *callback, NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *callback,
nsISupports *closure) nsISupports *closure)
{ {

View File

@ -690,6 +690,13 @@ PresShell::MemoryReporter::SizeEnumerator(PresShellPtrKey *aEntry,
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(GfxTextrunWordCacheMallocSizeOf, "gfx/textrun-word-cache") 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 NS_IMETHODIMP
PresShell::MemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb, PresShell::MemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
nsISupports* aClosure) nsISupports* aClosure)

View File

@ -182,6 +182,12 @@ public:
"associated with connections to this database."); "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. // 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 // 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 // Connection. This isn't very nice if CollectReports is called from the

View File

@ -121,7 +121,8 @@ const kTreeNames = {
'other': 'Other Measurements' '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() function onLoad()
{ {
@ -283,6 +284,11 @@ function getReportersByProcess(aMgr)
var e = aMgr.enumerateMultiReporters(); var e = aMgr.enumerateMultiReporters();
while (e.hasMoreElements()) { while (e.hasMoreElements()) {
var mrOrig = e.getNext().QueryInterface(Ci.nsIMemoryMultiReporter); var mrOrig = e.getNext().QueryInterface(Ci.nsIMemoryMultiReporter);
// Ignore the "smaps" reporters in non-verbose mode.
if (!gVerbose && mrOrig.name === "smaps") {
continue;
}
try { try {
mrOrig.collectReports(addReporter, null); mrOrig.collectReports(addReporter, null);
} }
@ -453,7 +459,7 @@ function buildTree(aReporters, aTreeName)
// traversal. // traversal.
// There should always be at least one matching reporter when |aTreeName| is // 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. // bail.
var foundReporter = false; var foundReporter = false;
for (var unsafePath in aReporters) { 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. * explicitly marking them as done.
* *
* @param aReporters * @param aReporters
* The table of Reporters, indexed by _unsafePath. * 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) { for (var unsafePath in aReporters) {
var r = aReporters[unsafePath]; var r = aReporters[unsafePath];
if (r.treeNameMatches(aTreeName)) { if (r.treeNameMatches("smaps")) {
var dummy = getBytes(aReporters, unsafePath); var dummy = getBytes(aReporters, unsafePath);
} }
} }
@ -785,21 +789,24 @@ function appendProcessElements(aP, aProcess, aReporters,
appendTreeElements(aP, explicitTree, aProcess); appendTreeElements(aP, explicitTree, aProcess);
// We only show these breakdown trees in verbose mode. // 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); var tree = buildTree(aReporters, t);
// |tree| will be null if we don't have any reporters for the given // |tree| will be null if we don't have any reporters for the given
// unsafePath. // unsafePath.
if (tree) { if (tree) {
sortTreeAndInsertAggregateNodes(tree._amount, 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); 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, // 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. // because it looks at all the reporters which aren't part of a tree.

View File

@ -92,7 +92,8 @@
f2("", "other4", OTHER, COUNT_CUMULATIVE, 888) f2("", "other4", OTHER, COUNT_CUMULATIVE, 888)
]; ];
var fakeMultiReporters = [ 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); } 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, 13 * MB),
f("explicit/c/d", NONHEAP, BYTES, 10 * MB), // dup f("explicit/c/d", NONHEAP, BYTES, 10 * MB), // dup
@ -105,7 +106,8 @@
}, },
explicitNonHeap: (100 + 13 + 10)*MB + (499 + 100)*KB 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); } function f(p, k, u, a) { cbObj.callback("", p, k, u, a, "(desc)", closure); }
f("other3", OTHER, COUNT, 777); f("other3", OTHER, COUNT, 777);
f("other2", OTHER, BYTES, 222 * MB); f("other2", OTHER, BYTES, 222 * MB);
@ -114,16 +116,17 @@
}, },
explicitNonHeap: 0 explicitNonHeap: 0
}, },
{ collectReports: function(cbObj, closure) { { name: "smaps",
collectReports: function(cbObj, closure) {
// The amounts are given in pages, so multiply here by 4kb. // 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); } function f(p, a) { cbObj.callback("", p, NONHEAP, BYTES, a * 4 * KB, "(desc)", closure); }
f("map/vsize/a", 24); f("smaps/vsize/a", 24);
f("map/swap/a", 1); f("smaps/swap/a", 1);
f("map/swap/a", 2); f("smaps/swap/a", 2);
f("map/vsize/a", 19); f("smaps/vsize/a", 19);
f("map/swap/b/c", 10); f("smaps/swap/b/c", 10);
f("map/resident/a", 42); f("smaps/resident/a", 42);
f("map/pss/a", 43); f("smaps/pss/a", 43);
}, },
explicitNonHeap: 0 explicitNonHeap: 0
} }
@ -197,10 +200,28 @@
f("5th", "explicit/a/neg1", NONHEAP, -20 * KB), f("5th", "explicit/a/neg1", NONHEAP, -20 * KB),
f("5th", "explicit/a/neg2", NONHEAP, -10 * 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++) { for (var i = 0; i < fakeReporters2.length; i++) {
mgr.registerReporter(fakeReporters2[i]); mgr.registerReporter(fakeReporters2[i]);
} }
for (var i = 0; i < fakeMultiReporters2.length; i++) {
mgr.registerMultiReporter(fakeMultiReporters2[i]);
}
fakeReporters = fakeReporters.concat(fakeReporters2); fakeReporters = fakeReporters.concat(fakeReporters2);
fakeMultiReporters = fakeMultiReporters.concat(fakeMultiReporters2);
]]> ]]>
</script> </script>
@ -393,6 +414,9 @@ Explicit Allocations\n\
├────209,715,200 B (20.00%) ── compartment(compartment-url)\n\ ├────209,715,200 B (20.00%) ── compartment(compartment-url)\n\
└────105,906,176 B (10.10%) ── heap-unclassified\n\ └────105,906,176 B (10.10%) ── heap-unclassified\n\
\n\ \n\
Virtual Size Breakdown\n\
196,608 B (100.0%) ++ vsize\n\
\n\
Other Measurements\n\ Other Measurements\n\
698,351,616 B ── danger<script>window.alert(1)</script>\n\ 698,351,616 B ── danger<script>window.alert(1)</script>\n\
1,048,576,000 B ── heap-allocated\n\ 1,048,576,000 B ── heap-allocated\n\

View File

@ -123,7 +123,8 @@ void GetBasename(const nsCString &aPath, nsACString &aOut)
} }
// MapsReporter::CollectReports uses this stuct to keep track of whether it's // 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 { struct CategoriesSeen {
CategoriesSeen() : CategoriesSeen() :
mSeenResident(false), mSeenResident(false),
@ -148,6 +149,12 @@ public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_IMETHOD GetName(nsACString &aName)
{
aName.AssignLiteral("smaps");
return NS_OK;
}
NS_IMETHOD NS_IMETHOD
CollectReports(nsIMemoryMultiReporterCallback *aCallback, CollectReports(nsIMemoryMultiReporterCallback *aCallback,
nsISupports *aClosure); nsISupports *aClosure);
@ -221,16 +228,16 @@ MapsReporter::CollectReports(nsIMemoryMultiReporterCallback *aCallback,
fclose(f); fclose(f);
// For sure we should have created some node under 'map/resident' and // For sure we should have created some node under 'smaps/resident' and
// 'map/vsize'; otherwise we're probably not reading smaps correctly. If we // 'smaps/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 // didn't create a node under 'smaps/swap', create one here so about:memory
// knows to create an empty 'map/swap' tree. See also bug 682735. // 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 vsize node?");
NS_ASSERTION(categoriesSeen.mSeenVsize, "Didn't create a resident node?"); NS_ASSERTION(categoriesSeen.mSeenVsize, "Didn't create a resident node?");
if (!categoriesSeen.mSeenSwap) { if (!categoriesSeen.mSeenSwap) {
aCallback->Callback(NS_LITERAL_CSTRING(""), aCallback->Callback(NS_LITERAL_CSTRING(""),
NS_LITERAL_CSTRING("map/swap/total"), NS_LITERAL_CSTRING("smaps/swap/total"),
nsIMemoryReporter::KIND_NONHEAP, nsIMemoryReporter::KIND_NONHEAP,
nsIMemoryReporter::UNITS_BYTES, nsIMemoryReporter::UNITS_BYTES,
0, 0,
@ -510,7 +517,7 @@ MapsReporter::ParseMapBody(
} }
nsCAutoString path; nsCAutoString path;
path.Append("map/"); path.Append("smaps/");
path.Append(category); path.Append(category);
path.Append("/"); path.Append("/");
path.Append(aName); path.Append(aName);

View File

@ -216,6 +216,16 @@ interface nsIMemoryMultiReporterCallback : nsISupports
[scriptable, uuid(61d498d5-b460-4398-a8ea-7f75208534b4)] [scriptable, uuid(61d498d5-b460-4398-a8ea-7f75208534b4)]
interface nsIMemoryMultiReporter : nsISupports 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, void collectReports(in nsIMemoryMultiReporterCallback callback,
in nsISupports closure); in nsISupports closure);