Index: third_party/WebKit/Source/devtools/front_end/sdk/CPUProfileDataModel.js |
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CPUProfileDataModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/CPUProfileDataModel.js |
index d51f72d510a9e418ce1b0e3a7dbfae8743f22f34..702ae6c71ee3a351160e57d1ff7fa86f66139e91 100644 |
--- a/third_party/WebKit/Source/devtools/front_end/sdk/CPUProfileDataModel.js |
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/CPUProfileDataModel.js |
@@ -2,72 +2,82 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+/** |
+ * @constructor |
+ * @extends {WebInspector.ProfileNode} |
+ * @param {!ProfilerAgent.CPUProfileNode} sourceNode |
+ * @param {number} sampleTime |
+ */ |
+WebInspector.CPUProfileNode = function(sourceNode, sampleTime) |
+{ |
+ WebInspector.ProfileNode.call(this, sourceNode.functionName, sourceNode.scriptId, sourceNode.url, sourceNode.lineNumber, sourceNode.columnNumber); |
+ this.id = sourceNode.id; |
+ this.self = sourceNode.hitCount * sampleTime; |
+ this.callUID = sourceNode.callUID; |
+ this.positionTicks = sourceNode.positionTicks; |
+ this.deoptReason = sourceNode.deoptReason; |
+ // TODO: Remove the following field in favor of this.self |
+ this.selfTime = this.self; |
+} |
+ |
+WebInspector.CPUProfileNode.prototype = { |
+ __proto__: WebInspector.ProfileNode.prototype |
+} |
/** |
* @constructor |
+ * @extends {WebInspector.ProfileTreeModel} |
* @param {!ProfilerAgent.CPUProfile} profile |
*/ |
WebInspector.CPUProfileDataModel = function(profile) |
{ |
- this.profileHead = profile.head; |
this.samples = profile.samples; |
this.timestamps = profile.timestamps; |
+ // Convert times from sec to msec. |
this.profileStartTime = profile.startTime * 1000; |
this.profileEndTime = profile.endTime * 1000; |
- this._assignParentsInProfile(); |
+ this.totalHitCount = 0; |
+ if (!WebInspector.moduleSetting("showNativeFunctionsInJSProfile").get()) |
+ this._filterNativeFrames(profile.head); |
+ this.profileHead = this._translateProfileTree(profile.head); |
+ WebInspector.ProfileTreeModel.call(this, this.profileHead, this.profileStartTime, this.profileEndTime); |
+ this._extractMetaNodes(); |
if (this.samples) { |
+ this._buildIdToNodeMap(); |
this._sortSamples(); |
this._normalizeTimestamps(); |
- this._buildIdToNodeMap(); |
this._fixMissingSamples(); |
} |
- if (!WebInspector.moduleSetting("showNativeFunctionsInJSProfile").get()) |
- this._filterNativeFrames(); |
- this._assignDepthsInProfile(); |
- this._calculateTimes(profile); |
+ this._assignTotalTimes(this.profileHead); |
} |
WebInspector.CPUProfileDataModel.prototype = { |
/** |
- * @param {!ProfilerAgent.CPUProfile} profile |
+ * @param {!ProfilerAgent.CPUProfileNode} root |
*/ |
- _calculateTimes: function(profile) |
- { |
- function totalHitCount(node) { |
- var result = node.hitCount; |
- for (var i = 0; i < node.children.length; i++) |
- result += totalHitCount(node.children[i]); |
- return result; |
- } |
- profile.totalHitCount = totalHitCount(profile.head); |
- this.totalHitCount = profile.totalHitCount; |
- |
- var duration = this.profileEndTime - this.profileStartTime; |
- var samplingInterval = duration / profile.totalHitCount; |
- this.samplingInterval = samplingInterval; |
- |
- function calculateTimesForNode(node) { |
- node.selfTime = node.hitCount * samplingInterval; |
- var totalHitCount = node.hitCount; |
- for (var i = 0; i < node.children.length; i++) |
- totalHitCount += calculateTimesForNode(node.children[i]); |
- node.totalTime = totalHitCount * samplingInterval; |
- return totalHitCount; |
- } |
- calculateTimesForNode(profile.head); |
- }, |
- |
- _filterNativeFrames: function() |
+ _filterNativeFrames: function(root) |
{ |
+ // TODO: get rid of this function and do the filtering while _translateProfileTree |
if (this.samples) { |
+ /** @type {!Map<number, !ProfilerAgent.CPUProfileNode>} */ |
+ var idToNode = new Map(); |
+ var stack = [root]; |
+ while (stack.length) { |
+ var node = stack.pop(); |
+ idToNode.set(node.id, node); |
+ for (var i = 0; i < node.children.length; i++) { |
+ node.children[i].parent = node; |
+ stack.push(node.children[i]); |
+ } |
+ } |
for (var i = 0; i < this.samples.length; ++i) { |
- var node = this.nodeByIndex(i); |
+ var node = idToNode.get(this.samples[i]); |
while (isNativeNode(node)) |
node = node.parent; |
this.samples[i] = node.id; |
} |
} |
- processSubtree(this.profileHead); |
+ processSubtree(root); |
/** |
* @param {!ProfilerAgent.CPUProfileNode} node |
@@ -118,44 +128,43 @@ WebInspector.CPUProfileDataModel.prototype = { |
} |
}, |
- _assignParentsInProfile: function() |
+ /** |
+ * @param {!ProfilerAgent.CPUProfileNode} root |
+ * @return {!WebInspector.CPUProfileNode} |
+ */ |
+ _translateProfileTree: function(root) |
{ |
- var head = this.profileHead; |
- head.parent = null; |
- var nodesToTraverse = [ head ]; |
- while (nodesToTraverse.length) { |
- var parent = nodesToTraverse.pop(); |
- var children = parent.children; |
- var length = children.length; |
- for (var i = 0; i < length; ++i) { |
- var child = children[i]; |
- child.parent = parent; |
- if (child.children.length) |
- nodesToTraverse.push(child); |
- } |
+ /** |
+ * @param {!ProfilerAgent.CPUProfileNode} node |
+ * @return {number} |
+ */ |
+ function computeHitCountForSubtree(node) |
+ { |
+ return node.children.reduce((acc, node) => acc + computeHitCountForSubtree(node), node.hitCount); |
+ } |
+ this.totalHitCount = computeHitCountForSubtree(root); |
+ var sampleTime = (this.profileEndTime - this.profileStartTime) / this.totalHitCount; |
+ var resultRoot = new WebInspector.CPUProfileNode(root, sampleTime); |
+ var targetNodeStack = [resultRoot]; |
+ var sourceNodeStack = [root]; |
+ while (sourceNodeStack.length) { |
+ var sourceNode = sourceNodeStack.pop(); |
+ var parentNode = targetNodeStack.pop(); |
+ parentNode.children = sourceNode.children.map(child => new WebInspector.CPUProfileNode(child, sampleTime)); |
+ sourceNodeStack.push.apply(sourceNodeStack, sourceNode.children); |
+ targetNodeStack.push.apply(targetNodeStack, parentNode.children); |
} |
+ return resultRoot; |
}, |
- _assignDepthsInProfile: function() |
+ /** |
+ * @param {!WebInspector.ProfileNode} node |
+ */ |
+ _assignTotalTimes: function(node) |
{ |
- var head = this.profileHead; |
- head.depth = -1; |
- this.maxDepth = 0; |
- var nodesToTraverse = [ head ]; |
- while (nodesToTraverse.length) { |
- var parent = nodesToTraverse.pop(); |
- var depth = parent.depth + 1; |
- if (depth > this.maxDepth) |
- this.maxDepth = depth; |
- var children = parent.children; |
- var length = children.length; |
- for (var i = 0; i < length; ++i) { |
- var child = children[i]; |
- child.depth = depth; |
- if (child.children.length) |
- nodesToTraverse.push(child); |
- } |
- } |
+ // TODO: get rid of this field in favor of this.total |
+ node.totalTime = node.total; |
+ node.children.forEach(this._assignTotalTimes, this); |
}, |
_sortSamples: function() |
@@ -213,7 +222,7 @@ WebInspector.CPUProfileDataModel.prototype = { |
_buildIdToNodeMap: function() |
{ |
- /** @type {!Object.<number, !ProfilerAgent.CPUProfileNode>} */ |
+ /** @type {!Object<number, !WebInspector.CPUProfileNode>} */ |
this._idToNode = {}; |
var idToNode = this._idToNode; |
var stack = [this.profileHead]; |
@@ -223,7 +232,10 @@ WebInspector.CPUProfileDataModel.prototype = { |
for (var i = 0; i < node.children.length; i++) |
stack.push(node.children[i]); |
} |
+ }, |
+ _extractMetaNodes: function() |
+ { |
var topLevelNodes = this.profileHead.children; |
for (var i = 0; i < topLevelNodes.length && !(this.gcNode && this.programNode && this.idleNode); i++) { |
var node = topLevelNodes[i]; |
@@ -265,12 +277,12 @@ WebInspector.CPUProfileDataModel.prototype = { |
} |
/** |
- * @param {!ProfilerAgent.CPUProfileNode} node |
- * @return {!ProfilerAgent.CPUProfileNode} |
+ * @param {!WebInspector.ProfileNode} node |
+ * @return {!WebInspector.ProfileNode} |
*/ |
function bottomNode(node) |
{ |
- while (node.parent.parent) |
+ while (node.parent && node.parent.parent) |
node = node.parent; |
return node; |
} |
@@ -286,8 +298,8 @@ WebInspector.CPUProfileDataModel.prototype = { |
}, |
/** |
- * @param {function(number, !ProfilerAgent.CPUProfileNode, number)} openFrameCallback |
- * @param {function(number, !ProfilerAgent.CPUProfileNode, number, number, number)} closeFrameCallback |
+ * @param {function(number, !WebInspector.CPUProfileNode, number)} openFrameCallback |
+ * @param {function(number, !WebInspector.CPUProfileNode, number, number, number)} closeFrameCallback |
* @param {number=} startTime |
* @param {number=} stopTime |
*/ |
@@ -358,7 +370,7 @@ WebInspector.CPUProfileDataModel.prototype = { |
var start = stackStartTimes[stackTop]; |
var duration = sampleTime - start; |
stackChildrenDuration[stackTop - 1] += duration; |
- closeFrameCallback(prevNode.depth, prevNode, start, duration, duration - stackChildrenDuration[stackTop]); |
+ closeFrameCallback(prevNode.depth, /** @type {!WebInspector.CPUProfileNode} */(prevNode), start, duration, duration - stackChildrenDuration[stackTop]); |
--stackTop; |
if (node.depth === prevNode.depth) { |
stackNodes.push(node); |
@@ -390,18 +402,19 @@ WebInspector.CPUProfileDataModel.prototype = { |
var start = stackStartTimes[stackTop]; |
var duration = sampleTime - start; |
stackChildrenDuration[stackTop - 1] += duration; |
- closeFrameCallback(node.depth, node, start, duration, duration - stackChildrenDuration[stackTop]); |
+ closeFrameCallback(node.depth, /** @type {!WebInspector.CPUProfileNode} */(node), start, duration, duration - stackChildrenDuration[stackTop]); |
--stackTop; |
} |
}, |
/** |
* @param {number} index |
- * @return {!ProfilerAgent.CPUProfileNode} |
+ * @return {!WebInspector.CPUProfileNode} |
*/ |
nodeByIndex: function(index) |
{ |
return this._idToNode[this.samples[index]]; |
- } |
+ }, |
+ __proto__: WebInspector.ProfileTreeModel.prototype |
} |