зеркало из https://github.com/mozilla/gecko-dev.git
Bug 755583 (part 4) - Split up the smaps/ memory reporter tree. r=jlebar.
This commit is contained in:
Родитель
e1b88c680a
Коммит
9976c1f421
|
@ -229,11 +229,11 @@ function processMemoryReporters(aMgr, aIgnoreSingle, aIgnoreMulti,
|
|||
|
||||
let e = aMgr.enumerateMultiReporters();
|
||||
while (e.hasMoreElements()) {
|
||||
let mrOrig = e.getNext().QueryInterface(Ci.nsIMemoryMultiReporter);
|
||||
let name = mrOrig.name;
|
||||
let mr = e.getNext().QueryInterface(Ci.nsIMemoryMultiReporter);
|
||||
let name = mr.name;
|
||||
try {
|
||||
if (!aIgnoreMulti(name)) {
|
||||
mrOrig.collectReports(handleReport, null);
|
||||
mr.collectReports(handleReport, null);
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
|
@ -269,14 +269,13 @@ function checkReport(aUnsafePath, aKind, aUnits, aAmount, aDescription)
|
|||
assert(gSentenceRegExp.test(aDescription),
|
||||
"non-sentence explicit description");
|
||||
|
||||
} else if (aUnsafePath.startsWith("smaps/")) {
|
||||
} else if (isSmapsPath(aUnsafePath)) {
|
||||
assert(aKind === KIND_NONHEAP, "bad smaps kind");
|
||||
assert(aUnits === UNITS_BYTES, "bad smaps units");
|
||||
assert(aDescription !== "", "empty smaps description");
|
||||
|
||||
} else if (aKind === KIND_SUMMARY) {
|
||||
assert(!aUnsafePath.startsWith("explicit/") &&
|
||||
!aUnsafePath.startsWith("smaps/"),
|
||||
assert(!aUnsafePath.startsWith("explicit/") && !isSmapsPath(aUnsafePath),
|
||||
"bad SUMMARY path");
|
||||
|
||||
} else {
|
||||
|
@ -379,7 +378,7 @@ mappings is currently using. Mappings which are not in the swap file (i.e., \
|
|||
nodes which would have a value of 0 in this tree) are omitted."
|
||||
};
|
||||
|
||||
const kTreeNames = {
|
||||
const kSectionNames = {
|
||||
'explicit': 'Explicit Allocations',
|
||||
'resident': 'Resident Set Size (RSS) Breakdown',
|
||||
'pss': 'Proportional Set Size (PSS) Breakdown',
|
||||
|
@ -388,8 +387,17 @@ const kTreeNames = {
|
|||
'other': 'Other Measurements'
|
||||
};
|
||||
|
||||
const kMapTreePaths =
|
||||
['smaps/resident', 'smaps/pss', 'smaps/vsize', 'smaps/swap'];
|
||||
const kSmapsTreePrefixes = ['resident/', 'pss/', 'vsize/', 'swap/'];
|
||||
|
||||
function isSmapsPath(aUnsafePath)
|
||||
{
|
||||
for (let i = 0; i < kSmapsTreePrefixes.length; i++) {
|
||||
if (aUnsafePath.startsWith(kSmapsTreePrefixes[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
@ -519,13 +527,6 @@ Report.prototype = {
|
|||
this._amount += r._amount;
|
||||
this._nMerged = this._nMerged ? this._nMerged + 1 : 2;
|
||||
},
|
||||
|
||||
treeNameMatches: function(aTreeName) {
|
||||
// Nb: the '/' must be present, because we have a KIND_OTHER reporter
|
||||
// called "explicit" which is not part of the "explicit" tree.
|
||||
return this._unsafePath.startsWith(aTreeName) &&
|
||||
this._unsafePath.charAt(aTreeName.length) === '/';
|
||||
}
|
||||
};
|
||||
|
||||
function getReportsByProcess(aMgr)
|
||||
|
@ -535,18 +536,18 @@ function getReportsByProcess(aMgr)
|
|||
// that reports from these multi-reporters can reach here as single reports
|
||||
// if they were in the child process.)
|
||||
|
||||
function ignoreSingle(aPath)
|
||||
function ignoreSingle(aUnsafePath)
|
||||
{
|
||||
return (aPath.startsWith("smaps/") && !gVerbose) ||
|
||||
aPath.startsWith("compartments/") ||
|
||||
aPath.startsWith("ghost-windows/");
|
||||
return (isSmapsPath(aUnsafePath) && !gVerbose) ||
|
||||
aUnsafePath.startsWith("compartments/") ||
|
||||
aUnsafePath.startsWith("ghost-windows/");
|
||||
}
|
||||
|
||||
function ignoreMulti(aName)
|
||||
function ignoreMulti(aMRName)
|
||||
{
|
||||
return (aName === "smaps" && !gVerbose) ||
|
||||
aName === "compartments" ||
|
||||
aName === "ghost-windows";
|
||||
return (aMRName === "smaps" && !gVerbose) ||
|
||||
aMRName === "compartments" ||
|
||||
aMRName === "ghost-windows";
|
||||
}
|
||||
|
||||
let reportsByProcess = {};
|
||||
|
@ -623,36 +624,26 @@ TreeNode.compare = function(a, b) {
|
|||
*
|
||||
* @param aReports
|
||||
* The table of Reports, indexed by _unsafePath.
|
||||
* @param aTreeName
|
||||
* The name of the tree being built.
|
||||
* @param aTreePrefix
|
||||
* The prefix (name) of the tree being built. Must have '/' on the end.
|
||||
* @return The built tree.
|
||||
*/
|
||||
function buildTree(aReports, aTreeName)
|
||||
function buildTree(aReports, aTreePrefix)
|
||||
{
|
||||
// We want to process all reports that begin with |aTreeName|. First we
|
||||
assert(aTreePrefix.indexOf('/') == aTreePrefix.length - 1,
|
||||
"aTreePrefix doesn't end in '/'");
|
||||
|
||||
// We want to process all reports that begin with |aTreePrefix|. First we
|
||||
// build the tree but only fill the properties that we can with a top-down
|
||||
// traversal.
|
||||
|
||||
// There should always be at least one matching Report object when
|
||||
// |aTreeName| is "explicit". But there may be zero for "smaps" trees; if
|
||||
// that happens, bail.
|
||||
let foundReport = false;
|
||||
for (let unsafePath in aReports) {
|
||||
if (aReports[unsafePath].treeNameMatches(aTreeName)) {
|
||||
foundReport = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundReport) {
|
||||
assert(aTreeName !== 'explicit', "aTreeName !== 'explicit'");
|
||||
return null;
|
||||
}
|
||||
|
||||
let t = new TreeNode("falseRoot");
|
||||
for (let unsafePath in aReports) {
|
||||
// Add any missing nodes in the tree implied by the unsafePath.
|
||||
if (unsafePath.startsWith(aTreePrefix)) {
|
||||
foundReport = true;
|
||||
let r = aReports[unsafePath];
|
||||
if (r.treeNameMatches(aTreeName)) {
|
||||
let unsafeNames = r._unsafePath.split('/');
|
||||
let u = t;
|
||||
for (let i = 0; i < unsafeNames.length; i++) {
|
||||
|
@ -677,8 +668,16 @@ function buildTree(aReports, aTreeName)
|
|||
}
|
||||
}
|
||||
|
||||
// There should always be at least one matching Report object when
|
||||
// |aTreePrefix| is "explicit/". But there may be zero for smaps trees; if
|
||||
// that happens, bail.
|
||||
if (!foundReport) {
|
||||
assert(aTreePrefix !== 'explicit/', "aTreePrefix !== 'explicit/'");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Using falseRoot makes the above code simpler. Now discard it, leaving
|
||||
// aTreeName at the root.
|
||||
// aTreePrefix at the root.
|
||||
t = t._kids[0];
|
||||
|
||||
// Next, fill in the remaining properties bottom-up.
|
||||
|
@ -704,16 +703,6 @@ function buildTree(aReports, aTreeName)
|
|||
|
||||
fillInNonLeafNodes(t);
|
||||
|
||||
// Reduce the depth of the tree by the number of occurrences of '/' in
|
||||
// aTreeName. (Thus the tree named 'foo/bar/baz' will be rooted at 'baz'.)
|
||||
let slashCount = 0;
|
||||
for (let i = 0; i < aTreeName.length; i++) {
|
||||
if (aTreeName[i] == '/') {
|
||||
assert(t._kids.length == 1, "Not expecting multiple kids here.");
|
||||
t = t._kids[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Set the (unsafe) description on the root node.
|
||||
t._description = kTreeDescriptions[t._unsafeName];
|
||||
|
||||
|
@ -721,7 +710,7 @@ function buildTree(aReports, aTreeName)
|
|||
}
|
||||
|
||||
/**
|
||||
* Ignore all the memory reports that belong to a "smaps" tree; this involves
|
||||
* Ignore all the memory reports that belong to a smaps tree; this involves
|
||||
* explicitly marking them as done.
|
||||
*
|
||||
* @param aReports
|
||||
|
@ -731,7 +720,7 @@ function ignoreSmapsTrees(aReports)
|
|||
{
|
||||
for (let unsafePath in aReports) {
|
||||
let r = aReports[unsafePath];
|
||||
if (r.treeNameMatches("smaps")) {
|
||||
if (isSmapsPath(r._unsafePath)) {
|
||||
r._done = true;
|
||||
}
|
||||
}
|
||||
|
@ -940,22 +929,22 @@ function appendProcessReportsElements(aP, aProcess, aReports,
|
|||
// We'll fill this in later.
|
||||
let warningsDiv = appendElement(aP, "div", "accuracyWarning");
|
||||
|
||||
let explicitTree = buildTree(aReports, 'explicit');
|
||||
let explicitTree = buildTree(aReports, 'explicit/');
|
||||
let hasKnownHeapAllocated = fixUpExplicitTree(explicitTree, aReports);
|
||||
sortTreeAndInsertAggregateNodes(explicitTree._amount, explicitTree);
|
||||
appendTreeElements(aP, explicitTree, aProcess);
|
||||
|
||||
// We only show these breakdown trees in verbose mode.
|
||||
if (gVerbose) {
|
||||
kMapTreePaths.forEach(function(t) {
|
||||
let tree = buildTree(aReports, t);
|
||||
kSmapsTreePrefixes.forEach(function(aTreePrefix) {
|
||||
let t = buildTree(aReports, aTreePrefix);
|
||||
|
||||
// |tree| will be null if we don't have any reports for the given
|
||||
// |t| will be null if we don't have any reports for the given
|
||||
// unsafePath.
|
||||
if (tree) {
|
||||
sortTreeAndInsertAggregateNodes(tree._amount, tree);
|
||||
tree._hideKids = true; // smaps trees are always initially collapsed
|
||||
appendTreeElements(aP, tree, aProcess);
|
||||
if (t) {
|
||||
sortTreeAndInsertAggregateNodes(t._amount, t);
|
||||
t._hideKids = true; // smaps trees are always initially collapsed
|
||||
appendTreeElements(aP, t, aProcess);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
@ -1339,7 +1328,7 @@ function appendTreeElements(aPOuter, aT, aProcess)
|
|||
appendMrValueSpan(d, tString, tIsInvalid);
|
||||
appendElementWithText(d, "span", "mrPerc", percText);
|
||||
|
||||
// We don't want to show '(nonheap)' on a tree like 'smaps/vsize', since
|
||||
// We don't want to show '(nonheap)' on a tree like 'vsize/', since
|
||||
// the whole tree is non-heap.
|
||||
let kind = isExplicitTree ? aT._kind : undefined;
|
||||
appendMrNameSpan(d, kind, kidsState, aT._description, aT._unsafeName,
|
||||
|
@ -1381,7 +1370,7 @@ function appendTreeElements(aPOuter, aT, aProcess)
|
|||
}
|
||||
}
|
||||
|
||||
appendSectionHeader(aPOuter, kTreeNames[aT._unsafeName]);
|
||||
appendSectionHeader(aPOuter, kSectionNames[aT._unsafeName]);
|
||||
|
||||
let pre = appendElement(aPOuter, "pre", "entries");
|
||||
appendTreeElements2(pre, /* prePath = */"", aT, [], "", rootStringLength);
|
||||
|
@ -1444,7 +1433,7 @@ OtherReport.compare = function(a, b) {
|
|||
*/
|
||||
function appendOtherElements(aP, aReportsByProcess)
|
||||
{
|
||||
appendSectionHeader(aP, kTreeNames['other']);
|
||||
appendSectionHeader(aP, kSectionNames['other']);
|
||||
|
||||
let pre = appendElement(aP, "pre", "entries");
|
||||
|
||||
|
@ -1573,14 +1562,14 @@ function getCompartmentsByProcess(aMgr)
|
|||
// (Note that some such reports can reach here as single reports if they were
|
||||
// in the child process.)
|
||||
|
||||
function ignoreSingle(aPath)
|
||||
function ignoreSingle(aUnsafePath)
|
||||
{
|
||||
return !aPath.startsWith("compartments/");
|
||||
return !aUnsafePath.startsWith("compartments/");
|
||||
}
|
||||
|
||||
function ignoreMulti(aName)
|
||||
function ignoreMulti(aMRName)
|
||||
{
|
||||
return aName !== "compartments";
|
||||
return aMRName !== "compartments";
|
||||
}
|
||||
|
||||
let compartmentsByProcess = {};
|
||||
|
@ -1648,9 +1637,9 @@ GhostWindow.prototype = {
|
|||
|
||||
function getGhostWindowsByProcess(aMgr)
|
||||
{
|
||||
function ignoreSingle(aPath)
|
||||
function ignoreSingle(aUnsafePath)
|
||||
{
|
||||
return !aPath.startsWith('ghost-windows/')
|
||||
return !aUnsafePath.startsWith('ghost-windows/')
|
||||
}
|
||||
|
||||
function ignoreMulti(aName)
|
||||
|
|
|
@ -121,13 +121,13 @@
|
|||
function f(aP, aA) {
|
||||
aCbObj.callback("", aP, NONHEAP, BYTES, aA * 4 * KB, "Desc.", aClosure);
|
||||
}
|
||||
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);
|
||||
f("vsize/a", 24);
|
||||
f("swap/a", 1);
|
||||
f("swap/a", 2);
|
||||
f("vsize/a", 19);
|
||||
f("swap/b/c", 10);
|
||||
f("resident/a", 42);
|
||||
f("pss/a", 43);
|
||||
},
|
||||
explicitNonHeap: 0
|
||||
},
|
||||
|
@ -181,8 +181,8 @@
|
|||
// The fact that we skip the "smaps" multi-reporter in the main
|
||||
// process won't cause these to be skipped; the fall-back skipping will
|
||||
// be hit instead.
|
||||
f("2nd", "smaps/vsize/e", NONHEAP, 24*4*KB),
|
||||
f("2nd", "smaps/vsize/f", NONHEAP, 24*4*KB),
|
||||
f("2nd", "vsize/e", NONHEAP, 24*4*KB),
|
||||
f("2nd", "vsize/f", NONHEAP, 24*4*KB),
|
||||
|
||||
// Check that we can handle "heap-allocated" not being present.
|
||||
f("3rd", "explicit/a/b", HEAP, 333 * MB),
|
||||
|
|
|
@ -124,8 +124,7 @@ void GetBasename(const nsCString &aPath, nsACString &aOut)
|
|||
}
|
||||
|
||||
// MapsReporter::CollectReports uses this stuct to keep track of whether it's
|
||||
// seen a mapping under 'smaps/resident', 'smaps/pss', 'smaps/vsize', and
|
||||
// 'smaps/swap'.
|
||||
// seen a mapping under 'resident', 'pss', 'vsize', and 'swap'.
|
||||
struct CategoriesSeen {
|
||||
CategoriesSeen() :
|
||||
mSeenResident(false),
|
||||
|
@ -229,17 +228,18 @@ MapsReporter::CollectReports(nsIMemoryMultiReporterCallback *aCb,
|
|||
|
||||
fclose(f);
|
||||
|
||||
// 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.
|
||||
// For sure we should have created some node under 'resident' and
|
||||
// 'vsize'; otherwise we're probably not reading smaps correctly. If we
|
||||
// didn't create a node under 'swap', create one here so about:memory
|
||||
// knows to create an empty 'swap' tree; it needs a 'total' child because
|
||||
// about:memory expects at least one report whose path begins with 'swap/'.
|
||||
|
||||
NS_ASSERTION(categoriesSeen.mSeenVsize, "Didn't create a vsize node?");
|
||||
NS_ASSERTION(categoriesSeen.mSeenVsize, "Didn't create a resident node?");
|
||||
if (!categoriesSeen.mSeenSwap) {
|
||||
nsresult rv;
|
||||
rv = aCb->Callback(NS_LITERAL_CSTRING(""),
|
||||
NS_LITERAL_CSTRING("smaps/swap/total"),
|
||||
NS_LITERAL_CSTRING("swap/total"),
|
||||
nsIMemoryReporter::KIND_NONHEAP,
|
||||
nsIMemoryReporter::UNITS_BYTES,
|
||||
0,
|
||||
|
@ -523,7 +523,6 @@ MapsReporter::ParseMapBody(
|
|||
}
|
||||
|
||||
nsCAutoString path;
|
||||
path.Append("smaps/");
|
||||
path.Append(category);
|
||||
path.Append("/");
|
||||
path.Append(aName);
|
||||
|
|
Загрузка…
Ссылка в новой задаче