--- a/toolkit/components/aboutmemory/content/aboutMemory.js
+++ b/toolkit/components/aboutmemory/content/aboutMemory.js
@@ -360,29 +360,30 @@ function update()
"heading to expand or collapse its tree.</span>" +
"</div>";
var div = document.createElement("div");
div.innerHTML = text;
content.appendChild(div);
}
-// There are two kinds of TreeNode. Those that correspond to Reporters
-// have more properties. The remainder are just scaffolding nodes for the
-// tree, whose values are derived from their children.
+// There are two kinds of TreeNode.
+// - Leaf TreeNodes correspond to Reporters and have more properties.
+// - Non-leaf TreeNodes are just scaffolding nodes for the tree; their values
+// are derived from their children.
function TreeNode(aName)
{
// Nb: _units is not needed, it's always UNITS_BYTES.
this._name = aName;
this._kids = [];
// All TreeNodes have these properties added later:
// - _amount (which is never |kUnknown|)
// - _description
//
- // TreeNodes corresponding to Reporters have these properties added later:
+ // Leaf TreeNodes have these properties added later:
// - _kind
// - _nMerged (if > 1)
// - _hasProblem (only defined if true)
}
TreeNode.prototype = {
findKid: function(aName) {
for (var i = 0; i < this._kids.length; i++) {
@@ -413,28 +414,28 @@ TreeNode.compare = function(a, b) {
* @return The built tree.
*/
function buildTree(aReporters, aTreeName)
{
// We want to process all reporters that begin with |aTreeName|. First we
// build the tree but only fill the properties that we can with a top-down
// traversal.
- // Is there any reporter which matches aTreeName? If not, we'll create a
- // dummy one.
+ // There should always be at least one matching reporter when |aTreeName| is
+ // "explicit". But there may be zero for "map" trees; if that happens,
+ // bail.
var foundReporter = false;
for (var path in aReporters) {
if (aReporters[path].treeNameMatches(aTreeName)) {
foundReporter = true;
break;
}
}
-
if (!foundReporter) {
- // We didn't find any reporters for this tree, so bail.
+ assert(aTreeName !== 'explicit');
return null;
}
var t = new TreeNode("falseRoot");
for (var path in aReporters) {
// Add any missing nodes in the tree implied by the path.
var r = aReporters[path];
if (r.treeNameMatches(aTreeName)) {
@@ -468,55 +469,35 @@ function buildTree(aReporters, aTreeName
// Next, fill in the remaining properties bottom-up.
// Note that this function never returns kUnknown.
function fillInTree(aT, aPrepath)
{
var path = aPrepath ? aPrepath + '/' + aT._name : aT._name;
if (aT._kids.length === 0) {
// Leaf node. Must have a reporter.
- assert(aT._kind !== undefined, "aT._kind !== undefined");
+ assert(aT._kind !== undefined, "aT._kind is undefined for leaf node");
aT._description = getDescription(aReporters, path);
var amount = getBytes(aReporters, path);
if (amount !== kUnknown) {
aT._amount = amount;
} else {
aT._amount = 0;
aT._hasProblem = true;
}
} else {
- // Non-leaf node. Get the size of the children.
+ // Non-leaf node. Derive its size and description entirely from its
+ // children.
+ assert(aT._kind === undefined, "aT._kind is defined for non-leaf node");
var childrenBytes = 0;
for (var i = 0; i < aT._kids.length; i++) {
- // Allow for kUnknown, treat it like 0.
childrenBytes += fillInTree(aT._kids[i], path);
}
- if (aT._kind !== undefined) {
- aT._description = getDescription(aReporters, path);
- var amount = getBytes(aReporters, path);
- if (amount !== kUnknown) {
- // Non-leaf node with its own reporter. Use the reporter and add
- // an "other" child node.
- aT._amount = amount;
- var other = new TreeNode("other");
- other._description = "All unclassified " + aT._name + " memory.",
- other._amount = aT._amount - childrenBytes,
- aT._kids.push(other);
- } else {
- // Non-leaf node with a reporter that returns kUnknown.
- // Use the sum of the children and mark it as problematic.
- aT._amount = childrenBytes;
- aT._hasProblem = true;
- }
- } else {
- // Non-leaf node without its own reporter. Derive its size and
- // description entirely from its children.
- aT._amount = childrenBytes;
- aT._description = "The sum of all entries below '" + aT._name + "'.";
- }
+ aT._amount = childrenBytes;
+ aT._description = "The sum of all entries below '" + aT._name + "'.";
}
assert(aT._amount !== kUnknown, "aT._amount !== kUnknown");
return aT._amount;
}
fillInTree(t, "");
// Reduce the depth of the tree by the number of occurrences of '/' in
@@ -534,59 +515,56 @@ function buildTree(aReporters, aTreeName
return t;
}
/**
* Do some work which only makes sense for the 'explicit' tree.
*/
function fixUpExplicitTree(aT, aReporters) {
- // Determine how many bytes are reported by heap reporters. Be careful
- // with non-leaf reporters; if we count a non-leaf reporter we don't want
- // to count any of its child reporters.
+ // Determine how many bytes are reported by heap reporters.
var s = "";
function getKnownHeapUsedBytes(aT)
{
- if (aT._kind === KIND_HEAP) {
- return aT._amount;
+ var n = 0;
+ if (aT._kids.length === 0) {
+ // Leaf node.
+ assert(aT._kind !== undefined, "aT._kind is undefined for leaf node");
+ n = aT._kind === KIND_HEAP ? aT._amount : 0;
} else {
- var n = 0;
for (var i = 0; i < aT._kids.length; i++) {
n += getKnownHeapUsedBytes(aT._kids[i]);
}
- return n;
}
+ return n;
}
// A special case: compute the derived "heap-unclassified" value. Don't
// mark "heap-allocated" when we get its size because we want it to appear
// in the "Other Measurements" list.
- var heapUsedBytes = getBytes(aReporters, "heap-allocated", true);
- var unknownHeapUsedBytes = 0;
- var hasProblem = true;
- if (heapUsedBytes !== kUnknown) {
- unknownHeapUsedBytes = heapUsedBytes - getKnownHeapUsedBytes(aT);
- hasProblem = false;
+ var heapAllocatedBytes = getBytes(aReporters, "heap-allocated", true);
+ var heapUnclassifiedT = new TreeNode("heap-unclassified");
+ if (heapAllocatedBytes !== kUnknown) {
+ heapUnclassifiedT._amount =
+ heapAllocatedBytes - getKnownHeapUsedBytes(aT);
+ } else {
+ heapUnclassifiedT._amount = 0;
+ heapUnclassifiedT._hasProblem = true;
}
- var heapUnclassified = new TreeNode("heap-unclassified");
// This kindToString() ensures the "(Heap)" prefix is set without having to
// set the _kind property, which would mean that there is a corresponding
// Reporter for this TreeNode (which isn't true).
- heapUnclassified._description =
+ heapUnclassifiedT._description =
kindToString(KIND_HEAP) +
"Memory not classified by a more specific reporter. This includes " +
- "waste due to internal fragmentation in the heap allocator (caused " +
- "when the allocator rounds up request sizes).";
- heapUnclassified._amount = unknownHeapUsedBytes;
- if (hasProblem) {
- heapUnclassified._hasProblem = true;
- }
+ "slop bytes due to internal fragmentation in the heap allocator "
+ "(caused when the allocator rounds up request sizes).";
- aT._kids.push(heapUnclassified);
- aT._amount += unknownHeapUsedBytes;
+ aT._kids.push(heapUnclassifiedT);
+ aT._amount += heapUnclassifiedT._amount;
}
/**
* Sort all kid nodes from largest to smallest and aggregate insignificant
* nodes.
*
* @param aTotalBytes
* The size of the tree's root node.
--- a/toolkit/components/aboutmemory/tests/chrome/test_aboutmemory.xul
+++ b/toolkit/components/aboutmemory/tests/chrome/test_aboutmemory.xul
@@ -73,38 +73,37 @@
var fakeReporters = [
f("", "heap-allocated", OTHER, 500 * MB),
f("", "heap-unallocated", OTHER, 100 * MB),
f("", "explicit/a", HEAP, 222 * MB),
f("", "explicit/b/a", HEAP, 85 * MB),
f("", "explicit/b/b", HEAP, 75 * MB),
f("", "explicit/b/c/a", HEAP, 70 * MB),
f("", "explicit/b/c/b", HEAP, 2 * MB), // omitted
- f("", "explicit/c", NONHEAP, 100 * MB),
f("", "explicit/c/d", NONHEAP, 13 * MB), // subsumed by parent
- f("", "explicit/g", HEAP, 1 * MB), // internal, dup: merge
+ f("", "explicit/c/other", NONHEAP, 77 * MB), // subsumed by parent
f("", "explicit/g/a", HEAP, 6 * MB),
f("", "explicit/g/b", HEAP, 5 * MB),
+ f("", "explicit/g/other", HEAP, 4 * MB),
f("", "other1", OTHER, 111 * MB),
f2("", "other4", OTHER, COUNT_CUMULATIVE, 888)
];
var fakeMultiReporters = [
{ collectReports: function(cbObj, closure) {
function f(p, k, u, a) { cbObj.callback("", p, k, u, a, "(desc)", closure); }
f("explicit/c/d", NONHEAP, BYTES, 10 * MB), // dup, subsumed by parent
f("explicit/cc", NONHEAP, BYTES, 13 * MB);
f("explicit/cc", NONHEAP, BYTES, 10 * MB); // dup
f("explicit/d", NONHEAP, BYTES, 499 * KB); // omitted
f("explicit/e", NONHEAP, BYTES, 100 * KB); // omitted
f("explicit/f/g/h/i", HEAP, BYTES, 20 * MB);
}
},
{ collectReports: function(cbObj, closure) {
function f(p, k, u, a) { cbObj.callback("", p, k, u, a, "(desc)", closure); }
- f("explicit/g", HEAP, BYTES, 14 * MB); // internal
f("other3", OTHER, COUNT, 777);
f("other2", OTHER, BYTES, 222 * MB);
f("perc2", OTHER, PERCENTAGE, 10000);
f("perc1", OTHER, PERCENTAGE, 4567);
}
},
{ collectReports: function(cbObj, closure) {
// The amounts are given in pages, so multiply here by 4kb.
@@ -149,17 +148,16 @@
// The escaping of compartment names must prevent this script from running.
f("2nd", "danger<script>window.alert(1)</script>",
OTHER, 666 * MB),
f("2nd", "other1", OTHER, 111 * MB),
// kUnknown should be handled gracefully for "heap-allocated", non-leaf
// reporters, leaf-reporters, "other" reporters, and duplicated reporters.
f("3rd", "heap-allocated", OTHER, kUnknown),
- f("3rd", "explicit/a", HEAP, kUnknown),
f("3rd", "explicit/a/b", HEAP, 333 * MB),
f("3rd", "explicit/a/c", HEAP, 444 * MB),
f("3rd", "explicit/a/c", HEAP, kUnknown), // dup: merge
f("3rd", "explicit/a/d", HEAP, kUnknown),
f("3rd", "explicit/a/d", HEAP, kUnknown), // dup: merge
f("3rd", "explicit/b", NONHEAP, kUnknown),
f("3rd", "other1", OTHER, kUnknown)
];
@@ -191,17 +189,17 @@ 623.58 MB (100.0%) -- explicit\n\
├──100.00 MB (16.04%) -- c\n\
│ ├───77.00 MB (12.35%) -- other\n\
│ └───23.00 MB (03.69%) -- d [2]\n\
├───23.00 MB (03.69%) -- cc [2]\n\
├───20.00 MB (03.21%) -- f\n\
│ └──20.00 MB (03.21%) -- g\n\
│ └──20.00 MB (03.21%) -- h\n\
│ └──20.00 MB (03.21%) -- i\n\
-├───15.00 MB (02.41%) -- g [2]\n\
+├───15.00 MB (02.41%) -- g\n\
│ ├───6.00 MB (00.96%) -- a\n\
│ ├───5.00 MB (00.80%) -- b\n\
│ └───4.00 MB (00.64%) -- other\n\
├───11.00 MB (01.76%) -- heap-unclassified\n\
└────0.58 MB (00.09%) -- (2 omitted)\n\
\n\
Resident Set Size (RSS) Breakdown\n\
0.16 MB (100.0%) -- resident\n\
@@ -243,17 +241,17 @@ Other Measurements\n\
1,000.00 MB -- heap-allocated\n\
100.00 MB -- heap-unallocated\n\
111.00 MB -- other1\n\
\n\
3rd Process\n\
\n\
Explicit Allocations\n\
777.00 MB (100.0%) -- explicit\n\
-├──777.00 MB (100.0%) -- a [*]\n\
+├──777.00 MB (100.0%) -- a\n\
│ ├──444.00 MB (57.14%) -- c [2]\n\
│ ├──333.00 MB (42.86%) -- b\n\
│ └────0.00 MB (00.00%) -- (1 omitted)\n\
└────0.00 MB (00.00%) -- (2 omitted)\n\
\n\
Other Measurements\n\
0.00 MB -- heap-allocated [*]\n\
0.00 MB -- other1 [*]\n\
@@ -276,17 +274,17 @@ 653,876,224 B (100.0%) -- explicit\n\
├──104,857,600 B (16.04%) -- c\n\
│ ├───80,740,352 B (12.35%) -- other\n\
│ └───24,117,248 B (03.69%) -- d [2]\n\
├───24,117,248 B (03.69%) -- cc [2]\n\
├───20,971,520 B (03.21%) -- f\n\
│ └──20,971,520 B (03.21%) -- g\n\
│ └──20,971,520 B (03.21%) -- h\n\
│ └──20,971,520 B (03.21%) -- i\n\
-├───15,728,640 B (02.41%) -- g [2]\n\
+├───15,728,640 B (02.41%) -- g\n\
│ ├───6,291,456 B (00.96%) -- a\n\
│ ├───5,242,880 B (00.80%) -- b\n\
│ └───4,194,304 B (00.64%) -- other\n\
├───11,534,336 B (01.76%) -- heap-unclassified\n\
├──────510,976 B (00.08%) -- d\n\
└──────102,400 B (00.02%) -- e\n\
\n\
Resident Set Size (RSS) Breakdown\n\
@@ -329,17 +327,17 @@ Other Measurements\n\
1,048,576,000 B -- heap-allocated\n\
104,857,600 B -- heap-unallocated\n\
116,391,936 B -- other1\n\
\n\
3rd Process\n\
\n\
Explicit Allocations\n\
814,743,552 B (100.0%) -- explicit\n\
-├──814,743,552 B (100.0%) -- a [*]\n\
+├──814,743,552 B (100.0%) -- a\n\
│ ├──465,567,744 B (57.14%) -- c [2]\n\
│ ├──349,175,808 B (42.86%) -- b\n\
│ └────────────0 B (00.00%) -- d [*] [2]\n\
├────────────0 B (00.00%) -- b [*]\n\
└────────────0 B (00.00%) -- heap-unclassified [*]\n\
\n\
Other Measurements\n\
0 B -- heap-allocated [*]\n\