зеркало из https://github.com/mozilla/gecko-dev.git
Bug 719335 - Allow arbitrary collapsing/expanding of sub-trees in about:memory. r=jlebar.
--HG-- extra : rebase_source : fc26877e0c181a77c2ec15967ab33b75d1f96606
This commit is contained in:
Родитель
f7ec7b1eda
Коммит
694f1deae5
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 += "<div>" +
|
||||
"<button title='" + UpDesc + "' onclick='update()' id='updateButton'>Update</button>" +
|
||||
"<button title='" + GCDesc + "' onclick='doGlobalGC()'>GC</button>" +
|
||||
"<button title='" + CCDesc + "' onclick='doCC()'>CC</button>" +
|
||||
"<button title='" + MPDesc + "' onclick='sendHeapMinNotifications()'>" + "Minimize memory usage</button>" +
|
||||
|
@ -363,10 +355,12 @@ function update()
|
|||
"</div>";
|
||||
|
||||
text += "<div>" +
|
||||
"<span class='legend'>Hover the pointer over the name of a memory " +
|
||||
"reporter to see a detailed description of what it measures. Click a " +
|
||||
"heading to expand or collapse its tree.</span>" +
|
||||
"<span class='legend'>Click on a non-leaf node in a tree to expand ('++') " +
|
||||
"or collapse ('--') its children.</span>" +
|
||||
"</div>";
|
||||
text += "<div>" +
|
||||
"<span class='legend'>Hover the pointer over the name of a memory " +
|
||||
"reporter to see a description of what it measures.</span>";
|
||||
|
||||
var div = document.createElement("div");
|
||||
div.innerHTML = text;
|
||||
|
@ -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,55 +597,78 @@ 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)
|
||||
|
@ -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 "<span class='mrValue'>" + aValue + "</span>";
|
||||
return "<span class='mrValue'>" + aValue + " </span>";
|
||||
}
|
||||
|
||||
function kindToString(aKind)
|
||||
|
@ -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 = "-- <span class='mrName hasDesc' title='" +
|
||||
kindToString(aKind) + prepDesc(aDesc) +
|
||||
"'>" + prepName(aName) + "</span>";
|
||||
var text = "";
|
||||
if (aHasKids) {
|
||||
if (aShowSubtrees) {
|
||||
text += "<span class='mrSep hidden'>++ </span>";
|
||||
text += "<span class='mrSep'>-- </span>";
|
||||
} else {
|
||||
text += "<span class='mrSep'>++ </span>";
|
||||
text += "<span class='mrSep hidden'>-- </span>";
|
||||
}
|
||||
} else {
|
||||
text += "<span class='mrSep'>" + kHorizontal + kHorizontal + " </span>";
|
||||
}
|
||||
text += "<span class='mrName' title='" +
|
||||
kindToString(aKind) + prepDesc(aDesc) + "'>" +
|
||||
prepName(aName) + "</span>";
|
||||
if (aHasProblem) {
|
||||
const problemDesc =
|
||||
"Warning: this memory reporter was unable to compute a useful value. ";
|
||||
text += " <span class='mrStar' title=\"" + problemDesc + "\">[*]</span>";
|
||||
text += "<span class='mrStar' title=\"" + problemDesc + "\"> [*]</span>";
|
||||
}
|
||||
if (aNMerged) {
|
||||
const dupDesc = "This value is the sum of " + aNMerged +
|
||||
" memory reporters that all have the same path.";
|
||||
text += " <span class='mrStar' title=\"" + dupDesc + "\">[" +
|
||||
text += "<span class='mrStar' title=\"" + dupDesc + "\"> [" +
|
||||
aNMerged + "]</span>";
|
||||
}
|
||||
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 = "<span class='treeLine'>";
|
||||
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,37 +1075,63 @@ function genTreeText(aT, aProcess)
|
|||
}
|
||||
indent += "</span>";
|
||||
|
||||
// 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 = "<span class='mrPerc'>(" + percText + "%) </span>";
|
||||
|
||||
// Reinstate any previous toggling of this sub-tree.
|
||||
var path = aPrePath + aT._name;
|
||||
var treeId = escapeAll(aProcess + ":" + path);
|
||||
if (gToggles[treeId]) {
|
||||
showSubtrees = !showSubtrees;
|
||||
}
|
||||
perc = "<span class='mrPerc'>(" + perc + "%)</span> ";
|
||||
|
||||
// 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 +=
|
||||
"<span onclick='toggle(event)' class='hasKids' id='" + treeId + "'>";
|
||||
}
|
||||
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 += "</span><span class='kids" + hiddenText + "'>";
|
||||
}
|
||||
|
||||
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 ? "</span>" : "";
|
||||
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,
|
||||
|
@ -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 '<h2 id="' + headerId + '" class="' + elemClass + '" ' +
|
||||
'onclick="toggleTreeVisibility(event)">' +
|
||||
kTreeNames[aName] +
|
||||
'</h2>\n' +
|
||||
'<pre id="' + preId + '" class="' + elemClass + '">' + aText + '</pre>\n';
|
||||
return "<h2 class='sectionHeader'>" + kTreeNames[aName] + "</h2>\n" +
|
||||
"<pre class='tree'>" + aText + "</pre>\n";
|
||||
}
|
||||
|
||||
function assert(aCond, aMsg)
|
||||
|
|
|
@ -46,6 +46,7 @@ include $(topsrcdir)/config/rules.mk
|
|||
|
||||
_CHROME_FILES = \
|
||||
test_aboutmemory.xul \
|
||||
test_aboutmemory2.xul \
|
||||
test_sqliteMultiReporter.xul \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -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<script>window.alert(1)</script>\n\
|
||||
1,000.00 MB -- heap-allocated\n\
|
||||
100.00 MB -- heap-unallocated\n\
|
||||
111.00 MB -- other1\n\
|
||||
666.00 MB ── danger<script>window.alert(1)</script>\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<script>window.alert(1)</script>\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<script>window.alert(1)</script>\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() {
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<window title="about:memory"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<!-- This file tests the collapsing and expanding of sub-trees in
|
||||
about:memory. -->
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml"></body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
var mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
||||
getService(Ci.nsIMemoryReporterManager);
|
||||
|
||||
// Remove all the real reporters and multi-reporters; save them to
|
||||
// restore at the end.
|
||||
var e = mgr.enumerateReporters();
|
||||
var realReporters = [];
|
||||
while (e.hasMoreElements()) {
|
||||
var r = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
|
||||
mgr.unregisterReporter(r);
|
||||
realReporters.push(r);
|
||||
}
|
||||
e = mgr.enumerateMultiReporters();
|
||||
var realMultiReporters = [];
|
||||
while (e.hasMoreElements()) {
|
||||
var r = e.getNext().QueryInterface(Ci.nsIMemoryMultiReporter);
|
||||
mgr.unregisterMultiReporter(r);
|
||||
realMultiReporters.push(r);
|
||||
}
|
||||
|
||||
// Setup various fake-but-deterministic reporters.
|
||||
const KB = 1024;
|
||||
const MB = KB * KB;
|
||||
const HEAP = Ci.nsIMemoryReporter.KIND_HEAP;
|
||||
const OTHER = Ci.nsIMemoryReporter.KIND_OTHER;
|
||||
const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
|
||||
|
||||
function f(aPath, aKind, aAmount) {
|
||||
return {
|
||||
process: "",
|
||||
path: aPath,
|
||||
kind: aKind,
|
||||
units: BYTES,
|
||||
description: "(description)",
|
||||
amount: aAmount
|
||||
};
|
||||
}
|
||||
|
||||
var fakeReporters = [
|
||||
f("heap-allocated", OTHER, 250 * MB),
|
||||
f("explicit/a/b", HEAP, 50 * MB),
|
||||
f("explicit/a/c/d", HEAP, 30 * MB),
|
||||
f("explicit/a/c/e", HEAP, 20 * MB),
|
||||
f("explicit/a/f", HEAP, 40 * MB),
|
||||
f("explicit/g", HEAP, 100 * MB)
|
||||
];
|
||||
|
||||
for (var i = 0; i < fakeReporters.length; i++) {
|
||||
mgr.registerReporter(fakeReporters[i]);
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<iframe id="amFrame" height="500" src="about:memory"></iframe>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
function finish()
|
||||
{
|
||||
// Unregister fake reporters and multi-reporters, re-register the real
|
||||
// reporters and multi-reporters, just in case subsequent tests rely on
|
||||
// them.
|
||||
for (var i = 0; i < fakeReporters.length; i++) {
|
||||
mgr.unregisterReporter(fakeReporters[i]);
|
||||
}
|
||||
for (var i = 0; i < realReporters.length; i++) {
|
||||
mgr.registerReporter(realReporters[i]);
|
||||
}
|
||||
for (var i = 0; i < realMultiReporters.length; i++) {
|
||||
mgr.registerMultiReporter(realMultiReporters[i]);
|
||||
}
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
var gHaveDumped = false;
|
||||
|
||||
function checkClipboard(actual, expected) {
|
||||
if (actual != expected) {
|
||||
if (!gHaveDumped) {
|
||||
dump("******EXPECTED******\n");
|
||||
dump(expected);
|
||||
dump("*******ACTUAL*******\n");
|
||||
dump(actual);
|
||||
dump("********************\n");
|
||||
gHaveDumped = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Click on the identified element, then cut+paste the entire page and
|
||||
// check that the cut text matches what we expect.
|
||||
function test(aId, aExpectedText, aNext) {
|
||||
var win = document.getElementById("amFrame").contentWindow;
|
||||
var node = win.document.getElementById(aId);
|
||||
|
||||
// Yuk: clicking a button is easy; but for tree entries we need to
|
||||
// click on a child of the span identified via |id|.
|
||||
if (node.nodeName === "button") {
|
||||
node.click();
|
||||
} else {
|
||||
node.childNodes[0].click();
|
||||
}
|
||||
|
||||
SimpleTest.executeSoon(function() {
|
||||
document.getElementById("amFrame").focus();
|
||||
SimpleTest.waitForClipboard(
|
||||
function(actual) { return checkClipboard(actual, aExpectedText) },
|
||||
function() {
|
||||
synthesizeKey("A", {accelKey: true});
|
||||
synthesizeKey("C", {accelKey: true});
|
||||
},
|
||||
aNext,
|
||||
function() {
|
||||
ok(false, "pasted text doesn't match");
|
||||
finish();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Returns a function that chains together one test() call per id.
|
||||
function chain(ids) {
|
||||
var x = ids.shift();
|
||||
if (x) {
|
||||
return function() { test(x.id, x.expected, chain(ids)); }
|
||||
} else {
|
||||
return function() { finish(); };
|
||||
}
|
||||
}
|
||||
|
||||
var openExpected =
|
||||
"\
|
||||
Main Process\n\
|
||||
\n\
|
||||
Explicit Allocations\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──140.00 MB (56.00%) -- a\n\
|
||||
│ ├───50.00 MB (20.00%) ── b\n\
|
||||
│ ├───50.00 MB (20.00%) -- c\n\
|
||||
│ │ ├──30.00 MB (12.00%) ── d\n\
|
||||
│ │ └──20.00 MB (08.00%) ── e\n\
|
||||
│ └───40.00 MB (16.00%) ── f\n\
|
||||
├──100.00 MB (40.00%) ── g\n\
|
||||
└───10.00 MB (04.00%) ── heap-unclassified\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
";
|
||||
|
||||
var cClosedExpected =
|
||||
"\
|
||||
Main Process\n\
|
||||
\n\
|
||||
Explicit Allocations\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──140.00 MB (56.00%) -- a\n\
|
||||
│ ├───50.00 MB (20.00%) ── b\n\
|
||||
│ ├───50.00 MB (20.00%) ++ c\n\
|
||||
│ └───40.00 MB (16.00%) ── f\n\
|
||||
├──100.00 MB (40.00%) ── g\n\
|
||||
└───10.00 MB (04.00%) ── heap-unclassified\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
";
|
||||
|
||||
var aClosedExpected =
|
||||
"\
|
||||
Main Process\n\
|
||||
\n\
|
||||
Explicit Allocations\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──140.00 MB (56.00%) ++ a\n\
|
||||
├──100.00 MB (40.00%) ── g\n\
|
||||
└───10.00 MB (04.00%) ── heap-unclassified\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
";
|
||||
|
||||
// We close two sub-trees, hit the "Update" button, then reopen the two
|
||||
// sub-trees in reverse order. After each step, we check the output.
|
||||
var idsToClick = [
|
||||
{ id: "Main:explicit/a/c", expected: cClosedExpected },
|
||||
{ id: "Main:explicit/a", expected: aClosedExpected },
|
||||
{ id: "updateButton", expected: aClosedExpected },
|
||||
{ id: "Main:explicit/a", expected: cClosedExpected },
|
||||
{ id: "Main:explicit/a/c", expected: openExpected }
|
||||
];
|
||||
|
||||
addLoadEvent(chain(idsToClick));
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
Загрузка…
Ссылка в новой задаче