diff --git a/toolkit/components/aboutmemory/content/aboutMemory.css b/toolkit/components/aboutmemory/content/aboutMemory.css
index 6ee14aa353cf..7b82e4b24f9b 100644
--- a/toolkit/components/aboutmemory/content/aboutMemory.css
+++ b/toolkit/components/aboutmemory/content/aboutMemory.css
@@ -35,10 +35,29 @@
*
* ***** END LICENSE BLOCK ***** */
+body.verbose {
+ /* override setting in about.css */
+ max-width: 100% !important;
+}
+
+body.non-verbose pre.tree {
+ overflow-x: hidden;
+ text-overflow: ellipsis;
+}
+
+.sectionHeader {
+ background: #ddd;
+ padding-left: .1em;
+}
+
.accuracyWarning {
color: #f00;
}
+.treeLine {
+ color: #888;
+}
+
.mrValue {
font-weight: bold;
color: #400;
@@ -47,20 +66,23 @@
.mrPerc {
}
-.mrName {
- color: #004;
+.mrSep {
}
-.hasDesc:hover {
- text-decoration: underline;
+.mrName {
+ color: #004;
}
.mrStar {
color: #604;
}
-.treeLine {
- color: #888;
+.hasKids {
+ cursor: pointer;
+}
+
+.hasKids:hover {
+ text-decoration: underline;
}
.option {
@@ -73,22 +95,6 @@
-moz-user-select: none; /* no need to include this when cutting+pasting */
}
-body.verbose {
- /* override setting in about.css */
- max-width: 100% !important;
-}
-
-h2.tree {
- cursor: pointer;
- background: #ddd;
- padding-left: .1em;
-}
-
-body.non-verbose pre.tree {
- overflow-x: hidden;
- text-overflow: ellipsis;
-}
-
-pre.collapsed {
+.hidden {
display: none;
}
diff --git a/toolkit/components/aboutmemory/content/aboutMemory.js b/toolkit/components/aboutmemory/content/aboutMemory.js
index 8aae22d1cbc1..776bf42155e6 100644
--- a/toolkit/components/aboutmemory/content/aboutMemory.js
+++ b/toolkit/components/aboutmemory/content/aboutMemory.js
@@ -199,17 +199,6 @@ function sendHeapMinNotifications()
sendHeapMinNotificationsInner();
}
-function toggleTreeVisibility(aEvent)
-{
- var headerElem = aEvent.target;
-
- // Replace "header-" with "pre-" in the header element's id to get the id of
- // the corresponding pre element.
- var treeElem = $(headerElem.id.replace(/^header-/, 'pre-'));
-
- treeElem.classList.toggle('collapsed');
-}
-
function Reporter(aPath, aKind, aUnits, aAmount, aDescription)
{
this._path = aPath;
@@ -337,6 +326,7 @@ function update()
}
// Memory-related actions.
+ const UpDesc = "Re-measure.";
const GCDesc = "Do a global garbage collection.";
const CCDesc = "Do a cycle collection.";
const MPDesc = "Send three \"heap-minimize\" notifications in a " +
@@ -345,7 +335,9 @@ function update()
"process to reduce memory usage in other ways, e.g. by " +
"flushing various caches.";
+ // The "Update" button has an id so it can be clicked in a test.
text += "
" +
+ "
Hover the pointer over the name of a memory " +
+ "reporter to see a description of what it measures.";
var div = document.createElement("div");
div.innerHTML = text;
@@ -374,7 +368,7 @@ function update()
}
// There are two kinds of TreeNode.
-// - Leaf TreeNodes correspond to Reporters and have more properties.
+// - 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)
@@ -390,6 +384,9 @@ function TreeNode(aName)
// - _kind
// - _nMerged (if > 1)
// - _hasProblem (only defined if true)
+ //
+ // Non-leaf TreeNodes have these properties added later:
+ // - _hideKids (only defined if true)
}
TreeNode.prototype = {
@@ -524,6 +521,25 @@ function buildTree(aReporters, aTreeName)
return t;
}
+/**
+ * Ignore all the memory reporters that belong to a tree; this involves
+ * explicitly marking them as done.
+ *
+ * @param aReporters
+ * The table of Reporters, indexed by path.
+ * @param aTreeName
+ * The name of the tree being built.
+ */
+function ignoreTree(aReporters, aTreeName)
+{
+ for (var path in aReporters) {
+ var r = aReporters[path];
+ if (r.treeNameMatches(aTreeName)) {
+ var dummy = getBytes(aReporters, path);
+ }
+ }
+}
+
/**
* Do some work which only makes sense for the 'explicit' tree.
*
@@ -581,58 +597,81 @@ function fixUpExplicitTree(aT, aReporters)
}
/**
- * Sort all kid nodes from largest to smallest and aggregate insignificant
- * nodes.
+ * Sort all kid nodes from largest to smallest, and insert aggregate nodes
+ * where appropriate.
*
* @param aTotalBytes
* The size of the tree's root node.
* @param aT
* The tree.
*/
-function filterTree(aTotalBytes, aT)
+function sortTreeAndInsertAggregateNodes(aTotalBytes, aT)
{
- const omitThresholdPerc = 0.5; /* percent */
+ const kSignificanceThresholdPerc = 1;
- function shouldOmit(aBytes)
+ function isInsignificant(aT)
{
return !gVerbose &&
aTotalBytes !== kUnknown &&
- (100 * aBytes / aTotalBytes) < omitThresholdPerc;
+ (100 * aT._amount / aTotalBytes) < kSignificanceThresholdPerc;
+ }
+
+ if (aT._kids.length === 0) {
+ return;
}
aT._kids.sort(TreeNode.compare);
- for (var i = 0; i < aT._kids.length; i++) {
- if (shouldOmit(aT._kids[i]._amount)) {
- // This sub-tree is below the significance threshold
- // Remove it and all remaining (smaller) sub-trees, and
- // replace them with a single aggregate node.
+ // If the first child is insignificant, they all are, and there's no point
+ // creating an aggregate node that lacks siblings. Just set the parent's
+ // _hideKids property and process all children.
+ if (isInsignificant(aT._kids[0])) {
+ aT._hideKids = true;
+ for (var i = 0; i < aT._kids.length; i++) {
+ sortTreeAndInsertAggregateNodes(aTotalBytes, aT._kids[i]);
+ }
+ return;
+ }
+
+ // Look at all children except the last one.
+ for (var i = 0; i < aT._kids.length - 1; i++) {
+ if (isInsignificant(aT._kids[i])) {
+ // This child is below the significance threshold. If there are other
+ // (smaller) children remaining, move them under an aggregate node.
var i0 = i;
+ var nAgg = aT._kids.length - i0;
+ // Create an aggregate node.
+ var aggT = new TreeNode("(" + nAgg + " tiny)");
var aggBytes = 0;
for ( ; i < aT._kids.length; i++) {
aggBytes += aT._kids[i]._amount;
+ aggT._kids.push(aT._kids[i]);
}
- aT._kids.splice(i0, aT._kids.length);
- var n = i - i0;
- var rSub = new TreeNode("(" + n + " omitted)");
- rSub._amount = aggBytes;
- rSub._description =
- n + " sub-trees that were below the " + omitThresholdPerc +
- "% significance threshold. Click 'More verbose' at the bottom of " +
- "this page to see them.";
-
- // Add the "omitted" sub-tree at the end and then re-sort, because the
- // sum of the omitted sub-trees may be larger than some of the shown
- // sub-trees.
- aT._kids[i0] = rSub;
+ aggT._hideKids = true;
+ aggT._amount = aggBytes;
+ aggT._description =
+ nAgg + " sub-trees that are below the " + kSignificanceThresholdPerc +
+ "% significance threshold.";
+ aT._kids.splice(i0, nAgg, aggT);
aT._kids.sort(TreeNode.compare);
- break;
+
+ // Process the moved children.
+ for (i = 0; i < aggT._kids.length; i++) {
+ sortTreeAndInsertAggregateNodes(aTotalBytes, aggT._kids[i]);
+ }
+ return;
}
- filterTree(aTotalBytes, aT._kids[i]);
+
+ sortTreeAndInsertAggregateNodes(aTotalBytes, aT._kids[i]);
}
+
+ // The first n-1 children were significant. Don't consider if the last child
+ // is significant; there's no point creating an aggregate node that only has
+ // one child. Just process it.
+ sortTreeAndInsertAggregateNodes(aTotalBytes, aT._kids[i]);
}
-function genWarningText(aHasKnownHeapAllocated, aHasMozMallocUsableSize)
+function genWarningText(aHasKnownHeapAllocated, aHasMozMallocUsableSize)
{
var warningText = "";
@@ -677,7 +716,7 @@ function genProcessText(aProcess, aReporters, aHasMozMallocUsableSize)
{
var explicitTree = buildTree(aReporters, 'explicit');
var hasKnownHeapAllocated = fixUpExplicitTree(explicitTree, aReporters);
- filterTree(explicitTree._amount, explicitTree);
+ sortTreeAndInsertAggregateNodes(explicitTree._amount, explicitTree);
var explicitText = genTreeText(explicitTree, aProcess);
// Generate any warnings about inaccuracies due to platform limitations.
@@ -687,14 +726,20 @@ function genProcessText(aProcess, aReporters, aHasMozMallocUsableSize)
var warningText =
genWarningText(hasKnownHeapAllocated, aHasMozMallocUsableSize);
- var mapTreeText = '';
+ // We only show these breakdown trees in verbose mode.
+ var mapTreeText = "";
kMapTreePaths.forEach(function(t) {
- var tree = buildTree(aReporters, t);
+ if (gVerbose) {
+ var tree = buildTree(aReporters, t);
- // |tree| will be null if we don't have any reporters for the given path.
- if (tree) {
- filterTree(tree._amount, tree);
- mapTreeText += genTreeText(tree, aProcess);
+ // |tree| will be null if we don't have any reporters for the given path.
+ if (tree) {
+ sortTreeAndInsertAggregateNodes(tree._amount, tree);
+ tree._hideKids = true; // map trees are always initially collapsed
+ mapTreeText += genTreeText(tree, aProcess);
+ }
+ } else {
+ ignoreTree(aReporters, t);
}
});
@@ -835,9 +880,18 @@ function getDescription(aReporters, aPath)
return r._description;
}
+// There's a subset of the Unicode "light" box-drawing chars that are widely
+// implemented in terminals, and this code sticks to that subset to maximize
+// the chance that cutting and pasting about:memory output to a terminal will
+// work correctly:
+const kHorizontal = "\u2500",
+ kVertical = "\u2502",
+ kUpAndRight = "\u2514",
+ kVerticalAndRight = "\u251c";
+
function genMrValueText(aValue)
{
- return "
" + aValue + "";
+ return "
" + aValue + " ";
}
function kindToString(aKind)
@@ -861,7 +915,7 @@ function escapeAll(aStr)
// Compartment reporter names are URLs and so can include forward slashes. But
// forward slash is the memory reporter path separator. So the memory
-// reporters change them to backslashes. Undo that here.
+// reporters change them to backslashes. Undo that here.
function flipBackslashes(aStr)
{
return aStr.replace(/\\/g, '/');
@@ -877,25 +931,86 @@ function prepDesc(aStr)
return escapeAll(flipBackslashes(aStr));
}
-function genMrNameText(aKind, aDesc, aName, aHasProblem, aNMerged)
+function genMrNameText(aKind, aShowSubtrees, aHasKids, aDesc, aName,
+ aHasProblem, aNMerged)
{
- var text = "--
" + prepName(aName) + "";
+ var text = "";
+ if (aHasKids) {
+ if (aShowSubtrees) {
+ text += "
++ ";
+ text += "
-- ";
+ } else {
+ text += "
++ ";
+ text += "
-- ";
+ }
+ } else {
+ text += "
" + kHorizontal + kHorizontal + " ";
+ }
+ text += "
" +
+ prepName(aName) + "";
if (aHasProblem) {
const problemDesc =
"Warning: this memory reporter was unable to compute a useful value. ";
- text += "
[*]";
+ text += "
[*]";
}
if (aNMerged) {
const dupDesc = "This value is the sum of " + aNMerged +
" memory reporters that all have the same path.";
- text += "
[" +
+ text += " [" +
aNMerged + "]";
}
return text + '\n';
}
+// This is used to record which sub-trees have been toggled, so the
+// collapsed/expanded state can be replicated when the page is regenerated.
+// It can end up holding IDs of nodes that no longer exist, e.g. for
+// compartments that have been closed. This doesn't seem like a big deal,
+// because the number is limited by the number of entries the user has changed
+// from their original state.
+var gToggles = {};
+
+function toggle(aEvent)
+{
+ // This relies on each line being a span that contains at least five spans:
+ // mrValue, mrPerc, mrSep ('++'), mrSep ('--'), mrName, and then zero or more
+ // mrStars. All whitespace must be within one of these spans for this
+ // function to find the right nodes. And the span containing the children of
+ // this line must immediately follow. Assertions check this.
+
+ function assertClassName(span, className) {
+ assert(span, "undefined " + className);
+ assert(span.nodeName === "span", "non-span " + className);
+ assert(span.classList.contains(className), "bad " + className);
+ }
+
+ // |aEvent.target| will be one of the five spans. Get the outer span.
+ var outerSpan = aEvent.target.parentNode;
+ assertClassName(outerSpan, "hasKids");
+
+ // Toggle visibility of the '++' and '--' separators.
+ var plusSpan = outerSpan.childNodes[2];
+ var minusSpan = outerSpan.childNodes[3];
+ assertClassName(plusSpan, "mrSep");
+ assertClassName(minusSpan, "mrSep");
+ plusSpan .classList.toggle("hidden");
+ minusSpan.classList.toggle("hidden");
+
+ // Toggle visibility of the span containing this node's children.
+ var subTreeSpan = outerSpan.nextSibling;
+ assertClassName(subTreeSpan, "kids");
+ subTreeSpan.classList.toggle("hidden");
+
+ // Record/unrecord that this sub-tree was toggled.
+ var treeId = outerSpan.id;
+ if (gToggles[treeId]) {
+ delete gToggles[treeId];
+ } else {
+ gToggles[treeId] = true;
+ }
+}
+
/**
* Generates the text for the tree, including its heading.
*
@@ -914,6 +1029,8 @@ function genTreeText(aT, aProcess)
/**
* Generates the text for a particular tree, without a heading.
*
+ * @param aPrePath
+ * The partial path leading up to this node.
* @param aT
* The tree.
* @param aIndentGuide
@@ -925,7 +1042,7 @@ function genTreeText(aT, aProcess)
* The length of the formatted byte count of the top node in the tree.
* @return The generated text.
*/
- function genTreeText2(aT, aIndentGuide, aParentStringLength)
+ function genTreeText2(aPrePath, aT, aIndentGuide, aParentStringLength)
{
function repeatStr(aC, aN)
{
@@ -936,15 +1053,7 @@ function genTreeText(aT, aProcess)
return s;
}
- // Generate the indent. There's a subset of the Unicode "light"
- // box-drawing chars that are widely implemented in terminals, and
- // this code sticks to that subset to maximize the chance that
- // cutting and pasting about:memory output to a terminal will work
- // correctly:
- const kHorizontal = "\u2500",
- kVertical = "\u2502",
- kUpAndRight = "\u2514",
- kVerticalAndRight = "\u251c";
+ // Generate the indent.
var indent = "";
if (aIndentGuide.length > 0) {
for (var i = 0; i < aIndentGuide.length - 1; i++) {
@@ -954,7 +1063,6 @@ function genTreeText(aT, aProcess)
indent += aIndentGuide[i]._isLastKid ? kUpAndRight : kVerticalAndRight;
indent += repeatStr(kHorizontal, aIndentGuide[i]._depth - 1);
}
-
// Indent more if this entry is narrower than its parent, and update
// aIndentGuide accordingly.
var tString = aT.toString();
@@ -967,40 +1075,66 @@ function genTreeText(aT, aProcess)
}
indent += "";
- // Generate the percentage.
- var perc = "";
+ // Generate the percentage, and determine if we should show subtrees.
+ var percText = "";
+ var showSubtrees = !aT._hideKids;
if (aT._amount === treeBytes) {
- perc = "100.0";
+ percText = "100.0";
} else {
- perc = (100 * aT._amount / treeBytes).toFixed(2);
- perc = pad(perc, 5, '0');
+ var perc = (100 * aT._amount / treeBytes);
+ percText = (100 * aT._amount / treeBytes).toFixed(2);
+ percText = pad(percText, 5, '0');
+ }
+ percText = "(" + percText + "%) ";
+
+ // Reinstate any previous toggling of this sub-tree.
+ var path = aPrePath + aT._name;
+ var treeId = escapeAll(aProcess + ":" + path);
+ if (gToggles[treeId]) {
+ showSubtrees = !showSubtrees;
}
- perc = "(" + perc + "%) ";
// We don't want to show '(nonheap)' on a tree like 'map/vsize', since the
// whole tree is non-heap.
var kind = isExplicitTree ? aT._kind : undefined;
- var text = indent + genMrValueText(tString) + " " + perc +
- genMrNameText(kind, aT._description, aT._name,
- aT._hasProblem, aT._nMerged);
+
+ // For non-leaf nodes, the entire sub-tree is put within a span so it can
+ // be collapsed if the node is clicked on.
+ var hasKids = aT._kids.length > 0;
+ if (!hasKids) {
+ assert(!aT._hideKids, "leaf node with _hideKids set")
+ }
+ var text = indent;
+ if (hasKids) {
+ text +=
+ "";
+ }
+ text += genMrValueText(tString) + percText;
+ text += genMrNameText(kind, showSubtrees, hasKids, aT._description,
+ aT._name, aT._hasProblem, aT._nMerged);
+ if (hasKids) {
+ var hiddenText = showSubtrees ? "" : " hidden";
+ // The 'kids' class is just used for sanity checking in toggle().
+ text += "";
+ }
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 });
- text += genTreeText2(aT._kids[i], aIndentGuide, tString.length);
+ text += genTreeText2(path + "/", aT._kids[i], aIndentGuide,
+ tString.length);
aIndentGuide.pop();
}
+ text += hasKids ? "" : "";
return text;
}
- var text = genTreeText2(aT, [], rootStringLength);
+ var text = genTreeText2(/* prePath = */"", aT, [], rootStringLength);
- // The explicit tree is not collapsed, but all other trees are, so pass
- // !isExplicitTree for genSectionMarkup's aCollapsed parameter.
- return genSectionMarkup(aProcess, aT._name, text, !isExplicitTree);
+ return genSectionMarkup(aT._name, text);
}
-function OtherReporter(aPath, aUnits, aAmount, aDescription,
+function OtherReporter(aPath, aUnits, aAmount, aDescription,
aNMerged)
{
// Nb: _kind is not needed, it's always KIND_OTHER.
@@ -1055,7 +1189,7 @@ function genOtherText(aReportersByProcess, aProcess)
var r = aReportersByProcess[path];
if (!r._done) {
assert(r._kind === KIND_OTHER, "_kind !== KIND_OTHER for " + r._path);
- assert(r.nMerged === undefined); // we don't allow dup'd OTHER reporters
+ assert(r.nMerged === undefined); // we don't allow dup'd OTHER reporters
var hasProblem = false;
if (r._amount === kUnknown) {
hasProblem = true;
@@ -1073,29 +1207,19 @@ function genOtherText(aReportersByProcess, aProcess)
var text = "";
for (var i = 0; i < otherReporters.length; i++) {
var o = otherReporters[i];
- text += genMrValueText(pad(o.asString, maxStringLength, ' ')) + " ";
- text += genMrNameText(KIND_OTHER, o._description, o._path, o._hasProblem);
+ text += genMrValueText(pad(o.asString, maxStringLength, ' '));
+ text += genMrNameText(KIND_OTHER, /* showSubtrees = */true,
+ /* hasKids = */false, o._description, o._path,
+ o._hasProblem);
}
- // Nb: the newlines give nice spacing if we cut+paste into a text buffer.
- const desc = "This list contains other memory measurements that cross-cut " +
- "the requested memory measurements above."
-
- return genSectionMarkup(aProcess, 'other', text, false);
+ return genSectionMarkup('other', text);
}
-function genSectionMarkup(aProcess, aName, aText, aCollapsed)
+function genSectionMarkup(aName, aText)
{
- var headerId = 'header-' + aProcess + '-' + aName;
- var preId = 'pre-' + aProcess + '-' + aName;
- var elemClass = (aCollapsed ? 'collapsed' : '') + ' tree';
-
- // Ugh.
- return '\n' +
- '' + aText + '
\n';
+ return "\n" +
+ "" + aText + "
\n";
}
function assert(aCond, aMsg)
diff --git a/toolkit/components/aboutmemory/tests/Makefile.in b/toolkit/components/aboutmemory/tests/Makefile.in
index 802b23877766..bffd47a7e87d 100644
--- a/toolkit/components/aboutmemory/tests/Makefile.in
+++ b/toolkit/components/aboutmemory/tests/Makefile.in
@@ -46,6 +46,7 @@ include $(topsrcdir)/config/rules.mk
_CHROME_FILES = \
test_aboutmemory.xul \
+ test_aboutmemory2.xul \
test_sqliteMultiReporter.xul \
$(NULL)
diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul
index f52751ef23b0..1289509853d3 100644
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul
+++ b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul
@@ -123,6 +123,7 @@
f("map/vsize/a", 19);
f("map/swap/b/c", 10);
f("map/resident/a", 42);
+ f("map/pss/a", 43);
},
explicitNonHeap: 0
}
@@ -186,50 +187,33 @@ Main Process\n\
Explicit Allocations\n\
623.58 MB (100.0%) -- explicit\n\
├──232.00 MB (37.20%) -- b\n\
-│ ├───85.00 MB (13.63%) -- a\n\
-│ ├───75.00 MB (12.03%) -- b\n\
+│ ├───85.00 MB (13.63%) ── a\n\
+│ ├───75.00 MB (12.03%) ── b\n\
│ └───72.00 MB (11.55%) -- c\n\
-│ ├──70.00 MB (11.23%) -- a\n\
-│ └───2.00 MB (00.32%) -- (1 omitted)\n\
-├──222.00 MB (35.60%) -- a\n\
+│ ├──70.00 MB (11.23%) ── a\n\
+│ └───2.00 MB (00.32%) ── b\n\
+├──222.00 MB (35.60%) ── a\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\
+│ ├───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\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\
-└──0.16 MB (100.0%) -- a\n\
-\n\
-Virtual Size Breakdown\n\
-0.17 MB (100.0%) -- vsize\n\
-└──0.17 MB (100.0%) -- a [2]\n\
-\n\
-Swap Usage Breakdown\n\
-0.05 MB (100.0%) -- swap\n\
-├──0.04 MB (76.92%) -- b\n\
-│ └──0.04 MB (76.92%) -- c\n\
-└──0.01 MB (23.08%) -- a [2]\n\
+│ └──20.00 MB (03.21%) ── i\n\
+├───15.00 MB (02.41%) ++ g\n\
+├───11.00 MB (01.76%) ── heap-unclassified\n\
+└────0.58 MB (00.09%) ++ (2 tiny)\n\
\n\
Other Measurements\n\
-500.00 MB -- heap-allocated\n\
-100.00 MB -- heap-unallocated\n\
-111.00 MB -- other1\n\
-222.00 MB -- other2\n\
- 777 -- other3\n\
- 888 -- other4\n\
- 45.67% -- perc1\n\
- 100.00% -- perc2\n\
+500.00 MB ── heap-allocated\n\
+100.00 MB ── heap-unallocated\n\
+111.00 MB ── other1\n\
+222.00 MB ── other2\n\
+ 777 ── other3\n\
+ 888 ── other4\n\
+ 45.67% ── perc1\n\
+ 100.00% ── perc2\n\
\n\
2nd Process\n\
\n\
@@ -237,16 +221,16 @@ Explicit Allocations\n\
1,000.00 MB (100.0%) -- explicit\n\
├────499.00 MB (49.90%) -- a\n\
│ └──499.00 MB (49.90%) -- b\n\
-│ └──499.00 MB (49.90%) -- c [3]\n\
-├────200.00 MB (20.00%) -- flip/the/backslashes\n\
-├────200.00 MB (20.00%) -- compartment(compartment-url)\n\
-└────101.00 MB (10.10%) -- heap-unclassified\n\
+│ └──499.00 MB (49.90%) ── c [3]\n\
+├────200.00 MB (20.00%) ── flip/the/backslashes\n\
+├────200.00 MB (20.00%) ── compartment(compartment-url)\n\
+└────101.00 MB (10.10%) ── heap-unclassified\n\
\n\
Other Measurements\n\
- 666.00 MB -- danger\n\
-1,000.00 MB -- heap-allocated\n\
- 100.00 MB -- heap-unallocated\n\
- 111.00 MB -- other1\n\
+ 666.00 MB ── danger\n\
+1,000.00 MB ── heap-allocated\n\
+ 100.00 MB ── heap-unallocated\n\
+ 111.00 MB ── other1\n\
\n\
3rd Process\n\
\n\
@@ -255,14 +239,14 @@ WARNING: the 'heap-allocated' memory reporter does not work for this platform an
Explicit Allocations\n\
777.00 MB (100.0%) -- explicit\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\
+│ ├──444.00 MB (57.14%) ── c [2]\n\
+│ ├──333.00 MB (42.86%) ── b\n\
+│ └────0.00 MB (00.00%) ── d [*] [2]\n\
+└────0.00 MB (00.00%) ++ (2 tiny)\n\
\n\
Other Measurements\n\
-0.00 MB -- heap-allocated [*]\n\
-0.00 MB -- other1 [*]\n\
+0.00 MB ── heap-allocated [*]\n\
+0.00 MB ── other1 [*]\n\
\n\
";
@@ -273,51 +257,49 @@ Main Process\n\
Explicit Allocations\n\
653,876,224 B (100.0%) -- explicit\n\
├──243,269,632 B (37.20%) -- b\n\
-│ ├───89,128,960 B (13.63%) -- a\n\
-│ ├───78,643,200 B (12.03%) -- b\n\
+│ ├───89,128,960 B (13.63%) ── a\n\
+│ ├───78,643,200 B (12.03%) ── b\n\
│ └───75,497,472 B (11.55%) -- c\n\
-│ ├──73,400,320 B (11.23%) -- a\n\
-│ └───2,097,152 B (00.32%) -- b\n\
-├──232,783,872 B (35.60%) -- a\n\
+│ ├──73,400,320 B (11.23%) ── a\n\
+│ └───2,097,152 B (00.32%) ── b\n\
+├──232,783,872 B (35.60%) ── a\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\
+│ ├───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\
+│ └──20,971,520 B (03.21%) ── i\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\
+│ ├───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\
-172,032 B (100.0%) -- resident\n\
-└──172,032 B (100.0%) -- a\n\
+172,032 B (100.0%) ++ resident\n\
+\n\
+Proportional Set Size (PSS) Breakdown\n\
+176,128 B (100.0%) ++ pss\n\
\n\
Virtual Size Breakdown\n\
-176,128 B (100.0%) -- vsize\n\
-└──176,128 B (100.0%) -- a [2]\n\
+176,128 B (100.0%) ++ vsize\n\
\n\
Swap Usage Breakdown\n\
-53,248 B (100.0%) -- swap\n\
-├──40,960 B (76.92%) -- b\n\
-│ └──40,960 B (76.92%) -- c\n\
-└──12,288 B (23.08%) -- a [2]\n\
+53,248 B (100.0%) ++ swap\n\
\n\
Other Measurements\n\
-524,288,000 B -- heap-allocated\n\
-104,857,600 B -- heap-unallocated\n\
-116,391,936 B -- other1\n\
-232,783,872 B -- other2\n\
- 777 -- other3\n\
- 888 -- other4\n\
- 45.67% -- perc1\n\
- 100.00% -- perc2\n\
+524,288,000 B ── heap-allocated\n\
+104,857,600 B ── heap-unallocated\n\
+116,391,936 B ── other1\n\
+232,783,872 B ── other2\n\
+ 777 ── other3\n\
+ 888 ── other4\n\
+ 45.67% ── perc1\n\
+ 100.00% ── perc2\n\
\n\
2nd Process\n\
\n\
@@ -325,16 +307,16 @@ Explicit Allocations\n\
1,048,576,000 B (100.0%) -- explicit\n\
├────523,239,424 B (49.90%) -- a\n\
│ └──523,239,424 B (49.90%) -- b\n\
-│ └──523,239,424 B (49.90%) -- c [3]\n\
-├────209,715,200 B (20.00%) -- flip/the/backslashes\n\
-├────209,715,200 B (20.00%) -- compartment(compartment-url)\n\
-└────105,906,176 B (10.10%) -- heap-unclassified\n\
+│ └──523,239,424 B (49.90%) ── c [3]\n\
+├────209,715,200 B (20.00%) ── flip/the/backslashes\n\
+├────209,715,200 B (20.00%) ── compartment(compartment-url)\n\
+└────105,906,176 B (10.10%) ── heap-unclassified\n\
\n\
Other Measurements\n\
- 698,351,616 B -- danger\n\
-1,048,576,000 B -- heap-allocated\n\
- 104,857,600 B -- heap-unallocated\n\
- 116,391,936 B -- other1\n\
+ 698,351,616 B ── danger\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\
@@ -343,15 +325,15 @@ WARNING: the 'heap-allocated' memory reporter does not work for this platform an
Explicit Allocations\n\
814,743,552 B (100.0%) -- explicit\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\
+│ ├──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\
-0 B -- other1 [*]\n\
+0 B ── heap-allocated [*]\n\
+0 B ── other1 [*]\n\
\n\
"
@@ -375,13 +357,18 @@ Other Measurements\n\
SimpleTest.finish();
}
+ var gHaveDumped = false;
+
function checkClipboard(actual, expected) {
if (actual != expected) {
- dump("*******ACTUAL*******\n");
- dump(actual);
- dump("******EXPECTED******\n");
- dump(expected);
- dump("********************\n");
+ if (!gHaveDumped) {
+ dump("******EXPECTED******\n");
+ dump(expected);
+ dump("*******ACTUAL*******\n");
+ dump(actual);
+ dump("********************\n");
+ gHaveDumped = true;
+ }
return false;
}
return true;
@@ -391,15 +378,8 @@ Other Measurements\n\
// expect. This tests the output in general and also that the cutting and
// pasting works as expected.
function test(aFrame, aExpectedText, aNext) {
- // Click all h2.collapsed elements so they expand.
- var win = document.querySelector("#" + aFrame).contentWindow;
- var nodes = win.document.querySelectorAll("pre.collapsed");
- for (var i = 0; i < nodes.length; i++) {
- nodes[i].classList.toggle('collapsed');
- }
-
SimpleTest.executeSoon(function() {
- document.querySelector("#" + aFrame).focus();
+ document.getElementById(aFrame).focus();
SimpleTest.waitForClipboard(
function(actual) { return checkClipboard(actual, aExpectedText) },
function() {
diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul
new file mode 100644
index 000000000000..d8bc318d4597
--- /dev/null
+++ b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+