1// Copyright 2009 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28import { ConsArray } from "./consarray.mjs"; 29 30/** 31 * Creates a Profile View builder object. 32 * 33 * @param {number} samplingRate Number of ms between profiler ticks. 34 * @constructor 35 */ 36export function ViewBuilder(samplingRate) { 37 this.samplingRate = samplingRate; 38}; 39 40 41/** 42 * Builds a profile view for the specified call tree. 43 * 44 * @param {CallTree} callTree A call tree. 45 * @param {boolean} opt_bottomUpViewWeights Whether remapping 46 * of self weights for a bottom up view is needed. 47 */ 48ViewBuilder.prototype.buildView = function( 49 callTree, opt_bottomUpViewWeights) { 50 let head; 51 const samplingRate = this.samplingRate; 52 const createViewNode = this.createViewNode; 53 callTree.traverse(function(node, viewParent) { 54 const totalWeight = node.totalWeight * samplingRate; 55 let selfWeight = node.selfWeight * samplingRate; 56 if (opt_bottomUpViewWeights === true) { 57 if (viewParent === head) { 58 selfWeight = totalWeight; 59 } else { 60 selfWeight = 0; 61 } 62 } 63 const viewNode = createViewNode(node.label, totalWeight, selfWeight, head); 64 if (viewParent) { 65 viewParent.addChild(viewNode); 66 } else { 67 head = viewNode; 68 } 69 return viewNode; 70 }); 71 const view = this.createView(head); 72 return view; 73}; 74 75 76/** 77 * Factory method for a profile view. 78 * 79 * @param {ProfileView.Node} head View head node. 80 * @return {ProfileView} Profile view. 81 */ 82ViewBuilder.prototype.createView = head => new ProfileView(head); 83 84 85/** 86 * Factory method for a profile view node. 87 * 88 * @param {string} internalFuncName A fully qualified function name. 89 * @param {number} totalTime Amount of time that application spent in the 90 * corresponding function and its descendants (not that depending on 91 * profile they can be either callees or callers.) 92 * @param {number} selfTime Amount of time that application spent in the 93 * corresponding function only. 94 * @param {ProfileView.Node} head Profile view head. 95 * @return {ProfileView.Node} Profile view node. 96 */ 97ViewBuilder.prototype.createViewNode = ( 98 funcName, totalTime, selfTime, head) => 99 new ProfileView.Node( 100 funcName, totalTime, selfTime, head) 101; 102 103 104/** 105 * Creates a Profile View object. It allows to perform sorting 106 * and filtering actions on the profile. 107 * 108 * @param {ProfileView.Node} head Head (root) node. 109 * @constructor 110 */ 111export function ProfileView(head) { 112 this.head = head; 113}; 114 115 116/** 117 * Sorts the profile view using the specified sort function. 118 * 119 * @param {function(ProfileView.Node, 120 * ProfileView.Node):number} sortFunc A sorting 121 * functions. Must comply with Array.sort sorting function requirements. 122 */ 123ProfileView.prototype.sort = function(sortFunc) { 124 this.traverse(function (node) { 125 node.sortChildren(sortFunc); 126 }); 127}; 128 129 130/** 131 * Traverses profile view nodes in preorder. 132 * 133 * @param {function(ProfileView.Node)} f Visitor function. 134 */ 135ProfileView.prototype.traverse = function(f) { 136 const nodesToTraverse = new ConsArray(); 137 nodesToTraverse.concat([this.head]); 138 while (!nodesToTraverse.atEnd()) { 139 const node = nodesToTraverse.next(); 140 f(node); 141 nodesToTraverse.concat(node.children); 142 } 143}; 144 145 146/** 147 * Constructs a Profile View node object. Each node object corresponds to 148 * a function call. 149 * 150 * @param {string} internalFuncName A fully qualified function name. 151 * @param {number} totalTime Amount of time that application spent in the 152 * corresponding function and its descendants (not that depending on 153 * profile they can be either callees or callers.) 154 * @param {number} selfTime Amount of time that application spent in the 155 * corresponding function only. 156 * @param {ProfileView.Node} head Profile view head. 157 * @constructor 158 */ 159ProfileView.Node = function( 160 internalFuncName, totalTime, selfTime, head) { 161 this.internalFuncName = internalFuncName; 162 this.totalTime = totalTime; 163 this.selfTime = selfTime; 164 this.head = head; 165 this.parent = null; 166 this.children = []; 167}; 168 169 170/** 171 * Returns a share of the function's total time in its parent's total time. 172 */ 173ProfileView.Node.prototype.__defineGetter__( 174 'parentTotalPercent', 175 function() { return this.totalTime / 176 (this.parent ? this.parent.totalTime : this.totalTime) * 100.0; }); 177 178 179/** 180 * Adds a child to the node. 181 * 182 * @param {ProfileView.Node} node Child node. 183 */ 184ProfileView.Node.prototype.addChild = function(node) { 185 node.parent = this; 186 this.children.push(node); 187}; 188 189 190/** 191 * Sorts all the node's children recursively. 192 * 193 * @param {function(ProfileView.Node, 194 * ProfileView.Node):number} sortFunc A sorting 195 * functions. Must comply with Array.sort sorting function requirements. 196 */ 197ProfileView.Node.prototype.sortChildren = function( 198 sortFunc) { 199 this.children.sort(sortFunc); 200}; 201