Bug 1260261 - Associate a `CensusTreeNode` with the leaf in the census report from which it was generated; r=jimb

This commit gives every `CensusTreeNode` instance a `reportLeafIndex` member
that is an index into a pre-order traversal of the census report from which it
was generated. This can be used to get the leaf in the census report
corresponding to a given `CensusTreeNode` instance.
This commit is contained in:
Nick Fitzgerald 2016-03-29 08:53:00 +02:00
Родитель 664b09649c
Коммит 3475bae57b
16 изменённых файлов: 214 добавлений и 26 удалений

Просмотреть файл

@ -282,6 +282,9 @@ function CensusTreeNodeVisitor() {
// The stack of `CensusTreeNodeCache`s that we use to aggregate many
// SavedFrame stacks into a single CensusTreeNode tree.
this._cacheStack = [new CensusTreeNodeCache()];
// The current index in the DFS of the census report tree.
this._index = -1;
}
CensusTreeNodeVisitor.prototype = Object.create(Visitor);
@ -293,6 +296,8 @@ CensusTreeNodeVisitor.prototype = Object.create(Visitor);
* @overrides Visitor.prototype.enter
*/
CensusTreeNodeVisitor.prototype.enter = function (breakdown, report, edge) {
this._index++;
const cache = this._cacheStack[this._cacheStack.length - 1];
makeCensusTreeNodeSubTree(breakdown, report, edge, cache, this._outParams);
const { top, bottom } = this._outParams;
@ -364,6 +369,7 @@ CensusTreeNodeVisitor.prototype.exit = function (breakdown, report, edge) {
*/
CensusTreeNodeVisitor.prototype.count = function (breakdown, report, edge) {
const node = this._nodeStack[this._nodeStack.length - 1];
node.reportLeafIndex = this._index;
if (breakdown.count) {
node.count = report.count;
@ -425,6 +431,27 @@ function CensusTreeNode(name) {
// If present, the unique ID of this node's parent. If this node does not have
// a parent, then undefined.
this.parent = undefined;
// The `reportLeafIndex` property allows mapping a CensusTreeNode node back to
// a leaf in the census report it was generated from. It is always one of the
// following variants:
//
// * A `Number` index pointing a leaf report in a pre-order DFS traversal of
// this CensusTreeNode's census report.
//
// * A `Set` object containing such indices, when this is part of an inverted
// CensusTreeNode tree and multiple leaves in the report map onto this node.
//
// * Finally, `undefined` when no leaves in the census report correspond with
// this node.
//
// The first and third cases are the common cases. The second case is rather
// uncommon, and to avoid doubling the number of allocations when creating
// CensusTreeNode trees, and objects that get structured cloned when sending
// such trees from the HeapAnalysesWorker to the main thread, we only allocate
// a Set object once a node actually does have multiple leaves it corresponds
// to.
this.reportLeafIndex = undefined;
}
CensusTreeNode.prototype = null;
@ -484,12 +511,28 @@ function insertOrMergeNode(parentCacheValue, node) {
let val = CensusTreeNodeCache.lookupNode(parentCacheValue.children, node);
if (val) {
// When inverting, it is possible that multiple leaves in the census report
// get merged into a single CensusTreeNode node. When this occurs, switch
// from a single index to a set of indices.
if (val.node.reportLeafIndex !== undefined &&
val.node.reportLeafIndex !== node.reportLeafIndex) {
if (typeof val.node.reportLeafIndex === "number") {
const oldIndex = val.node.reportLeafIndex;
val.node.reportLeafIndex = new Set();
val.node.reportLeafIndex.add(oldIndex);
val.node.reportLeafIndex.add(node.reportLeafIndex);
} else {
val.node.reportLeafIndex.add(node.reportLeafIndex);
}
}
val.node.count += node.count;
val.node.bytes += node.bytes;
} else {
val = new CensusTreeNodeCacheValue();
val.node = new CensusTreeNode(node.name);
val.node.reportLeafIndex = node.reportLeafIndex;
val.node.count = node.count;
val.node.totalCount = node.totalCount;
val.node.bytes = node.bytes;

Просмотреть файл

@ -253,6 +253,17 @@ function assertStructurallyEquivalent(actual, expected, path="root") {
equal(expectedKeys.size, 0,
`${path}: every key in expected should also exist in actual, did not see ${[...expectedKeys]}`);
} else if (actualProtoString === "[object Set]") {
const expectedItems = new Set([...expected]);
for (let item of actual) {
ok(expectedItems.has(item),
`${path}: every set item in actual should exist in expected: ${item}`);
expectedItems.delete(item);
}
equal(expectedItems.size, 0,
`${path}: every set item in expected should also exist in actual, did not see ${[...expectedItems]}`);
} else {
const expectedKeys = new Set(Object.keys(expected));

Просмотреть файл

@ -40,7 +40,8 @@ const EXPECTED = {
totalCount: 50,
children: undefined,
id: 3,
parent: 1
parent: 1,
reportLeafIndex: 2,
},
{
name: "JSObject",
@ -50,7 +51,8 @@ const EXPECTED = {
totalCount: 10,
children: undefined,
id: 2,
parent: 1
parent: 1,
reportLeafIndex: 1,
},
{
name: "JSString",
@ -60,11 +62,13 @@ const EXPECTED = {
totalCount: 1,
children: undefined,
id: 4,
parent: 1
parent: 1,
reportLeafIndex: 3,
},
],
id: 1,
parent: undefined,
reportLeafIndex: undefined,
};
function run_test() {

Просмотреть файл

@ -51,6 +51,7 @@ const EXPECTED = {
children: undefined,
id: 9,
parent: 7,
reportLeafIndex: 8,
},
{
name: "js::Shape",
@ -61,10 +62,12 @@ const EXPECTED = {
children: undefined,
id: 8,
parent: 7,
reportLeafIndex: 7,
},
],
id: 7,
parent: 1,
reportLeafIndex: undefined,
},
{
name: "objects",
@ -82,6 +85,7 @@ const EXPECTED = {
children: undefined,
id: 4,
parent: 2,
reportLeafIndex: 3,
},
{
name: "Function",
@ -92,10 +96,12 @@ const EXPECTED = {
children: undefined,
id: 3,
parent: 2,
reportLeafIndex: 2,
},
],
id: 2,
parent: 1,
reportLeafIndex: undefined,
},
{
name: "strings",
@ -106,6 +112,7 @@ const EXPECTED = {
children: undefined,
id: 6,
parent: 1,
reportLeafIndex: 5,
},
{
name: "scripts",
@ -116,10 +123,12 @@ const EXPECTED = {
children: undefined,
id: 5,
parent: 1,
reportLeafIndex: 4,
},
],
id: 1,
parent: undefined,
reportLeafIndex: undefined,
};
function run_test() {

Просмотреть файл

@ -38,6 +38,7 @@ const EXPECTED = {
children: undefined,
id: 3,
parent: 1,
reportLeafIndex: 2,
},
{
name: "other",
@ -55,6 +56,7 @@ const EXPECTED = {
children: undefined,
id: 6,
parent: 4,
reportLeafIndex: 5,
},
{
name: "JIT::CODE::NOW!!!",
@ -65,10 +67,12 @@ const EXPECTED = {
children: undefined,
id: 5,
parent: 4,
reportLeafIndex: 4,
},
],
id: 4,
parent: 1,
reportLeafIndex: undefined,
},
{
name: "Function",
@ -79,10 +83,12 @@ const EXPECTED = {
children: undefined,
id: 2,
parent: 1,
reportLeafIndex: 1,
},
],
id: 1,
parent: undefined,
reportLeafIndex: undefined,
};
function run_test() {

Просмотреть файл

@ -70,6 +70,7 @@ function run_test() {
children: undefined,
id: 7,
parent: 5,
reportLeafIndex: 3,
},
{
name: stack2,
@ -80,10 +81,12 @@ function run_test() {
children: undefined,
id: 6,
parent: 5,
reportLeafIndex: 2,
}
],
id: 5,
parent: 2,
reportLeafIndex: undefined,
},
{
name: stack4,
@ -94,6 +97,7 @@ function run_test() {
children: undefined,
id: 8,
parent: 2,
reportLeafIndex: 4,
},
{
name: stack1.parent,
@ -111,14 +115,17 @@ function run_test() {
children: undefined,
id: 4,
parent: 3,
reportLeafIndex: 1,
},
],
id: 3,
parent: 2,
reportLeafIndex: undefined,
},
],
id: 2,
parent: 1,
reportLeafIndex: undefined,
},
{
name: "noStack",
@ -129,6 +136,7 @@ function run_test() {
children: undefined,
id: 10,
parent: 1,
reportLeafIndex: 6,
},
{
name: stack5,
@ -139,10 +147,12 @@ function run_test() {
children: undefined,
id: 9,
parent: 1,
reportLeafIndex: 5
},
],
id: 1,
parent: undefined,
reportLeafIndex: undefined,
};
compareCensusViewData(BREAKDOWN, REPORT, EXPECTED);

Просмотреть файл

@ -74,6 +74,7 @@ function run_test() {
children: undefined,
id: 8,
parent: 4,
reportLeafIndex: 5,
},
{
name: "Baz",
@ -84,6 +85,7 @@ function run_test() {
children: undefined,
id: 7,
parent: 4,
reportLeafIndex: 4,
},
{
name: "Bar",
@ -94,6 +96,7 @@ function run_test() {
children: undefined,
id: 6,
parent: 4,
reportLeafIndex: 3,
},
{
name: "Foo",
@ -104,18 +107,22 @@ function run_test() {
children: undefined,
id: 5,
parent: 4,
reportLeafIndex: 2,
},
],
id: 4,
parent: 3,
reportLeafIndex: undefined,
}
],
id: 3,
parent: 2,
reportLeafIndex: undefined,
}
],
id: 2,
parent: 1,
reportLeafIndex: undefined,
},
{
name: "noStack",
@ -126,10 +133,12 @@ function run_test() {
children: undefined,
id: 9,
parent: 1,
reportLeafIndex: 6,
},
],
id: 1,
parent: undefined,
reportLeafIndex: undefined,
};
compareCensusViewData(BREAKDOWN, REPORT, EXPECTED);

Просмотреть файл

@ -68,10 +68,12 @@ function run_test() {
children: undefined,
id: 16,
parent: 15,
reportLeafIndex: undefined,
}
],
id: 15,
parent: 14,
reportLeafIndex: 6,
},
{
name: abc_Stack,
@ -89,6 +91,7 @@ function run_test() {
children: undefined,
id: 18,
parent: 17,
reportLeafIndex: undefined,
},
{
name: abc_Stack.parent,
@ -106,6 +109,7 @@ function run_test() {
children: undefined,
id: 22,
parent: 19,
reportLeafIndex: undefined,
},
{
name: abc_Stack.parent.parent,
@ -123,10 +127,12 @@ function run_test() {
children: undefined,
id: 21,
parent: 20,
reportLeafIndex: undefined,
}
],
id: 20,
parent: 19,
reportLeafIndex: undefined,
},
{
name: dbc_Stack.parent.parent,
@ -144,14 +150,17 @@ function run_test() {
children: undefined,
id: 24,
parent: 23,
reportLeafIndex: undefined,
}
],
id: 23,
parent: 19,
reportLeafIndex: undefined,
}
],
id: 19,
parent: 17,
reportLeafIndex: undefined,
},
{
name: ec_Stack.parent,
@ -169,18 +178,22 @@ function run_test() {
children: undefined,
id: 26,
parent: 25,
reportLeafIndex: undefined,
},
],
id: 25,
parent: 17,
reportLeafIndex: undefined,
},
],
id: 17,
parent: 14,
reportLeafIndex: new Set([1, 2, 3, 4, 5]),
}
],
id: 14,
parent: undefined,
reportLeafIndex: undefined,
};
compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { invert: true });

