зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1260939 - Add a method for getting census individuals and their shortest paths to HeapAnalyses{Client,Worker}; r=jimb a=kwierso
MozReview-Commit-ID: HHJ2masZB4k --HG-- extra : histedit_source : bbc90e79f8ddc76b79faec7ce027b549aaaead45
This commit is contained in:
Родитель
81e06bd5ae
Коммит
1a331c72d1
|
@ -124,6 +124,35 @@ HeapAnalysesClient.prototype.takeCensus = function (snapshotFilePath,
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the individual nodes that correspond to the given census report leaf
|
||||
* indices.
|
||||
*
|
||||
* @param {Object} opts
|
||||
* An object with the following properties:
|
||||
* - {DominatorTreeId} dominatorTreeId: The id of the dominator tree.
|
||||
* - {Set<Number>} indices: The indices of the census report leaves we
|
||||
* would like to get the individuals for.
|
||||
* - {Object} censusBreakdown: The breakdown used to generate the census.
|
||||
* - {Object} labelBreakdown: The breakdown we would like to use when
|
||||
* labeling the resulting nodes.
|
||||
* - {Number} maxRetainingPaths: The maximum number of retaining paths to
|
||||
* compute for each node.
|
||||
* - {Number} maxIndividuals: The maximum number of individual nodes to
|
||||
* return.
|
||||
*
|
||||
* @returns {Promise<Object>}
|
||||
* A promise of an object with the following properties:
|
||||
* - {Array<DominatorTreeNode>} nodes: An array of `DominatorTreeNode`s
|
||||
* with their shortest paths attached, and without any dominator tree
|
||||
* child/parent information attached. The results are sorted by
|
||||
* retained size.
|
||||
*
|
||||
*/
|
||||
HeapAnalysesClient.prototype.getCensusIndividuals = function(opts) {
|
||||
return this._worker.performTask("getCensusIndividuals", opts);
|
||||
};
|
||||
|
||||
/**
|
||||
* Request that the worker take a census on the heap snapshots with the given
|
||||
* paths and then return the difference between them. Both heap snapshots must
|
||||
|
|
|
@ -19,10 +19,27 @@ const CensusUtils = require("resource://devtools/shared/heapsnapshot/CensusUtils
|
|||
const DEFAULT_START_INDEX = 0;
|
||||
const DEFAULT_MAX_COUNT = 50;
|
||||
|
||||
// The set of HeapSnapshot instances this worker has read into memory. Keyed by
|
||||
// snapshot file path.
|
||||
/**
|
||||
* The set of HeapSnapshot instances this worker has read into memory. Keyed by
|
||||
* snapshot file path.
|
||||
*/
|
||||
const snapshots = Object.create(null);
|
||||
|
||||
/**
|
||||
* The set of `DominatorTree`s that have been computed, mapped by their id (aka
|
||||
* the index into this array).
|
||||
*
|
||||
* @see /dom/webidl/DominatorTree.webidl
|
||||
*/
|
||||
const dominatorTrees = [];
|
||||
|
||||
/**
|
||||
* The i^th HeapSnapshot in this array is the snapshot used to generate the i^th
|
||||
* dominator tree in `dominatorTrees` above. This lets us map from a dominator
|
||||
* tree id to the snapshot it came from.
|
||||
*/
|
||||
const dominatorTreeSnapshots = [];
|
||||
|
||||
/**
|
||||
* @see HeapAnalysesClient.prototype.readHeapSnapshot
|
||||
*/
|
||||
|
@ -73,6 +90,49 @@ workerHelper.createTask(self, "takeCensus", ({ snapshotFilePath, censusOptions,
|
|||
return { report, parentMap };
|
||||
});
|
||||
|
||||
/**
|
||||
* @see HeapAnalysesClient.prototype.getCensusIndividuals
|
||||
*/
|
||||
workerHelper.createTask(self, "getCensusIndividuals", request => {
|
||||
const {
|
||||
dominatorTreeId,
|
||||
indices,
|
||||
censusBreakdown,
|
||||
labelBreakdown,
|
||||
maxRetainingPaths,
|
||||
maxIndividuals,
|
||||
} = request;
|
||||
|
||||
const dominatorTree = dominatorTrees[dominatorTreeId];
|
||||
if (!dominatorTree) {
|
||||
throw new Error(
|
||||
`There does not exist a DominatorTree with the id ${dominatorTreeId}`);
|
||||
}
|
||||
|
||||
const snapshot = dominatorTreeSnapshots[dominatorTreeId];
|
||||
const nodeIds = CensusUtils.getCensusIndividuals(indices, censusBreakdown, snapshot);
|
||||
|
||||
const nodes = nodeIds
|
||||
.sort((a, b) => dominatorTree.getRetainedSize(b) - dominatorTree.getRetainedSize(a))
|
||||
.slice(0, maxIndividuals)
|
||||
.map(id => {
|
||||
const { label, shallowSize } =
|
||||
DominatorTreeNode.getLabelAndShallowSize(id, snapshot, labelBreakdown);
|
||||
const retainedSize = dominatorTree.getRetainedSize(id);
|
||||
const node = new DominatorTreeNode(id, label, shallowSize, retainedSize);
|
||||
node.moreChildrenAvailable = false;
|
||||
return node;
|
||||
});
|
||||
|
||||
DominatorTreeNode.attachShortestPaths(snapshot,
|
||||
labelBreakdown,
|
||||
dominatorTree.root,
|
||||
nodes,
|
||||
maxRetainingPaths);
|
||||
|
||||
return { nodes };
|
||||
});
|
||||
|
||||
/**
|
||||
* @see HeapAnalysesClient.prototype.takeCensusDiff
|
||||
*/
|
||||
|
@ -119,21 +179,6 @@ workerHelper.createTask(self, "getCreationTime", snapshotFilePath => {
|
|||
return snapshots[snapshotFilePath].creationTime;
|
||||
});
|
||||
|
||||
/**
|
||||
* The set of `DominatorTree`s that have been computed, mapped by their id (aka
|
||||
* the index into this array).
|
||||
*
|
||||
* @see /dom/webidl/DominatorTree.webidl
|
||||
*/
|
||||
const dominatorTrees = [];
|
||||
|
||||
/**
|
||||
* The i^th HeapSnapshot in this array is the snapshot used to generate the i^th
|
||||
* dominator tree in `dominatorTrees` above. This lets us map from a dominator
|
||||
* tree id to the snapshot it came from.
|
||||
*/
|
||||
const dominatorTreeSnapshots = [];
|
||||
|
||||
/**
|
||||
* @see HeapAnalysesClient.prototype.computeDominatorTree
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that the HeapAnalyses{Client,Worker} can get census individuals.
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
const COUNT = { by: "count", count: true, bytes: true };
|
||||
|
||||
const CENSUS_BREAKDOWN = {
|
||||
by: "coarseType",
|
||||
objects: COUNT,
|
||||
strings: COUNT,
|
||||
scripts: COUNT,
|
||||
other: COUNT,
|
||||
};
|
||||
|
||||
const LABEL_BREAKDOWN = {
|
||||
by: "internalType",
|
||||
then: COUNT,
|
||||
};
|
||||
|
||||
const MAX_INDIVIDUALS = 10;
|
||||
|
||||
add_task(function* () {
|
||||
const client = new HeapAnalysesClient();
|
||||
|
||||
const snapshotFilePath = saveNewHeapSnapshot();
|
||||
yield client.readHeapSnapshot(snapshotFilePath);
|
||||
ok(true, "Should have read the heap snapshot");
|
||||
|
||||
const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath);
|
||||
ok(true, "Should have computed dominator tree");
|
||||
|
||||
const { report } = yield client.takeCensus(snapshotFilePath,
|
||||
{ breakdown: CENSUS_BREAKDOWN },
|
||||
{ asTreeNode: true });
|
||||
ok(report, "Should get a report");
|
||||
|
||||
let nodesWithLeafIndicesFound = 0;
|
||||
|
||||
yield* (function* assertCanGetIndividuals(censusNode) {
|
||||
if (censusNode.reportLeafIndex !== undefined) {
|
||||
nodesWithLeafIndicesFound++;
|
||||
|
||||
const response = yield client.getCensusIndividuals({
|
||||
dominatorTreeId,
|
||||
indices: DevToolsUtils.isSet(censusNode.reportLeafIndex)
|
||||
? censusNode.reportLeafIndex
|
||||
: new Set([censusNode.reportLeafIndex]),
|
||||
censusBreakdown: CENSUS_BREAKDOWN,
|
||||
labelBreakdown: LABEL_BREAKDOWN,
|
||||
maxRetainingPaths: 1,
|
||||
maxIndividuals: MAX_INDIVIDUALS,
|
||||
});
|
||||
|
||||
dumpn(`response = ${JSON.stringify(response, null, 4)}`);
|
||||
|
||||
equal(response.nodes.length, Math.min(MAX_INDIVIDUALS, censusNode.count),
|
||||
"response.nodes.length === Math.min(MAX_INDIVIDUALS, censusNode.count)");
|
||||
|
||||
let lastRetainedSize = Infinity;
|
||||
for (let individual of response.nodes) {
|
||||
equal(typeof individual.nodeId, "number",
|
||||
"individual.nodeId should be a number");
|
||||
ok(individual.retainedSize <= lastRetainedSize,
|
||||
"individual.retainedSize <= lastRetainedSize");
|
||||
lastRetainedSize = individual.retainedSize;
|
||||
ok(individual.shallowSize, "individual.shallowSize should exist and be non-zero");
|
||||
ok(individual.shortestPaths, "individual.shortestPaths should exist");
|
||||
ok(individual.shortestPaths.nodes, "individual.shortestPaths.nodes should exist");
|
||||
ok(individual.shortestPaths.edges, "individual.shortestPaths.edges should exist");
|
||||
ok(individual.label, "individual.label should exist");
|
||||
}
|
||||
}
|
||||
|
||||
if (censusNode.children) {
|
||||
for (let child of censusNode.children) {
|
||||
yield* assertCanGetIndividuals(child);
|
||||
}
|
||||
}
|
||||
}(report));
|
||||
|
||||
equal(nodesWithLeafIndicesFound, 4, "Should have found a leaf for each coarse type");
|
||||
|
||||
client.destroy();
|
||||
});
|
|
@ -57,6 +57,7 @@ support-files =
|
|||
[test_HeapAnalyses_deleteHeapSnapshot_01.js]
|
||||
[test_HeapAnalyses_deleteHeapSnapshot_02.js]
|
||||
[test_HeapAnalyses_deleteHeapSnapshot_03.js]
|
||||
[test_HeapAnalyses_getCensusIndividuals_01.js]
|
||||
[test_HeapAnalyses_getCreationTime_01.js]
|
||||
[test_HeapAnalyses_getDominatorTree_01.js]
|
||||
[test_HeapAnalyses_getDominatorTree_02.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче