| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 /* | 
|  | 2  * Copyright (C) 2009 280 North Inc. All Rights Reserved. | 
|  | 3  * | 
|  | 4  * Redistribution and use in source and binary forms, with or without | 
|  | 5  * modification, are permitted provided that the following conditions | 
|  | 6  * are met: | 
|  | 7  * 1. Redistributions of source code must retain the above copyright | 
|  | 8  *    notice, this list of conditions and the following disclaimer. | 
|  | 9  * 2. Redistributions in binary form must reproduce the above copyright | 
|  | 10  *    notice, this list of conditions and the following disclaimer in the | 
|  | 11  *    documentation and/or other materials provided with the distribution. | 
|  | 12  * | 
|  | 13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
|  | 14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | 15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
|  | 16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR | 
|  | 17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
|  | 18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
|  | 19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
|  | 20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
|  | 21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | 22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | 23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | 24  */ | 
|  | 25 | 
|  | 26 // Bottom Up Profiling shows the entire callstack backwards: | 
|  | 27 // The root node is a representation of each individual function called, and eac
     h child of that node represents | 
|  | 28 // a reverse-callstack showing how many of those calls came from it. So, unlike 
     top-down, the statistics in | 
|  | 29 // each child still represent the root node. We have to be particularly careful 
     of recursion with this mode | 
|  | 30 // because a root node can represent itself AND an ancestor. | 
|  | 31 | 
|  | 32 WebInspector.BottomUpProfileDataGridNode = function(/*ProfileView*/ profileView,
      /*ProfileNode*/ profileNode, /*BottomUpProfileDataGridTree*/ owningTree) | 
|  | 33 { | 
|  | 34     // In bottom up mode, our parents are our children since we display an inver
     ted tree. | 
|  | 35     // However, we don't want to show the very top parent since it is redundant. | 
|  | 36     var hasChildren = !!(profileNode.parent && profileNode.parent.parent); | 
|  | 37 | 
|  | 38     WebInspector.ProfileDataGridNode.call(this, profileView, profileNode, owning
     Tree, hasChildren); | 
|  | 39 | 
|  | 40     this._remainingNodeInfos = []; | 
|  | 41 } | 
|  | 42 | 
|  | 43 WebInspector.BottomUpProfileDataGridNode.prototype = { | 
|  | 44     _takePropertiesFromProfileDataGridNode: function(/*ProfileDataGridNode*/ pro
     fileDataGridNode) | 
|  | 45     { | 
|  | 46         this._save(); | 
|  | 47 | 
|  | 48         this.selfTime = profileDataGridNode.selfTime; | 
|  | 49         this.totalTime = profileDataGridNode.totalTime; | 
|  | 50         this.numberOfCalls = profileDataGridNode.numberOfCalls; | 
|  | 51     }, | 
|  | 52 | 
|  | 53     // When focusing, we keep just the members of the callstack. | 
|  | 54     _keepOnlyChild: function(/*ProfileDataGridNode*/ child) | 
|  | 55     { | 
|  | 56         this._save(); | 
|  | 57 | 
|  | 58         this.removeChildren(); | 
|  | 59         this.appendChild(child); | 
|  | 60     }, | 
|  | 61 | 
|  | 62     _exclude: function(aCallUID) | 
|  | 63     { | 
|  | 64         if (this._remainingNodeInfos) | 
|  | 65             this._populate(); | 
|  | 66 | 
|  | 67         this._save(); | 
|  | 68 | 
|  | 69         var children = this.children; | 
|  | 70         var index = this.children.length; | 
|  | 71 | 
|  | 72         while (index--) | 
|  | 73             children[index]._exclude(aCallUID); | 
|  | 74 | 
|  | 75         var child = this.childrenByCallUID[aCallUID]; | 
|  | 76 | 
|  | 77         if (child) | 
|  | 78             this._merge(child, true); | 
|  | 79     }, | 
|  | 80 | 
|  | 81     _merge: function(/*ProfileDataGridNode*/ child, /*Boolean*/ shouldAbsorb) | 
|  | 82     { | 
|  | 83         this.selfTime -= child.selfTime; | 
|  | 84 | 
|  | 85         WebInspector.ProfileDataGridNode.prototype._merge.call(this, child, shou
     ldAbsorb); | 
|  | 86     }, | 
|  | 87 | 
|  | 88     _sharedPopulate: function() | 
|  | 89     { | 
|  | 90         var remainingNodeInfos = this._remainingNodeInfos; | 
|  | 91         var count = remainingNodeInfos.length; | 
|  | 92 | 
|  | 93         for (var index = 0; index < count; ++index) { | 
|  | 94             var nodeInfo = remainingNodeInfos[index]; | 
|  | 95             var ancestor = nodeInfo.ancestor; | 
|  | 96             var focusNode = nodeInfo.focusNode; | 
|  | 97             var child = this.findChild(ancestor); | 
|  | 98 | 
|  | 99             // If we already have this child, then merge the data together. | 
|  | 100             if (child) { | 
|  | 101                 var totalTimeAccountedFor = nodeInfo.totalTimeAccountedFor; | 
|  | 102 | 
|  | 103                 child.selfTime += focusNode.selfTime; | 
|  | 104                 child.numberOfCalls += focusNode.numberOfCalls; | 
|  | 105 | 
|  | 106                 if (!totalTimeAccountedFor) | 
|  | 107                     child.totalTime += focusNode.totalTime; | 
|  | 108             } else { | 
|  | 109                 // If not, add it as a true ancestor. | 
|  | 110                 // In heavy mode, we take our visual identity from ancestor node
     ... | 
|  | 111                 var child = new WebInspector.BottomUpProfileDataGridNode(this.pr
     ofileView, ancestor, this.tree); | 
|  | 112 | 
|  | 113                 if (ancestor !== focusNode) { | 
|  | 114                     // but the actual statistics from the "root" node (bottom of
      the callstack). | 
|  | 115                     child.selfTime = focusNode.selfTime; | 
|  | 116                     child.totalTime = focusNode.totalTime; | 
|  | 117                     child.numberOfCalls = focusNode.numberOfCalls; | 
|  | 118                 } | 
|  | 119 | 
|  | 120                 this.appendChild(child); | 
|  | 121             } | 
|  | 122 | 
|  | 123             var parent = ancestor.parent; | 
|  | 124             if (parent && parent.parent) { | 
|  | 125                 nodeInfo.ancestor = parent; | 
|  | 126                 child._remainingNodeInfos.push(nodeInfo); | 
|  | 127             } | 
|  | 128         } | 
|  | 129 | 
|  | 130         delete this._remainingNodeInfos; | 
|  | 131     } | 
|  | 132 } | 
|  | 133 | 
|  | 134 WebInspector.BottomUpProfileDataGridNode.prototype.__proto__ = WebInspector.Prof
     ileDataGridNode.prototype; | 
|  | 135 | 
|  | 136 WebInspector.BottomUpProfileDataGridTree = function(/*ProfileView*/ aProfileView
     , /*ProfileNode*/ aProfileNode) | 
|  | 137 { | 
|  | 138     WebInspector.ProfileDataGridTree.call(this, aProfileView, aProfileNode); | 
|  | 139 | 
|  | 140     // Iterate each node in pre-order. | 
|  | 141     var profileNodeUIDs = 0; | 
|  | 142     var profileNodeGroups = [[], [aProfileNode]]; | 
|  | 143     var visitedProfileNodesForCallUID = {}; | 
|  | 144 | 
|  | 145     this._remainingNodeInfos = []; | 
|  | 146 | 
|  | 147     for (var profileNodeGroupIndex = 0; profileNodeGroupIndex < profileNodeGroup
     s.length; ++profileNodeGroupIndex) { | 
|  | 148         var parentProfileNodes = profileNodeGroups[profileNodeGroupIndex]; | 
|  | 149         var profileNodes = profileNodeGroups[++profileNodeGroupIndex]; | 
|  | 150         var count = profileNodes.length; | 
|  | 151 | 
|  | 152         for (var index = 0; index < count; ++index) { | 
|  | 153             var profileNode = profileNodes[index]; | 
|  | 154 | 
|  | 155             if (!profileNode.UID) | 
|  | 156                 profileNode.UID = ++profileNodeUIDs; | 
|  | 157 | 
|  | 158             if (profileNode.head && profileNode !== profileNode.head) { | 
|  | 159                 // The total time of this ancestor is accounted for if we're in 
     any form of recursive cycle. | 
|  | 160                 var visitedNodes = visitedProfileNodesForCallUID[profileNode.cal
     lUID]; | 
|  | 161                 var totalTimeAccountedFor = false; | 
|  | 162 | 
|  | 163                 if (!visitedNodes) { | 
|  | 164                     visitedNodes = {} | 
|  | 165                     visitedProfileNodesForCallUID[profileNode.callUID] = visited
     Nodes; | 
|  | 166                 } else { | 
|  | 167                     // The total time for this node has already been accounted f
     or iff one of it's parents has already been visited. | 
|  | 168                     // We can do this check in this style because we are travers
     ing the tree in pre-order. | 
|  | 169                     var parentCount = parentProfileNodes.length; | 
|  | 170                     for (var parentIndex = 0; parentIndex < parentCount; ++paren
     tIndex) { | 
|  | 171                         if (visitedNodes[parentProfileNodes[parentIndex].UID]) { | 
|  | 172                             totalTimeAccountedFor = true; | 
|  | 173                             break; | 
|  | 174                         } | 
|  | 175                     } | 
|  | 176                 } | 
|  | 177 | 
|  | 178                 visitedNodes[profileNode.UID] = true; | 
|  | 179 | 
|  | 180                 this._remainingNodeInfos.push({ ancestor:profileNode, focusNode:
     profileNode, totalTimeAccountedFor:totalTimeAccountedFor }); | 
|  | 181             } | 
|  | 182 | 
|  | 183             var children = profileNode.children; | 
|  | 184             if (children.length) { | 
|  | 185                 profileNodeGroups.push(parentProfileNodes.concat([profileNode])) | 
|  | 186                 profileNodeGroups.push(children); | 
|  | 187             } | 
|  | 188         } | 
|  | 189     } | 
|  | 190 | 
|  | 191     // Populate the top level nodes. | 
|  | 192     WebInspector.BottomUpProfileDataGridNode.prototype._populate.call(this); | 
|  | 193 | 
|  | 194     return this; | 
|  | 195 } | 
|  | 196 | 
|  | 197 WebInspector.BottomUpProfileDataGridTree.prototype = { | 
|  | 198     // When focusing, we keep the entire callstack up to this ancestor. | 
|  | 199     focus: function(/*ProfileDataGridNode*/ profileDataGridNode) | 
|  | 200     { | 
|  | 201         if (!profileDataGridNode) | 
|  | 202             return; | 
|  | 203 | 
|  | 204         this._save(); | 
|  | 205 | 
|  | 206         var currentNode = profileDataGridNode; | 
|  | 207         var focusNode = profileDataGridNode; | 
|  | 208 | 
|  | 209         while (currentNode.parent && (currentNode instanceof WebInspector.Profil
     eDataGridNode)) { | 
|  | 210             currentNode._takePropertiesFromProfileDataGridNode(profileDataGridNo
     de); | 
|  | 211 | 
|  | 212             focusNode = currentNode; | 
|  | 213             currentNode = currentNode.parent; | 
|  | 214 | 
|  | 215             if (currentNode instanceof WebInspector.ProfileDataGridNode) | 
|  | 216                 currentNode._keepOnlyChild(focusNode); | 
|  | 217         } | 
|  | 218 | 
|  | 219         this.children = [focusNode]; | 
|  | 220         this.totalTime = profileDataGridNode.totalTime; | 
|  | 221     }, | 
|  | 222 | 
|  | 223     exclude: function(/*ProfileDataGridNode*/ profileDataGridNode) | 
|  | 224     { | 
|  | 225         if (!profileDataGridNode) | 
|  | 226             return; | 
|  | 227 | 
|  | 228         this._save(); | 
|  | 229 | 
|  | 230         var excludedCallUID = profileDataGridNode.callUID; | 
|  | 231         var excludedTopLevelChild = this.childrenByCallUID[excludedCallUID]; | 
|  | 232 | 
|  | 233         // If we have a top level node that is excluded, get rid of it completel
     y (not keeping children), | 
|  | 234         // since bottom up data relies entirely on the root node. | 
|  | 235         if (excludedTopLevelChild) | 
|  | 236             this.children.remove(excludedTopLevelChild); | 
|  | 237 | 
|  | 238         var children = this.children; | 
|  | 239         var count = children.length; | 
|  | 240 | 
|  | 241         for (var index = 0; index < count; ++index) | 
|  | 242             children[index]._exclude(excludedCallUID); | 
|  | 243 | 
|  | 244         if (this.lastComparator) | 
|  | 245             this.sort(this.lastComparator, true); | 
|  | 246     }, | 
|  | 247 | 
|  | 248     _sharedPopulate: WebInspector.BottomUpProfileDataGridNode.prototype._sharedP
     opulate | 
|  | 249 } | 
|  | 250 | 
|  | 251 WebInspector.BottomUpProfileDataGridTree.prototype.__proto__ = WebInspector.Prof
     ileDataGridTree.prototype; | 
|  | 252 | 
| OLD | NEW | 
|---|