| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| /** |
| * @unrestricted |
| */ |
| export class ProfileNode { |
| /** |
| * @param {!Protocol.Runtime.CallFrame} callFrame |
| */ |
| constructor(callFrame) { |
| /** @type {!Protocol.Runtime.CallFrame} */ |
| this.callFrame = callFrame; |
| /** @type {string} */ |
| this.callUID = `${callFrame.functionName}@${callFrame.scriptId}:${callFrame.lineNumber}:${callFrame.columnNumber}`; |
| /** @type {number} */ |
| this.self = 0; |
| /** @type {number} */ |
| this.total = 0; |
| /** @type {number} */ |
| this.id = 0; |
| /** @type {?ProfileNode} */ |
| this.parent = null; |
| /** @type {!Array<!ProfileNode>} */ |
| this.children = []; |
| } |
| |
| /** |
| * @return {string} |
| */ |
| get functionName() { |
| return this.callFrame.functionName; |
| } |
| |
| /** |
| * @return {string} |
| */ |
| get scriptId() { |
| return this.callFrame.scriptId; |
| } |
| |
| /** |
| * @return {string} |
| */ |
| get url() { |
| return this.callFrame.url; |
| } |
| |
| /** |
| * @return {number} |
| */ |
| get lineNumber() { |
| return this.callFrame.lineNumber; |
| } |
| |
| /** |
| * @return {number} |
| */ |
| get columnNumber() { |
| return this.callFrame.columnNumber; |
| } |
| } |
| |
| /** |
| * @unrestricted |
| */ |
| export default class ProfileTreeModel { |
| /** |
| * @param {?SDK.Target=} target |
| */ |
| constructor(target) { |
| this._target = target || null; |
| } |
| |
| /** |
| * @param {!ProfileNode} root |
| * @protected |
| */ |
| initialize(root) { |
| this.root = root; |
| this._assignDepthsAndParents(); |
| this.total = this._calculateTotals(this.root); |
| } |
| |
| _assignDepthsAndParents() { |
| const root = this.root; |
| root.depth = -1; |
| root.parent = null; |
| this.maxDepth = 0; |
| const nodesToTraverse = [root]; |
| while (nodesToTraverse.length) { |
| const parent = nodesToTraverse.pop(); |
| const depth = parent.depth + 1; |
| if (depth > this.maxDepth) { |
| this.maxDepth = depth; |
| } |
| const children = parent.children; |
| const length = children.length; |
| for (let i = 0; i < length; ++i) { |
| const child = children[i]; |
| child.depth = depth; |
| child.parent = parent; |
| if (child.children.length) { |
| nodesToTraverse.push(child); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @param {!ProfileNode} root |
| * @return {number} |
| */ |
| _calculateTotals(root) { |
| const nodesToTraverse = [root]; |
| const dfsList = []; |
| while (nodesToTraverse.length) { |
| const node = nodesToTraverse.pop(); |
| node.total = node.self; |
| dfsList.push(node); |
| nodesToTraverse.push(...node.children); |
| } |
| while (dfsList.length > 1) { |
| const node = dfsList.pop(); |
| node.parent.total += node.total; |
| } |
| return root.total; |
| } |
| |
| /** |
| * @return {?SDK.Target} |
| */ |
| target() { |
| return this._target; |
| } |
| } |
| |
| /* Legacy exported object */ |
| self.SDK = self.SDK || {}; |
| |
| /* Legacy exported object */ |
| SDK = SDK || {}; |
| |
| /** @constructor */ |
| SDK.ProfileTreeModel = ProfileTreeModel; |
| |
| /** @constructor */ |
| SDK.ProfileNode = ProfileNode; |