Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(97)

Unified Diff: tools/profile.js

Issue 99181: Enhancing profiling data processing code with functionality needed for the Dev Tools Profiler. (Closed)
Patch Set: Created 11 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/profile.js
diff --git a/tools/profile.js b/tools/profile.js
index 70e30846da9ebef5dc135c234d8a9defee5fbadb..614c63557697b5a73858d38d0af8026e4e7b78ea 100644
--- a/tools/profile.js
+++ b/tools/profile.js
@@ -185,25 +185,7 @@ devtools.profiler.Profile.prototype.resolveAndFilterFuncs_ = function(stack) {
/**
- * Returns the root of the top down call graph.
- */
-devtools.profiler.Profile.prototype.getTopDownTreeRoot = function() {
- this.topDownTree_.computeTotalWeights();
- return this.topDownTree_.getRoot();
-};
-
-
-/**
- * Returns the root of the bottom up call graph.
- */
-devtools.profiler.Profile.prototype.getBottomUpTreeRoot = function() {
- this.bottomUpTree_.computeTotalWeights();
- return this.bottomUpTree_.getRoot();
-};
-
-
-/**
- * Traverses the top down call graph in preorder.
+ * Performs a BF traversal of the top down call graph.
*
* @param {function(devtools.profiler.CallTree.Node)} f Visitor function.
*/
@@ -213,7 +195,7 @@ devtools.profiler.Profile.prototype.traverseTopDownTree = function(f) {
/**
- * Traverses the bottom up call graph in preorder.
+ * Performs a BF traversal of the bottom up call graph.
*
* @param {function(devtools.profiler.CallTree.Node)} f Visitor function.
*/
@@ -223,60 +205,96 @@ devtools.profiler.Profile.prototype.traverseBottomUpTree = function(f) {
/**
- * Calculates a top down profile starting from the specified node.
+ * Calculates a top down profile for a node with the specified label.
+ * If no name specified, returns the whole top down calls tree.
*
- * @param {devtools.profiler.CallTree.Node} opt_root Starting node.
+ * @param {string} opt_label Node label.
*/
-devtools.profiler.Profile.prototype.getTopDownProfile = function(opt_root) {
- if (!opt_root) {
- this.topDownTree_.computeTotalWeights();
- return this.topDownTree_;
- } else {
- throw Error('not implemented');
- }
+devtools.profiler.Profile.prototype.getTopDownProfile = function(opt_label) {
+ return this.getTreeProfile_(this.topDownTree_, opt_label);
+};
+
+
+/**
+ * Calculates a bottom up profile for a node with the specified label.
+ * If no name specified, returns the whole bottom up calls tree.
+ *
+ * @param {string} opt_label Node label.
+ */
+devtools.profiler.Profile.prototype.getBottomUpProfile = function(opt_label) {
+ return this.getTreeProfile_(this.bottomUpTree_, opt_label);
};
/**
- * Calculates a bottom up profile starting from the specified node.
+ * Helper function for calculating a tree profile.
*
- * @param {devtools.profiler.CallTree.Node} opt_root Starting node.
+ * @param {devtools.profiler.Profile.CallTree} tree Call tree.
+ * @param {string} opt_label Node label.
*/
-devtools.profiler.Profile.prototype.getBottomUpProfile = function(opt_root) {
- if (!opt_root) {
- this.bottomUpTree_.computeTotalWeights();
- return this.bottomUpTree_;
+devtools.profiler.Profile.prototype.getTreeProfile_ = function(tree, opt_label) {
+ if (!opt_label) {
+ tree.computeTotalWeights();
+ return tree;
} else {
- throw Error('not implemented');
+ var subTree = tree.cloneSubtree(opt_label);
+ subTree.computeTotalWeights();
+ return subTree;
}
};
/**
- * Calculates a flat profile of callees starting from the specified node.
+ * Calculates a flat profile of callees starting from a node with
+ * the specified label. If no name specified, starts from the root.
*
- * @param {devtools.profiler.CallTree.Node} opt_root Starting node.
+ * @param {string} opt_label Starting node label.
*/
-devtools.profiler.Profile.prototype.getFlatProfile = function(opt_root) {
+devtools.profiler.Profile.prototype.getFlatProfile = function(opt_label) {
var counters = new devtools.profiler.CallTree();
+ var rootLabel = opt_label || devtools.profiler.CallTree.ROOT_NODE_LABEL;
var precs = {};
+ precs[rootLabel] = 0;
+ var root = counters.findOrAddChild(rootLabel);
+
this.topDownTree_.computeTotalWeights();
this.topDownTree_.traverseInDepth(
function onEnter(node) {
if (!(node.label in precs)) {
precs[node.label] = 0;
}
- var rec = counters.findOrAddChild(node.label);
- rec.selfWeight += node.selfWeight;
- if (precs[node.label] == 0) {
- rec.totalWeight += node.totalWeight;
+ var nodeLabelIsRootLabel = node.label == rootLabel;
+ if (nodeLabelIsRootLabel || precs[rootLabel] > 0) {
+ if (precs[rootLabel] == 0) {
+ root.selfWeight += node.selfWeight;
+ root.totalWeight += node.totalWeight;
+ } else {
+ var rec = root.findOrAddChild(node.label);
+ rec.selfWeight += node.selfWeight;
+ if (nodeLabelIsRootLabel || precs[node.label] == 0) {
+ rec.totalWeight += node.totalWeight;
+ }
+ }
+ precs[node.label]++;
}
- precs[node.label]++;
},
function onExit(node) {
- precs[node.label]--;
+ if (node.label == rootLabel || precs[rootLabel] > 0) {
+ precs[node.label]--;
+ }
},
- opt_root);
+ null);
+
+ if (!opt_label) {
+ // If we have created a flat profile for the whole program, we don't
+ // need an explicit root in it. Thus, replace the counters tree
+ // root with the node corresponding to the whole program.
+ counters.root_ = root;
+ } else {
+ // Propagate weights so percents can be calculated correctly.
+ counters.getRoot().selfWeight = root.selfWeight;
+ counters.getRoot().totalWeight = root.totalWeight;
+ }
return counters;
};
@@ -316,11 +334,18 @@ devtools.profiler.Profile.DynamicCodeEntry.prototype.getName = function() {
* @constructor
*/
devtools.profiler.CallTree = function() {
- this.root_ = new devtools.profiler.CallTree.Node('');
+ this.root_ = new devtools.profiler.CallTree.Node(
+ devtools.profiler.CallTree.ROOT_NODE_LABEL);
};
/**
+ * The label of the root node.
+ */
+devtools.profiler.CallTree.ROOT_NODE_LABEL = '';
+
+
+/**
* @private
*/
devtools.profiler.CallTree.prototype.totalsComputed_ = false;
@@ -359,10 +384,38 @@ devtools.profiler.CallTree.prototype.addPath = function(path) {
*
* @param {string} label Child node label.
*/
-devtools.profiler.CallTree.prototype.findOrAddChild = function(
- label, opt_parent) {
- var parent = opt_parent || this.root_;
- return parent.findOrAddChild(label);
+devtools.profiler.CallTree.prototype.findOrAddChild = function(label) {
+ return this.root_.findOrAddChild(label);
+};
+
+
+/**
+ * Creates a subtree by cloning and merging all subtrees rooted at nodes
+ * with a given label. E.g. cloning the following call tree on label 'A'
+ * will give the following result:
+ *
+ * <A>--<B> <B>
+ * / /
+ * <root> == clone on 'A' ==> <root>--<A>
+ * \ \
+ * <C>--<A>--<D> <D>
+ *
+ * And <A>'s selfWeight will be the sum of selfWeights of <A>'s from the
+ * source call tree.
+ *
+ * @param {string} label The label of the new root node.
+ */
+devtools.profiler.CallTree.prototype.cloneSubtree = function(label) {
+ var subTree = new devtools.profiler.CallTree();
+ this.traverse(function(node, parent) {
+ if (!parent && node.label != label) {
+ return null;
+ }
+ var child = (parent ? parent : subTree).findOrAddChild(node.label);
+ child.selfWeight += node.selfWeight;
+ return child;
+ });
+ return subTree;
};
@@ -392,11 +445,10 @@ devtools.profiler.CallTree.prototype.computeTotalWeights = function() {
*
* @param {function(devtools.profiler.CallTree.Node, *)} f Visitor function.
* The second parameter is the result of calling 'f' on the parent node.
- * @param {devtools.profiler.CallTree.Node} opt_start Starting node.
*/
-devtools.profiler.CallTree.prototype.traverse = function(f, opt_start) {
+devtools.profiler.CallTree.prototype.traverse = function(f) {
var pairsToProcess = new ConsArray();
- pairsToProcess.concat([{node: opt_start || this.root_, param: null}]);
+ pairsToProcess.concat([{node: this.root_, param: null}]);
while (!pairsToProcess.atEnd()) {
var pair = pairsToProcess.next();
var node = pair.node;
@@ -416,16 +468,14 @@ devtools.profiler.CallTree.prototype.traverse = function(f, opt_start) {
* prior to visiting node's children.
* @param {function(devtools.profiler.CallTree.Node)} exit A function called
* after visiting node's children.
- * @param {devtools.profiler.CallTree.Node} opt_start Starting node.
*/
-devtools.profiler.CallTree.prototype.traverseInDepth = function(
- enter, exit, opt_start) {
+devtools.profiler.CallTree.prototype.traverseInDepth = function(enter, exit) {
function traverse(node) {
enter(node);
node.forEachChild(traverse);
exit(node);
}
- traverse(opt_start || this.root_);
+ traverse(this.root_);
};
@@ -507,8 +557,7 @@ devtools.profiler.CallTree.Node.prototype.findChild = function(label) {
*
* @param {string} label Child node label.
*/
-devtools.profiler.CallTree.Node.prototype.findOrAddChild = function(
- label) {
+devtools.profiler.CallTree.Node.prototype.findOrAddChild = function(label) {
return this.findChild(label) || this.addChild(label);
};
« no previous file with comments | « test/mjsunit/tools/profile.js ('k') | tools/profile_view.js » ('j') | tools/profile_view.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698