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;
}
NS_IMETHODIMP
nsDOMMemoryMultiReporter::GetName(nsACString &aName)
{
aName.AssignLiteral("dom+style");
return NS_OK;
}
NS_IMETHODIMP
nsDOMMemoryMultiReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
nsISupports* aClosure)

View File

@ -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)

View File

@ -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)
{

View File

@ -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)

View File

@ -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

View File

@ -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) {
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.

View File

@ -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);
]]>
</script>
@ -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<script>window.alert(1)</script>\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
// 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);

View File

@ -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);