Просмотреть файл

@ -73,14 +73,17 @@ function run_test() {
children: undefined,
id: 14,
parent: 13,
reportLeafIndex: undefined,
}
],
id: 13,
parent: 12,
reportLeafIndex: undefined,
}
],
id: 12,
parent: 11,
reportLeafIndex: 9,
},
{
name: "JSAtom",
@ -105,14 +108,17 @@ function run_test() {
children: undefined,
id: 17,
parent: 16,
reportLeafIndex: undefined,
}
],
id: 16,
parent: 15,
reportLeafIndex: undefined,
}
],
id: 15,
parent: 11,
reportLeafIndex: 7,
},
{
name: "Array",
@ -137,14 +143,17 @@ function run_test() {
children: undefined,
id: 20,
parent: 19,
reportLeafIndex: undefined,
}
],
id: 19,
parent: 18,
reportLeafIndex: undefined,
}
],
id: 18,
parent: 11,
reportLeafIndex: 2,
},
{
name: "js::jit::JitScript",
@ -169,18 +178,22 @@ function run_test() {
children: undefined,
id: 23,
parent: 22,
reportLeafIndex: undefined,
}
],
id: 22,
parent: 21,
reportLeafIndex: undefined,
}
],
id: 21,
parent: 11,
reportLeafIndex: 5,
},
],
id: 11,
parent: undefined,
reportLeafIndex: undefined,
};
compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { invert: true });

