зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1246017 - Create the parent map in the HeapAnalysesWorker; r=jimb
This commit is contained in:
Родитель
f96d54f1b4
Коммит
34215b63aa
|
@ -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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче