Bug 1246017 - Create the parent map in the HeapAnalysesWorker; r=jimb

This commit is contained in:
Nick Fitzgerald 2016-02-04 18:05:00 +01:00
Родитель f96d54f1b4
Коммит 34215b63aa
20 изменённых файлов: 90 добавлений и 66 удалений

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

@ -50,7 +50,7 @@ const takeCensusDiff = exports.takeCensusDiff = function (heapWorker, first, sec
assert(snapshotIsDiffable(second), assert(snapshotIsDiffable(second),
`Second snapshot must be in a diffable state, found ${second.state}`); `Second snapshot must be in a diffable state, found ${second.state}`);
let report; let report, parentMap;
let inverted = getState().inverted; let inverted = getState().inverted;
let breakdown = getState().breakdown; let breakdown = getState().breakdown;
let filter = getState().filter; let filter = getState().filter;

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

@ -136,7 +136,7 @@ const takeCensus = exports.takeCensus = function (heapWorker, id) {
assert([states.READ, states.SAVED_CENSUS].includes(snapshot.state), assert([states.READ, states.SAVED_CENSUS].includes(snapshot.state),
`Can only take census of snapshots in READ or SAVED_CENSUS state, found ${snapshot.state}`); `Can only take census of snapshots in READ or SAVED_CENSUS state, found ${snapshot.state}`);
let report; let report, parentMap;
let inverted = getState().inverted; let inverted = getState().inverted;
let breakdown = getState().breakdown; let breakdown = getState().breakdown;
let filter = getState().filter; let filter = getState().filter;

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

@ -32,7 +32,7 @@ const Census = module.exports = createClass({
} = this.props; } = this.props;
const report = census.report; const report = census.report;
let parentMap = createParentMap(report); let parentMap = census.parentMap;
const { totalBytes, totalCount } = report; const { totalBytes, totalCount } = report;
const getPercentBytes = totalBytes === 0 const getPercentBytes = totalBytes === 0

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

@ -4,9 +4,10 @@
const { DOM: dom, createClass, PropTypes, createFactory } = require("devtools/client/shared/vendor/react"); const { DOM: dom, createClass, PropTypes, createFactory } = require("devtools/client/shared/vendor/react");
const { assert, safeErrorString } = require("devtools/shared/DevToolsUtils"); const { assert, safeErrorString } = require("devtools/shared/DevToolsUtils");
const { createParentMap } = require("devtools/shared/heapsnapshot/CensusUtils");
const Tree = createFactory(require("devtools/client/shared/components/tree")); const Tree = createFactory(require("devtools/client/shared/components/tree"));
const DominatorTreeItem = createFactory(require("./dominator-tree-item")); const DominatorTreeItem = createFactory(require("./dominator-tree-item"));
const { createParentMap, L10N } = require("../utils"); const { L10N } = require("../utils");
const { TREE_ROW_HEIGHT, dominatorTreeState } = require("../constants"); const { TREE_ROW_HEIGHT, dominatorTreeState } = require("../constants");
const { dominatorTreeModel } = require("../models"); const { dominatorTreeModel } = require("../models");
const DominatorTreeLazyChildren = require("../dominator-tree-lazy-children"); const DominatorTreeLazyChildren = require("../dominator-tree-lazy-children");

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

@ -56,6 +56,8 @@ let breakdownModel = exports.breakdown = PropTypes.shape({
let censusModel = exports.censusModel = PropTypes.shape({ let censusModel = exports.censusModel = PropTypes.shape({
// The current census report data. // The current census report data.
report: PropTypes.object, report: PropTypes.object,
// The parent map for the report.
parentMap: PropTypes.object,
// The breakdown used to generate the current census // The breakdown used to generate the current census
breakdown: breakdownModel, breakdown: breakdownModel,
// Whether the currently cached report tree is inverted or not. // Whether the currently cached report tree is inverted or not.

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

@ -81,6 +81,7 @@ handlers[actions.TAKE_CENSUS_DIFF_END] = function (diffing, action) {
state: diffingState.TOOK_DIFF, state: diffingState.TOOK_DIFF,
census: { census: {
report: action.report, report: action.report,
parentMap: action.parentMap,
expanded: new Set(), expanded: new Set(),
inverted: action.inverted, inverted: action.inverted,
filter: action.filter, filter: action.filter,

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

@ -67,9 +67,15 @@ handlers[actions.TAKE_CENSUS_START] = function (snapshots, { id, breakdown, inve
}); });
}; };
handlers[actions.TAKE_CENSUS_END] = function (snapshots, { id, report, breakdown, inverted, filter }) { handlers[actions.TAKE_CENSUS_END] = function (snapshots, { id,
report,
parentMap,
breakdown,
inverted,
filter }) {
const census = { const census = {
report, report,
parentMap,
expanded: new Set(), expanded: new Set(),
breakdown, breakdown,
inverted, inverted,

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

@ -16,7 +16,8 @@ module.exports = function () {
// we'll later attach to the store // we'll later attach to the store
if (DevToolsUtils.testing) { if (DevToolsUtils.testing) {
history = []; history = [];
shouldLog = true; // Uncomment this for TONS of logging in tests.
// shouldLog = true;
} }
let store = createStore({ let store = createStore({

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

@ -561,25 +561,3 @@ exports.formatPercent = function(percent, showSign = false) {
return exports.L10N.getFormatStr("tree-item.percent", return exports.L10N.getFormatStr("tree-item.percent",
exports.formatNumber(percent, showSign)); exports.formatNumber(percent, showSign));
}; };
/**
* Creates a hash map mapping node IDs to its parent node.
*
* @param {CensusTreeNode} node
* @param {Object<number, TreeNode>} aggregator
*
* @return {Object<number, TreeNode>}
*/
const createParentMap = exports.createParentMap = function (node,
getId = node => node.id,
aggregator = Object.create(null)) {
if (node.children) {
for (let i = 0, length = node.children.length; i < length; i++) {
const child = node.children[i];
aggregator[getId(child)] = node;
createParentMap(child, getId, aggregator);
}
}
return aggregator;
};

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

@ -360,3 +360,25 @@ function diff(breakdown, startCensus, endCensus) {
return visitor.results(); return visitor.results();
}; };
exports.diff = diff exports.diff = diff
/**
* Creates a hash map mapping node IDs to its parent node.
*
* @param {CensusTreeNode} node
* @param {Object<number, TreeNode>} aggregator
*
* @return {Object<number, TreeNode>}
*/
const createParentMap = exports.createParentMap = function (node,
getId = node => node.id,
aggregator = Object.create(null)) {
if (node.children) {
for (let i = 0, length = node.children.length; i < length; i++) {
const child = node.children[i];
aggregator[getId(child)] = getId(node);
createParentMap(child, getId, aggregator);
}
}
return aggregator;
};

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

@ -21,7 +21,7 @@ var workerCounter = 0;
const HeapAnalysesClient = module.exports = function () { const HeapAnalysesClient = module.exports = function () {
this._worker = new DevToolsWorker(WORKER_URL, { this._worker = new DevToolsWorker(WORKER_URL, {
name: `HeapAnalyses-${workerCounter++}`, name: `HeapAnalyses-${workerCounter++}`,
verbose: DevToolsUtils.dumpn.wantLogging verbose: DevToolsUtils.dumpv.wantLogging
}); });
}; };
@ -104,10 +104,15 @@ HeapAnalysesClient.prototype.getCreationTime = function (snapshotFilePath) {
* A filter string to prune the resulting tree with. Only applies if * A filter string to prune the resulting tree with. Only applies if
* either asTreeNode or asInvertedTreeNode is true. * either asTreeNode or asInvertedTreeNode is true.
* *
* @returns Promise<census report|CensusTreeNode> * @returns Promise<Object>
* The report generated by the given census breakdown, or * An object with the following properties:
* a CensusTreeNode generated by the given census breakdown * - report:
* if `asTreeNode` is true. * The report generated by the given census breakdown, or a
* CensusTreeNode generated by the given census breakdown if
* `asTreeNode` is true.
* - parentMap:
* The result of calling CensusUtils.createParentMap on the generated
* report. Only exists if asTreeNode or asInvertedTreeNode are set.
*/ */
HeapAnalysesClient.prototype.takeCensus = function (snapshotFilePath, HeapAnalysesClient.prototype.takeCensus = function (snapshotFilePath,
censusOptions, censusOptions,
@ -147,10 +152,14 @@ HeapAnalysesClient.prototype.takeCensus = function (snapshotFilePath,
* A filter string to prune the resulting tree with. Only applies if * A filter string to prune the resulting tree with. Only applies if
* either asTreeNode or asInvertedTreeNode is true. * either asTreeNode or asInvertedTreeNode is true.
* *
* @returns Promise<delta report|CensusTreeNode> * @returns Promise<Object>
* - delta:
* The delta report generated by diffing the two census reports, or a * The delta report generated by diffing the two census reports, or a
* CensusTreeNode generated from the delta report if * CensusTreeNode generated from the delta report if
* `requestOptions.asTreeNode` was true. * `requestOptions.asTreeNode` was true.
* - parentMap:
* The result of calling CensusUtils.createParentMap on the generated
* delta. Only exists if asTreeNode or asInvertedTreeNode are set.
*/ */
HeapAnalysesClient.prototype.takeCensusDiff = function (firstSnapshotFilePath, HeapAnalysesClient.prototype.takeCensusDiff = function (firstSnapshotFilePath,
secondSnapshotFilePath, secondSnapshotFilePath,

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

@ -58,17 +58,19 @@ workerHelper.createTask(self, "takeCensus", ({ snapshotFilePath, censusOptions,
throw new Error(`No known heap snapshot for '${snapshotFilePath}'`); throw new Error(`No known heap snapshot for '${snapshotFilePath}'`);
} }
const report = snapshots[snapshotFilePath].takeCensus(censusOptions); let report = snapshots[snapshotFilePath].takeCensus(censusOptions);
let parentMap;
if (requestOptions.asTreeNode || requestOptions.asInvertedTreeNode) { if (requestOptions.asTreeNode || requestOptions.asInvertedTreeNode) {
const opts = { filter: requestOptions.filter || null }; const opts = { filter: requestOptions.filter || null };
if (requestOptions.asInvertedTreeNode) { if (requestOptions.asInvertedTreeNode) {
opts.invert = true; opts.invert = true;
} }
return censusReportToCensusTreeNode(censusOptions.breakdown, report, opts); report = censusReportToCensusTreeNode(censusOptions.breakdown, report, opts);
parentMap = CensusUtils.createParentMap(report);
} }
return report; return { report, parentMap };
}); });
/** /**
@ -92,17 +94,19 @@ workerHelper.createTask(self, "takeCensusDiff", request => {
const first = snapshots[firstSnapshotFilePath].takeCensus(censusOptions); const first = snapshots[firstSnapshotFilePath].takeCensus(censusOptions);
const second = snapshots[secondSnapshotFilePath].takeCensus(censusOptions); const second = snapshots[secondSnapshotFilePath].takeCensus(censusOptions);
const delta = CensusUtils.diff(censusOptions.breakdown, first, second); let delta = CensusUtils.diff(censusOptions.breakdown, first, second);
let parentMap;
if (requestOptions.asTreeNode || requestOptions.asInvertedTreeNode) { if (requestOptions.asTreeNode || requestOptions.asInvertedTreeNode) {
const opts = { filter: requestOptions.filter || null }; const opts = { filter: requestOptions.filter || null };
if (requestOptions.asInvertedTreeNode) { if (requestOptions.asInvertedTreeNode) {
opts.invert = true; opts.invert = true;
} }
return censusReportToCensusTreeNode(censusOptions.breakdown, delta, opts); delta = censusReportToCensusTreeNode(censusOptions.breakdown, delta, opts);
parentMap = CensusUtils.createParentMap(delta);
} }
return delta; return { delta, parentMap };
}); });
/** /**

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

@ -30,14 +30,14 @@ add_task(function* () {
yield client.readHeapSnapshot(secondSnapshotFilePath); yield client.readHeapSnapshot(secondSnapshotFilePath);
ok(true, "Should have read both heap snapshot files"); ok(true, "Should have read both heap snapshot files");
const delta = yield client.takeCensusDiff(firstSnapshotFilePath, const { delta } = yield client.takeCensusDiff(firstSnapshotFilePath,
secondSnapshotFilePath, secondSnapshotFilePath,
{ breakdown: BREAKDOWN }); { breakdown: BREAKDOWN });
equal(delta.AllocationMarker.count, 1, equal(delta.AllocationMarker.count, 1,
"There exists one new AllocationMarker in the second heap snapshot"); "There exists one new AllocationMarker in the second heap snapshot");
const deltaTreeNode = yield client.takeCensusDiff(firstSnapshotFilePath, const { delta: deltaTreeNode } = yield client.takeCensusDiff(firstSnapshotFilePath,
secondSnapshotFilePath, secondSnapshotFilePath,
{ breakdown: BREAKDOWN }, { breakdown: BREAKDOWN },
{ asTreeNode: true }); { asTreeNode: true });

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

@ -39,11 +39,11 @@ add_task(function* () {
ok(true, "Should have read both heap snapshot files"); ok(true, "Should have read both heap snapshot files");
const delta = yield client.takeCensusDiff(firstSnapshotFilePath, const { delta } = yield client.takeCensusDiff(firstSnapshotFilePath,
secondSnapshotFilePath, secondSnapshotFilePath,
{ breakdown: BREAKDOWN }); { breakdown: BREAKDOWN });
const deltaTreeNode = yield client.takeCensusDiff(firstSnapshotFilePath, const { delta: deltaTreeNode } = yield client.takeCensusDiff(firstSnapshotFilePath,
secondSnapshotFilePath, secondSnapshotFilePath,
{ breakdown: BREAKDOWN }, { breakdown: BREAKDOWN },
{ asInvertedTreeNode: true }); { asInvertedTreeNode: true });

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

@ -14,7 +14,7 @@ add_task(function* () {
yield client.readHeapSnapshot(snapshotFilePath); yield client.readHeapSnapshot(snapshotFilePath);
ok(true, "Should have read the heap snapshot"); ok(true, "Should have read the heap snapshot");
const report = yield client.takeCensus(snapshotFilePath); const { report } = yield client.takeCensus(snapshotFilePath);
ok(report, "Should get a report"); ok(report, "Should get a report");
equal(typeof report, "object", "report should be an object"); equal(typeof report, "object", "report should be an object");

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

@ -15,7 +15,7 @@ add_task(function* () {
yield client.readHeapSnapshot(snapshotFilePath); yield client.readHeapSnapshot(snapshotFilePath);
ok(true, "Should have read the heap snapshot"); ok(true, "Should have read the heap snapshot");
const report = yield client.takeCensus(snapshotFilePath, { const { report } = yield client.takeCensus(snapshotFilePath, {
breakdown: { by: "count", count: true, bytes: true } breakdown: { by: "count", count: true, bytes: true }
}); });

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

@ -49,7 +49,7 @@ add_task(function* test() {
// Run a census broken down by class name -> allocation stack so we can grab // Run a census broken down by class name -> allocation stack so we can grab
// only the AllocationMarker objects we have complete control over. // only the AllocationMarker objects we have complete control over.
const report = yield client.takeCensus(snapshotFilePath, { const { report } = yield client.takeCensus(snapshotFilePath, {
breakdown: { by: 'objectClass', breakdown: { by: 'objectClass',
then: { by: 'allocationStack', then: { by: 'allocationStack',
then: { by: 'count', then: { by: 'count',

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

@ -20,11 +20,11 @@ add_task(function* () {
yield client.readHeapSnapshot(snapshotFilePath); yield client.readHeapSnapshot(snapshotFilePath);
ok(true, "Should have read the heap snapshot"); ok(true, "Should have read the heap snapshot");
const report = yield client.takeCensus(snapshotFilePath, { const { report } = yield client.takeCensus(snapshotFilePath, {
breakdown: BREAKDOWN breakdown: BREAKDOWN
}); });
const treeNode = yield client.takeCensus(snapshotFilePath, { const { report: treeNode } = yield client.takeCensus(snapshotFilePath, {
breakdown: BREAKDOWN breakdown: BREAKDOWN
}, { }, {
asTreeNode: true asTreeNode: true

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

@ -59,11 +59,11 @@ add_task(function* () {
yield client.readHeapSnapshot(snapshotFilePath); yield client.readHeapSnapshot(snapshotFilePath);
ok(true, "Should have read the heap snapshot"); ok(true, "Should have read the heap snapshot");
const report = yield client.takeCensus(snapshotFilePath, { const { report } = yield client.takeCensus(snapshotFilePath, {
breakdown: BREAKDOWN breakdown: BREAKDOWN
}); });
const treeNode = yield client.takeCensus(snapshotFilePath, { const { report: treeNode } = yield client.takeCensus(snapshotFilePath, {
breakdown: BREAKDOWN breakdown: BREAKDOWN
}, { }, {
asTreeNode: true asTreeNode: true

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

@ -36,11 +36,11 @@ add_task(function* () {
yield client.readHeapSnapshot(snapshotFilePath); yield client.readHeapSnapshot(snapshotFilePath);
ok(true, "Should have read the heap snapshot"); ok(true, "Should have read the heap snapshot");
const report = yield client.takeCensus(snapshotFilePath, { const { report } = yield client.takeCensus(snapshotFilePath, {
breakdown: BREAKDOWN breakdown: BREAKDOWN
}); });
const treeNode = yield client.takeCensus(snapshotFilePath, { const { report: treeNode } = yield client.takeCensus(snapshotFilePath, {
breakdown: BREAKDOWN breakdown: BREAKDOWN
}, { }, {
asInvertedTreeNode: true asInvertedTreeNode: true