Просмотреть файл

@ -55,11 +55,13 @@ function run_test() {
totalCount: 40,
children: undefined,
id: 9,
parent: 8
parent: 8,
reportLeafIndex: 8,
}
],
id: 8,
parent: 1
parent: 1,
reportLeafIndex: undefined,
},
{
name: "http://example.com/trackers.js",
@ -76,11 +78,13 @@ function run_test() {
totalCount: 30,
children: undefined,
id: 7,
parent: 6
parent: 6,
reportLeafIndex: 6,
}
],
id: 6,
parent: 1
parent: 1,
reportLeafIndex: undefined,
},
{
name: "http://example.com/ads.js",
@ -97,11 +101,13 @@ function run_test() {
totalCount: 20,
children: undefined,
id: 5,
parent: 4
parent: 4,
reportLeafIndex: 4,
}
],
id: 4,
parent: 1
parent: 1,
reportLeafIndex: undefined,
},
{
name: "http://example.com/app.js",
@ -118,15 +124,18 @@ function run_test() {
totalCount: 10,
children: undefined,
id: 3,
parent: 2
parent: 2,
reportLeafIndex: 2,
}
],
id: 2,
parent: 1
parent: 1,
reportLeafIndex: undefined,
}
],
id: 1,
parent: undefined,
reportLeafIndex: undefined,
};
compareCensusViewData(BREAKDOWN, REPORT, EXPECTED);

