2015-09-04 03:29:40 +03:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
2015-09-21 20:04:18 +03:00
|
|
|
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
2015-10-07 23:40:24 +03:00
|
|
|
const { DevToolsWorker } = require("devtools/shared/worker/worker");
|
2015-09-04 03:29:40 +03:00
|
|
|
|
2015-09-21 20:04:18 +03:00
|
|
|
const WORKER_URL =
|
2015-10-14 02:18:43 +03:00
|
|
|
"resource://devtools/shared/heapsnapshot/HeapAnalysesWorker.js";
|
2015-09-15 21:19:45 +03:00
|
|
|
var workerCounter = 0;
|
2015-09-04 03:29:40 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A HeapAnalysesClient instance provides a developer-friendly interface for
|
|
|
|
* interacting with a HeapAnalysesWorker. This enables users to be ignorant of
|
|
|
|
* the message passing protocol used to communicate with the worker. The
|
|
|
|
* HeapAnalysesClient owns the worker, and terminating the worker is done by
|
|
|
|
* terminating the client (see the `destroy` method).
|
|
|
|
*/
|
2018-03-12 21:24:38 +03:00
|
|
|
const HeapAnalysesClient = (module.exports = function() {
|
2015-09-04 03:29:40 +03:00
|
|
|
this._worker = new DevToolsWorker(WORKER_URL, {
|
|
|
|
name: `HeapAnalyses-${workerCounter++}`,
|
2016-02-10 19:57:37 +03:00
|
|
|
verbose: DevToolsUtils.dumpv.wantVerbose,
|
2015-09-04 03:29:40 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destroy the worker, causing it to release its resources (such as heap
|
|
|
|
* snapshots it has deserialized and read into memory). The client is no longer
|
|
|
|
* usable after calling this method.
|
|
|
|
*/
|
2018-03-12 21:24:38 +03:00
|
|
|
HeapAnalysesClient.prototype.destroy = function() {
|
2015-09-04 03:29:40 +03:00
|
|
|
this._worker.destroy();
|
2016-02-04 13:53:00 +03:00
|
|
|
this._worker = null;
|
2015-09-04 03:29:40 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tell the worker to read into memory the heap snapshot at the given file
|
|
|
|
* path. This is a prerequisite for asking the worker to perform various
|
|
|
|
* analyses on a heap snapshot.
|
|
|
|
*
|
|
|
|
* @param {String} snapshotFilePath
|
|
|
|
*
|
|
|
|
* @returns Promise
|
|
|
|
* The promise is fulfilled if the heap snapshot is successfully
|
|
|
|
* deserialized and read into memory. The promise is rejected if that
|
|
|
|
* does not happen, eg due to a bad file path or malformed heap
|
|
|
|
* snapshot file.
|
|
|
|
*/
|
2018-03-12 21:24:38 +03:00
|
|
|
HeapAnalysesClient.prototype.readHeapSnapshot = function(snapshotFilePath) {
|
2015-09-04 03:29:40 +03:00
|
|
|
return this._worker.performTask("readHeapSnapshot", { snapshotFilePath });
|
|
|
|
};
|
|
|
|
|
2016-01-12 12:41:17 +03:00
|
|
|
/**
|
|
|
|
* Tell the worker to delete all references to the snapshot and dominator trees
|
|
|
|
* linked to the provided snapshot file path.
|
|
|
|
*
|
|
|
|
* @param {String} snapshotFilePath
|
|
|
|
* @return Promise<undefined>
|
|
|
|
*/
|
2018-03-12 21:24:38 +03:00
|
|
|
HeapAnalysesClient.prototype.deleteHeapSnapshot = function(snapshotFilePath) {
|
2016-01-12 12:41:17 +03:00
|
|
|
return this._worker.performTask("deleteHeapSnapshot", { snapshotFilePath });
|
|
|
|
};
|
|
|
|
|
2015-12-03 20:15:13 +03:00
|
|
|
/**
|
|
|
|
* Request the creation time given a snapshot file path. Returns `null`
|
|
|
|
* if snapshot does not exist.
|
|
|
|
*
|
|
|
|
* @param {String} snapshotFilePath
|
|
|
|
* The path to the snapshot.
|
|
|
|
* @return {Number?}
|
|
|
|
* The unix timestamp of the creation time of the snapshot, or null if
|
|
|
|
* snapshot does not exist.
|
|
|
|
*/
|
2018-03-12 21:24:38 +03:00
|
|
|
HeapAnalysesClient.prototype.getCreationTime = function(snapshotFilePath) {
|
2015-12-03 20:15:13 +03:00
|
|
|
return this._worker.performTask("getCreationTime", snapshotFilePath);
|
|
|
|
};
|
|
|
|
|
2016-05-17 21:25:54 +03:00
|
|
|
/** * Censuses *****************************************************************/
|
2015-12-03 20:15:13 +03:00
|
|
|
|
2015-09-04 03:29:40 +03:00
|
|
|
/**
|
|
|
|
* Ask the worker to perform a census analysis on the heap snapshot with the
|
|
|
|
* given path. The heap snapshot at the given path must have already been read
|
|
|
|
* into memory by the worker (see `readHeapSnapshot`).
|
|
|
|
*
|
|
|
|
* @param {String} snapshotFilePath
|
|
|
|
*
|
|
|
|
* @param {Object} censusOptions
|
|
|
|
* A structured-cloneable object specifying the requested census's
|
|
|
|
* breakdown. See the "takeCensus" section of
|
|
|
|
* `js/src/doc/Debugger/Debugger.Memory.md` for detailed documentation.
|
|
|
|
*
|
2015-10-14 00:30:40 +03:00
|
|
|
* @param {Object} requestOptions
|
|
|
|
* An object specifying options of this worker request.
|
|
|
|
* - {Boolean} asTreeNode
|
|
|
|
* Whether or not the census is returned as a CensusTreeNode,
|
|
|
|
* or just a breakdown report. Defaults to false.
|
|
|
|
* @see `devtools/shared/heapsnapshot/census-tree-node.js`
|
2015-10-22 23:43:30 +03:00
|
|
|
* - {Boolean} asInvertedTreeNode
|
|
|
|
* Whether or not the census is returned as an inverted
|
|
|
|
* CensusTreeNode. Defaults to false.
|
2015-11-05 03:12:31 +03:00
|
|
|
* - {String} filter
|
|
|
|
* A filter string to prune the resulting tree with. Only applies if
|
|
|
|
* either asTreeNode or asInvertedTreeNode is true.
|
2015-10-14 00:30:40 +03:00
|
|
|
*
|
2016-02-06 02:11:48 +03:00
|
|
|
* @returns Promise<Object>
|
|
|
|
* An object with the following properties:
|
|
|
|
* - report:
|
|
|
|
* 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.
|
2015-09-04 03:29:40 +03:00
|
|
|
*/
|
2018-03-12 21:24:38 +03:00
|
|
|
HeapAnalysesClient.prototype.takeCensus = function(
|
|
|
|
snapshotFilePath,
|
2015-10-15 09:23:00 +03:00
|
|
|
censusOptions,
|
2016-05-17 21:25:54 +03:00
|
|
|
requestOptions = {}
|
|
|
|
) {
|
2015-09-04 03:29:40 +03:00
|
|
|
return this._worker.performTask("takeCensus", {
|
|
|
|
snapshotFilePath,
|
2015-10-14 00:30:40 +03:00
|
|
|
censusOptions,
|
|
|
|
requestOptions,
|
2015-09-04 03:29:40 +03:00
|
|
|
});
|
|
|
|
};
|
2015-10-15 09:23:00 +03:00
|
|
|
|
2016-04-01 02:19:59 +03:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
2018-03-12 21:24:38 +03:00
|
|
|
HeapAnalysesClient.prototype.getCensusIndividuals = function(opts) {
|
2016-04-01 02:19:59 +03:00
|
|
|
return this._worker.performTask("getCensusIndividuals", opts);
|
|
|
|
};
|
|
|
|
|
2015-10-15 09:23:00 +03:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
* have already been read into memory by the worker (see `readHeapSnapshot`).
|
|
|
|
*
|
|
|
|
* @param {String} firstSnapshotFilePath
|
|
|
|
* The first snapshot file path.
|
|
|
|
*
|
|
|
|
* @param {String} secondSnapshotFilePath
|
|
|
|
* The second snapshot file path.
|
|
|
|
*
|
|
|
|
* @param {Object} censusOptions
|
|
|
|
* A structured-cloneable object specifying the requested census's
|
|
|
|
* breakdown. See the "takeCensus" section of
|
|
|
|
* `js/src/doc/Debugger/Debugger.Memory.md` for detailed documentation.
|
|
|
|
*
|
|
|
|
* @param {Object} requestOptions
|
|
|
|
* An object specifying options for this request.
|
|
|
|
* - {Boolean} asTreeNode
|
|
|
|
* Whether the resulting delta report should be converted to a census
|
|
|
|
* tree node before returned. Defaults to false.
|
2015-10-22 23:43:30 +03:00
|
|
|
* - {Boolean} asInvertedTreeNode
|
|
|
|
* Whether or not the census is returned as an inverted
|
|
|
|
* CensusTreeNode. Defaults to false.
|
2015-11-13 22:20:45 +03:00
|
|
|
* - {String} filter
|
|
|
|
* A filter string to prune the resulting tree with. Only applies if
|
|
|
|
* either asTreeNode or asInvertedTreeNode is true.
|
2015-10-15 09:23:00 +03:00
|
|
|
*
|
2016-02-06 02:11:48 +03:00
|
|
|
* @returns Promise<Object>
|
|
|
|
* - delta:
|
|
|
|
* The delta report generated by diffing the two census reports, or a
|
|
|
|
* CensusTreeNode generated from the delta report if
|
|
|
|
* `requestOptions.asTreeNode` was true.
|
|
|
|
* - parentMap:
|
|
|
|
* The result of calling CensusUtils.createParentMap on the generated
|
|
|
|
* delta. Only exists if asTreeNode or asInvertedTreeNode are set.
|
2015-10-15 09:23:00 +03:00
|
|
|
*/
|
2018-03-12 21:24:38 +03:00
|
|
|
HeapAnalysesClient.prototype.takeCensusDiff = function(
|
|
|
|
firstSnapshotFilePath,
|
2015-10-15 09:23:00 +03:00
|
|
|
secondSnapshotFilePath,
|
|
|
|
censusOptions,
|
|
|
|
requestOptions = {}
|
|
|
|
) {
|
|
|
|
return this._worker.performTask("takeCensusDiff", {
|
|
|
|
firstSnapshotFilePath,
|
|
|
|
secondSnapshotFilePath,
|
|
|
|
censusOptions,
|
|
|
|
requestOptions,
|
|
|
|
});
|
2015-10-29 07:27:46 +03:00
|
|
|
};
|
|
|
|
|
2016-05-17 21:25:54 +03:00
|
|
|
/** * Dominator Trees **********************************************************/
|
2015-12-03 20:15:13 +03:00
|
|
|
|
2015-10-29 07:27:46 +03:00
|
|
|
/**
|
2015-12-03 20:15:13 +03:00
|
|
|
* Compute the dominator tree of the heap snapshot loaded from the given file
|
|
|
|
* path. Returns the id of the computed dominator tree.
|
2015-10-29 07:27:46 +03:00
|
|
|
*
|
|
|
|
* @param {String} snapshotFilePath
|
2015-12-03 20:15:13 +03:00
|
|
|
*
|
|
|
|
* @returns {Promise<DominatorTreeId>}
|
2015-10-29 07:27:46 +03:00
|
|
|
*/
|
2018-03-12 21:24:38 +03:00
|
|
|
HeapAnalysesClient.prototype.computeDominatorTree = function(snapshotFilePath) {
|
2015-12-03 20:15:13 +03:00
|
|
|
return this._worker.performTask("computeDominatorTree", snapshotFilePath);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the initial, partial view of the dominator tree with the given id.
|
|
|
|
*
|
|
|
|
* @param {Object} opts
|
|
|
|
* An object specifying options for this request.
|
|
|
|
* - {DominatorTreeId} dominatorTreeId
|
|
|
|
* The id of the dominator tree.
|
2015-12-18 23:05:14 +03:00
|
|
|
* - {Object} breakdown
|
|
|
|
* The breakdown used to generate node labels.
|
2015-12-03 20:15:13 +03:00
|
|
|
* - {Number} maxDepth
|
|
|
|
* The maximum depth to traverse down the tree to create this initial
|
|
|
|
* view.
|
|
|
|
* - {Number} maxSiblings
|
|
|
|
* The maximum number of siblings to visit within each traversed node's
|
|
|
|
* children.
|
2016-04-12 04:04:31 +03:00
|
|
|
* - {Number} maxRetainingPaths
|
|
|
|
* The maximum number of retaining paths to find for each node.
|
2015-12-03 20:15:13 +03:00
|
|
|
*
|
|
|
|
* @returns {Promise<DominatorTreeNode>}
|
|
|
|
*/
|
2018-03-12 21:24:38 +03:00
|
|
|
HeapAnalysesClient.prototype.getDominatorTree = function(opts) {
|
2015-12-03 20:15:13 +03:00
|
|
|
return this._worker.performTask("getDominatorTree", opts);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a subset of a nodes children in the dominator tree.
|
|
|
|
*
|
|
|
|
* @param {Object} opts
|
|
|
|
* An object specifying options for this request.
|
|
|
|
* - {DominatorTreeId} dominatorTreeId
|
|
|
|
* The id of the dominator tree.
|
|
|
|
* - {NodeId} nodeId
|
|
|
|
* The id of the node whose children are being found.
|
2015-12-18 23:05:14 +03:00
|
|
|
* - {Object} breakdown
|
|
|
|
* The breakdown used to generate node labels.
|
2015-12-03 20:15:13 +03:00
|
|
|
* - {Number} startIndex
|
|
|
|
* The starting index within the full set of immediately dominated
|
|
|
|
* children of the children being requested. Children are always sorted
|
|
|
|
* by greatest to least retained size.
|
|
|
|
* - {Number} maxCount
|
|
|
|
* The maximum number of children to return.
|
2016-02-12 17:23:00 +03:00
|
|
|
* - {Number} maxRetainingPaths
|
|
|
|
* The maximum number of retaining paths to find for each node.
|
2015-12-03 20:15:13 +03:00
|
|
|
*
|
|
|
|
* @returns {Promise<Object>}
|
|
|
|
* A promise of an object with the following properties:
|
|
|
|
* - {Array<DominatorTreeNode>} nodes
|
|
|
|
* The requested nodes that are immediately dominated by the node
|
|
|
|
* identified by `opts.nodeId`.
|
|
|
|
* - {Boolean} moreChildrenAvailable
|
|
|
|
* True iff there are more children available after the returned
|
|
|
|
* nodes.
|
2016-01-07 00:57:12 +03:00
|
|
|
* - {Array<NodeId>} path
|
|
|
|
* The path through the tree from the root to these node's parent, eg
|
|
|
|
* [root's id, child of root's id, child of child of root's id, ..., `nodeId`].
|
2015-12-03 20:15:13 +03:00
|
|
|
*/
|
2018-03-12 21:24:38 +03:00
|
|
|
HeapAnalysesClient.prototype.getImmediatelyDominated = function(opts) {
|
2015-12-03 20:15:13 +03:00
|
|
|
return this._worker.performTask("getImmediatelyDominated", opts);
|
2015-10-29 07:27:46 +03:00
|
|
|
};
|