mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Bug 653630 - Allow non-leaf reporters in about:memory. r=sdwilsh.
This commit is contained in:
parent
d258fef2cf
commit
82a8ac704a
@ -164,18 +164,21 @@ function update()
|
||||
*/
|
||||
function genProcessText(aProcess, aTmrs)
|
||||
{
|
||||
// First, duplicate the "mapped/heap/used" reporter as "heap-used"; this
|
||||
// value shows up in both the "mapped" and the "heap-used" trees.
|
||||
var mappedHeapUsedTmr = aTmrs["mapped/heap/used"];
|
||||
aTmrs["heap-used"] = {
|
||||
_tpath: "heap-used",
|
||||
_description: mappedHeapUsedTmr._description,
|
||||
_memoryUsed: mappedHeapUsedTmr._memoryUsed
|
||||
};
|
||||
|
||||
/**
|
||||
* From a list of memory reporters, builds a tree that mirrors the tree
|
||||
* structure that will be shown as output.
|
||||
*
|
||||
* @param aTreeName
|
||||
* The name of the tree; either "mapped" or "heap-used"
|
||||
* @param aTreeRootTpath
|
||||
* The tpath of the top node in the tree
|
||||
* @param aTreeRootDesc
|
||||
* The description of the top node in the tree
|
||||
* @param aOtherDescTail
|
||||
* Extra description for the end of the "aTreeName/other" entry
|
||||
* @param aOmitThresholdPerc
|
||||
* The threshold percentage; entries that account for less than
|
||||
* this fraction are aggregated
|
||||
@ -185,10 +188,10 @@ function genProcessText(aProcess, aTmrs)
|
||||
* _description: string;
|
||||
* _memoryUsed: number;
|
||||
* _kids: [Node];
|
||||
* _hasReporter: boolean; (might not be defined)
|
||||
* }
|
||||
*/
|
||||
function buildTree(aTreeName, aTreeRootTpath, aTreeRootDesc, aOtherDescTail,
|
||||
aOmitThresholdPerc)
|
||||
function buildTree(aTreeName, aOmitThresholdPerc)
|
||||
{
|
||||
function findKid(aName, aKids)
|
||||
{
|
||||
@ -201,12 +204,13 @@ function genProcessText(aProcess, aTmrs)
|
||||
}
|
||||
|
||||
// We want to process all reporters that begin with 'aTreeName'.
|
||||
// First we build the tree but only filling in '_name' and '_kids'.
|
||||
var t = { _name:aTreeName, _kids:[] };
|
||||
for (var _tpath in aTmrs) {
|
||||
var tmr = aTmrs[_tpath];
|
||||
if (tmr._tpath.slice(0, aTreeName.length + 1) === aTreeName + "/") {
|
||||
var names = tmr._tpath.slice(aTreeName.length + 1).split('/');
|
||||
// First we build the tree but only filling in '_name', '_kids' and
|
||||
// maybe '._hasReporter'. This is done top-down from the reporters.
|
||||
var t = { _name: "falseRoot", _kids: [] };
|
||||
for (var tpath in aTmrs) {
|
||||
var tmr = aTmrs[tpath];
|
||||
if (tmr._tpath.slice(0, aTreeName.length) === aTreeName) {
|
||||
var names = tmr._tpath.split('/');
|
||||
var u = t;
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
var name = names[i];
|
||||
@ -214,60 +218,66 @@ function genProcessText(aProcess, aTmrs)
|
||||
if (uMatch) {
|
||||
u = uMatch;
|
||||
} else {
|
||||
var v = { _name:name, _kids:[] };
|
||||
var v = { _name: name, _kids: [] };
|
||||
u._kids.push(v);
|
||||
u = v;
|
||||
}
|
||||
}
|
||||
u._hasReporter = true;
|
||||
}
|
||||
}
|
||||
// Using falseRoot makes the above code simpler. Now discard it, leaving
|
||||
// aTreeName at the root.
|
||||
t = t._kids[0];
|
||||
|
||||
// Next, fill in '_description' and '_memoryUsed' for each node. For
|
||||
// interior nodes, '_memoryUsed' is computed by summing child nodes.
|
||||
// Next, fill in '_description' and '_memoryUsed' for each node. This is
|
||||
// done bottom-up because for most non-leaf nodes '_memoryUsed' and
|
||||
// '_description' are determined from the child nodes.
|
||||
function fillInTree(aT, aPretpath)
|
||||
{
|
||||
var tpath = aPretpath ? aPretpath + '/' + aT._name : aT._name;
|
||||
if (aT._kids.length === 0) {
|
||||
// Leaf node. Must have a reporter.
|
||||
aT._memoryUsed = getBytes(aTmrs, tpath);
|
||||
aT._description = getDescription(aTmrs, tpath);
|
||||
} else {
|
||||
var bytes = 0;
|
||||
// Non-leaf node. Get the size of the children.
|
||||
var childrenBytes = 0;
|
||||
for (var i = 0; i < aT._kids.length; i++) {
|
||||
// Allow for -1 (ie. "unknown"), treat it like 0.
|
||||
var b = fillInTree(aT._kids[i], tpath);
|
||||
bytes += (b === -1 ? 0 : b);
|
||||
childrenBytes += (b === -1 ? 0 : b);
|
||||
}
|
||||
if (aT._hasReporter === true) {
|
||||
// Non-leaf node with its own reporter. Use the reporter and add an
|
||||
// "other" child node (unless the byte count is -1, ie. unknown).
|
||||
aT._memoryUsed = getBytes(aTmrs, tpath);
|
||||
aT._description = getDescription(aTmrs, tpath);
|
||||
if (aT._memoryUsed !== -1) {
|
||||
var other = {
|
||||
_name: "other",
|
||||
_description: "All unclassified " + aT._name + " memory.",
|
||||
_memoryUsed: aT._memoryUsed - childrenBytes,
|
||||
_kids: []
|
||||
};
|
||||
aT._kids.push(other);
|
||||
}
|
||||
} else {
|
||||
// Non-leaf node without its own reporter. Derive its size and
|
||||
// description entirely from its children.
|
||||
aT._memoryUsed = childrenBytes;
|
||||
aT._description = "The sum of all entries below " + aT._name + ".";
|
||||
}
|
||||
aT._memoryUsed = bytes;
|
||||
aT._description = "The sum of all entries below " + tpath + ".";
|
||||
}
|
||||
return aT._memoryUsed;
|
||||
}
|
||||
fillInTree(t, "");
|
||||
|
||||
// Add the "aTreeName/other" node, which is derived from existing
|
||||
// nodes, then update the root node accordingly. (But don't do this
|
||||
// if the root node byte count is -1, ie. unknown).
|
||||
var nonOtherBytes = t._memoryUsed;
|
||||
var treeBytes = getBytes(aTmrs, aTreeRootTpath);
|
||||
if (treeBytes !== -1) {
|
||||
var otherBytes = treeBytes - nonOtherBytes;
|
||||
var other = {
|
||||
_name:"other",
|
||||
_description:"All unclassified " + aTreeName + " memory." +
|
||||
aOtherDescTail,
|
||||
_memoryUsed:otherBytes,
|
||||
_kids:[]
|
||||
};
|
||||
t._kids.push(other);
|
||||
}
|
||||
t._memoryUsed = treeBytes;
|
||||
t._description = aTreeRootDesc;
|
||||
|
||||
function shouldOmit(aBytes)
|
||||
{
|
||||
return !gVerbose &&
|
||||
treeBytes !== -1 &&
|
||||
(100 * aBytes / treeBytes) < aOmitThresholdPerc;
|
||||
t._memoryUsed !== -1 &&
|
||||
(100 * aBytes / t._memoryUsed) < aOmitThresholdPerc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -300,7 +310,7 @@ function genProcessText(aProcess, aTmrs)
|
||||
_name: "(" + n + " omitted)",
|
||||
_description: "Omitted sub-trees: " + aggNames.join(", ") + ".",
|
||||
_memoryUsed: aggBytes,
|
||||
_kids:[]
|
||||
_kids: []
|
||||
};
|
||||
aT._kids[i0] = tmrSub;
|
||||
break;
|
||||
@ -313,19 +323,11 @@ function genProcessText(aProcess, aTmrs)
|
||||
return t;
|
||||
}
|
||||
|
||||
var mappedOtherDescTail =
|
||||
" This includes code and data segments, and thread stacks."
|
||||
var mappedRootDesc = getDescription(aTmrs, "mapped");
|
||||
// The threshold used here is much lower than the one for the heap-used
|
||||
// tree, because the "mapped" total size is so much bigger relative to
|
||||
// the interesting entries in the "mapped" tree.
|
||||
var mappedTree = buildTree("mapped", "mapped", mappedRootDesc,
|
||||
mappedOtherDescTail, 0.01);
|
||||
|
||||
var heapUsedOtherDescTail = "";
|
||||
var heapUsedRootDesc = "See mapped/heap/used above.";
|
||||
var heapUsedTree = buildTree("heap-used", "mapped/heap/used",
|
||||
heapUsedRootDesc, heapUsedOtherDescTail, 0.1);
|
||||
// The threshold used for the "mapped" tree is lower than the one for the
|
||||
// "heap-used" tree, because the "mapped" total size is dominated (especially
|
||||
// on Mac) by memory usage that isn't covered by more specific reporters.
|
||||
var mappedTree = buildTree("mapped", 0.01);
|
||||
var heapUsedTree = buildTree("heap-used", 0.1);
|
||||
|
||||
// Nb: the newlines give nice spacing if we cut+paste into a text buffer.
|
||||
var text = "";
|
||||
@ -535,7 +537,9 @@ function genTreeText(aT, aTreeName)
|
||||
// Generate the percentage.
|
||||
var perc = "";
|
||||
if (treeBytes !== -1) {
|
||||
if (aT._memoryUsed === treeBytes) {
|
||||
if (aT._memoryUsed === -1) {
|
||||
perc = "??.??";
|
||||
} else if (aT._memoryUsed === treeBytes) {
|
||||
perc = "100.0";
|
||||
} else {
|
||||
perc = (100 * aT._memoryUsed / treeBytes).toFixed(2);
|
||||
@ -549,7 +553,7 @@ function genTreeText(aT, aTreeName)
|
||||
|
||||
for (var i = 0; i < aT._kids.length; i++) {
|
||||
// 3 is the standard depth, the callee adjusts it if necessary.
|
||||
aIndentGuide.push({ _isLastKid:(i === aT._kids.length - 1), _depth:3 });
|
||||
aIndentGuide.push({ _isLastKid: (i === aT._kids.length - 1), _depth: 3 });
|
||||
text += genTreeText2(aT._kids[i], aIndentGuide, tBytesLength);
|
||||
aIndentGuide.pop();
|
||||
}
|
||||
|
@ -44,6 +44,9 @@
|
||||
{ path: "heap-used/d", memoryUsed: 499 * KB }, // aggregated
|
||||
{ path: "heap-used/e", memoryUsed: 100 * KB }, // aggregated
|
||||
{ path: "heap-used/f/g/h/i", memoryUsed: 20 * MB },
|
||||
{ path: "heap-used/g", memoryUsed: 15 * MB }, // internal
|
||||
{ path: "heap-used/g/a", memoryUsed: 6 * MB },
|
||||
{ path: "heap-used/g/b", memoryUsed: 5 * MB },
|
||||
{ path: "other1", memoryUsed: 111 * MB },
|
||||
{ path: "other2", memoryUsed: 222 * MB },
|
||||
|
||||
@ -67,8 +70,8 @@
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<iframe id="amFrame" src="about:memory"></iframe>
|
||||
<iframe id="amvFrame" src="about:memory?verbose"></iframe>
|
||||
<iframe id="amFrame" height="300" src="about:memory"></iframe>
|
||||
<iframe id="amvFrame" height="300" src="about:memory?verbose"></iframe>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
@ -94,11 +97,15 @@ Used Heap Memory\n\
|
||||
│ └───75.00 MB (15.00%) -- b\n\
|
||||
├──123.00 MB (24.60%) -- c\n\
|
||||
├───99.00 MB (19.80%) -- a\n\
|
||||
├───25.42 MB (05.08%) -- other\n\
|
||||
├───20.00 MB (04.00%) -- f\n\
|
||||
│ └──20.00 MB (04.00%) -- g\n\
|
||||
│ └──20.00 MB (04.00%) -- h\n\
|
||||
│ └──20.00 MB (04.00%) -- i\n\
|
||||
├───15.00 MB (03.00%) -- g\n\
|
||||
│ ├───6.00 MB (01.20%) -- a\n\
|
||||
│ ├───5.00 MB (01.00%) -- b\n\
|
||||
│ └───4.00 MB (00.80%) -- other\n\
|
||||
├───10.42 MB (02.08%) -- other\n\
|
||||
└────0.58 MB (00.12%) -- (2 omitted)\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
@ -165,11 +172,15 @@ Used Heap Memory\n\
|
||||
│ └───78,643,200 B (15.00%) -- b\n\
|
||||
├──128,974,848 B (24.60%) -- c\n\
|
||||
├──103,809,024 B (19.80%) -- a\n\
|
||||
├───26,649,600 B (05.08%) -- other\n\
|
||||
├───20,971,520 B (04.00%) -- f\n\
|
||||
│ └──20,971,520 B (04.00%) -- g\n\
|
||||
│ └──20,971,520 B (04.00%) -- h\n\
|
||||
│ └──20,971,520 B (04.00%) -- i\n\
|
||||
├───15,728,640 B (03.00%) -- g\n\
|
||||
│ ├───6,291,456 B (01.20%) -- a\n\
|
||||
│ ├───5,242,880 B (01.00%) -- b\n\
|
||||
│ └───4,194,304 B (00.80%) -- other\n\
|
||||
├───10,920,960 B (02.08%) -- other\n\
|
||||
├──────510,976 B (00.10%) -- d\n\
|
||||
└──────102,400 B (00.02%) -- e\n\
|
||||
\n\
|
||||
|
@ -51,28 +51,26 @@ interface nsIMemoryReporter : nsISupports
|
||||
*
|
||||
* - Paths starting with "mapped" represent non-overlapping regions of mapped
|
||||
* memory. Each one can be viewed as representing a path in a tree from
|
||||
* the root node ("mapped") to a leaf node. The one exception is the
|
||||
* special "mapped" path which represents the root of that tree. So, for
|
||||
* example, "mapped/heap/used", "mapped/heap/unused",
|
||||
* "mapped/js/mjit-code", mapped/js/tjit-code", plus the special "mapped"
|
||||
* path, define this tree:
|
||||
* the root node ("mapped") to a node lower in the tree; this lower node
|
||||
* may be a non-leaf or a leaf node. So, for example, "mapped",
|
||||
* "mapped/heap/used", "mapped/heap/unused", "mapped/js/mjit-code",
|
||||
* and "mapped/js/tjit-code" define this tree:
|
||||
*
|
||||
* mapped
|
||||
* mapped [*]
|
||||
* |--heap
|
||||
* | |--used
|
||||
* | \--unused
|
||||
* | |--used [*]
|
||||
* | \--unused [*]
|
||||
* \--js
|
||||
* |--mjit-code
|
||||
* \--tjit-code
|
||||
* |--mjit-code [*]
|
||||
* \--tjit-code [*]
|
||||
*
|
||||
* "mapped/heap" would not be a valid path in this example because "heap"
|
||||
* is not a leaf node.
|
||||
* Nodes marked with a [*] have a reporter.
|
||||
*
|
||||
* - Paths starting with "heap-used" represent non-overlapping regions of
|
||||
* used heap memory. The "mapped" rules above apply equally here. The
|
||||
* exceptional path for this tree is "mapped/heap/used" (and so this tree
|
||||
* is a sub-tree of the "mapped" tree). When shown in about:memory, this
|
||||
* tree's root node is given the synonym "heap-used".
|
||||
* used heap memory. The "mapped" rules above apply equally here. These
|
||||
* paths are actually sub-paths of "mapped/heap/used", but that reporter
|
||||
* is duplicated under the name "heap-used" to make the processing for
|
||||
* about:memory simpler.
|
||||
*
|
||||
* - All other paths represent cross-cuttings memory regions, ie. ones that
|
||||
* may overlap arbitrarily with regions in the "mapped" and "heap-used"
|
||||
|
@ -149,8 +149,11 @@ static PRInt64 GetResident(void *)
|
||||
// byte count returned is always -1.
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(Mapped,
|
||||
"mapped",
|
||||
"Memory mapped by the process. Note that 'resident' is a better measure "
|
||||
"of memory resources used by the process. "
|
||||
"Memory mapped by the process, including the heap, code and data segments, "
|
||||
"thread stacks, and memory explicitly mapped by the process via "
|
||||
"mmap, VirtualAlloc and similar operations. "
|
||||
"Note that 'resident' is a better measure of memory resources used by the "
|
||||
"process. "
|
||||
"On Windows (XP SP2 or later only) this is the private usage and does not "
|
||||
"include memory shared with other processes. "
|
||||
"On Mac and Linux this is the vsize figure as reported by 'top' or 'ps' "
|
||||
|
Loading…
Reference in New Issue
Block a user