Просмотреть файл

@ -0,0 +1,43 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Test when multiple leaves in the census report map to the same node in an
* inverted CensusReportTree.
*/
function run_test() {
const BREAKDOWN = {
by: "coarseType",
objects: {
by: "objectClass",
then: { by: "count", count: true, bytes: true },
},
other: {
by: "internalType",
then: { by: "count", count: true, bytes: true },
},
strings: { by: "count", count: true, bytes: true },
scripts: { by: "count", count: true, bytes: true },
};
const REPORT = {
objects: {
Array: { count: 1, bytes: 10 },
},
other: {
Array: { count: 1, bytes: 10 },
},
strings: { count: 0, bytes: 0 },
scripts: { count: 0, bytes: 0 },
};
const node = censusReportToCensusTreeNode(BREAKDOWN, REPORT, { invert: true });
equal(node.children[0].name, "Array");
equal(node.children[0].reportLeafIndex.size, 2);
dumpn(`node.children[0].reportLeafIndex = ${[...node.children[0].reportLeafIndex]}`);
ok(node.children[0].reportLeafIndex.has(2));
ok(node.children[0].reportLeafIndex.has(6));
}

Просмотреть файл

@ -65,7 +65,8 @@ function run_test() {
totalCount: 32,
children: undefined,
id: 15,
parent: 14
parent: 14,
reportLeafIndex: 4,
},
{
name: "UInt8Array",
@ -75,7 +76,8 @@ function run_test() {
totalCount: 8,
children: undefined,
id: 16,
parent: 14
parent: 14,
reportLeafIndex: 3,
},
{
name: "Array",
@ -85,15 +87,18 @@ function run_test() {
totalCount: 5,
children: undefined,
id: 17,
parent: 14
parent: 14,
reportLeafIndex: 2,
}
],
id: 14,
parent: 13
parent: 13,
reportLeafIndex: undefined,
}
],
id: 13,
parent: undefined,
reportLeafIndex: undefined,
};
compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { filter: "Array" });

Просмотреть файл

@ -67,7 +67,8 @@ function run_test() {
totalCount: 3,
children: undefined,
id: 15,
parent: 14
parent: 14,
reportLeafIndex: 3,
},
{
name: stack2,
@ -77,11 +78,13 @@ function run_test() {
totalCount: 2,
children: undefined,
id: 16,
parent: 14
parent: 14,
reportLeafIndex: 2,
}
],
id: 14,
parent: 13
parent: 13,
reportLeafIndex: undefined,
},
{
name: stack1.parent,
@ -98,19 +101,23 @@ function run_test() {
totalCount: 1,
children: undefined,
id: 18,
parent: 17
parent: 17,
reportLeafIndex: 1,
}
],
id: 17,
parent: 13
parent: 13,
reportLeafIndex: undefined,
}
],
id: 13,
parent: 12
parent: 12,
reportLeafIndex: undefined,
}
],
id: 12,
parent: undefined
parent: undefined,
reportLeafIndex: undefined,
};
compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { filter: "bar" });

Просмотреть файл

@ -52,6 +52,7 @@ function run_test() {
children: undefined,
id: 13,
parent: undefined,
reportLeafIndex: undefined,
};
compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { filter: "zzzzzzzzzzzzzzzzzzzz" });

Просмотреть файл

@ -74,7 +74,8 @@ function run_test() {
totalCount: 7,
id: 13,
parent: 12,
children: undefined
children: undefined,
reportLeafIndex: 2,
},
{
name: "Array",
@ -84,14 +85,17 @@ function run_test() {
totalCount: 6,
id: 14,
parent: 12,
children: undefined
children: undefined,
reportLeafIndex: 3,
},
],
id: 12,
parent: 11
parent: 11,
reportLeafIndex: undefined,
}
],
id: 11
id: 11,
reportLeafIndex: undefined,
};
compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { filter: "objects" });

Просмотреть файл

@ -31,6 +31,7 @@ support-files =
[test_census-tree-node-07.js]
[test_census-tree-node-08.js]
[test_census-tree-node-09.js]
[test_census-tree-node-10.js]
[test_countToBucketBreakdown_01.js]
[test_deduplicatePaths_01.js]
[test_DominatorTree_01.js]