Index: resources/inspector/BottomUpProfileDataGridTree.js |
=================================================================== |
--- resources/inspector/BottomUpProfileDataGridTree.js (revision 33840) |
+++ resources/inspector/BottomUpProfileDataGridTree.js (working copy) |
@@ -1,252 +0,0 @@ |
-/* |
- * Copyright (C) 2009 280 North Inc. All Rights Reserved. |
- * |
- * Redistribution and use in source and binary forms, with or without |
- * modification, are permitted provided that the following conditions |
- * are met: |
- * 1. Redistributions of source code must retain the above copyright |
- * notice, this list of conditions and the following disclaimer. |
- * 2. Redistributions in binary form must reproduce the above copyright |
- * notice, this list of conditions and the following disclaimer in the |
- * documentation and/or other materials provided with the distribution. |
- * |
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- */ |
- |
-// Bottom Up Profiling shows the entire callstack backwards: |
-// The root node is a representation of each individual function called, and each child of that node represents |
-// a reverse-callstack showing how many of those calls came from it. So, unlike top-down, the statistics in |
-// each child still represent the root node. We have to be particularly careful of recursion with this mode |
-// because a root node can represent itself AND an ancestor. |
- |
-WebInspector.BottomUpProfileDataGridNode = function(/*ProfileView*/ profileView, /*ProfileNode*/ profileNode, /*BottomUpProfileDataGridTree*/ owningTree) |
-{ |
- // In bottom up mode, our parents are our children since we display an inverted tree. |
- // However, we don't want to show the very top parent since it is redundant. |
- var hasChildren = !!(profileNode.parent && profileNode.parent.parent); |
- |
- WebInspector.ProfileDataGridNode.call(this, profileView, profileNode, owningTree, hasChildren); |
- |
- this._remainingNodeInfos = []; |
-} |
- |
-WebInspector.BottomUpProfileDataGridNode.prototype = { |
- _takePropertiesFromProfileDataGridNode: function(/*ProfileDataGridNode*/ profileDataGridNode) |
- { |
- this._save(); |
- |
- this.selfTime = profileDataGridNode.selfTime; |
- this.totalTime = profileDataGridNode.totalTime; |
- this.numberOfCalls = profileDataGridNode.numberOfCalls; |
- }, |
- |
- // When focusing, we keep just the members of the callstack. |
- _keepOnlyChild: function(/*ProfileDataGridNode*/ child) |
- { |
- this._save(); |
- |
- this.removeChildren(); |
- this.appendChild(child); |
- }, |
- |
- _exclude: function(aCallUID) |
- { |
- if (this._remainingNodeInfos) |
- this._populate(); |
- |
- this._save(); |
- |
- var children = this.children; |
- var index = this.children.length; |
- |
- while (index--) |
- children[index]._exclude(aCallUID); |
- |
- var child = this.childrenByCallUID[aCallUID]; |
- |
- if (child) |
- this._merge(child, true); |
- }, |
- |
- _merge: function(/*ProfileDataGridNode*/ child, /*Boolean*/ shouldAbsorb) |
- { |
- this.selfTime -= child.selfTime; |
- |
- WebInspector.ProfileDataGridNode.prototype._merge.call(this, child, shouldAbsorb); |
- }, |
- |
- _sharedPopulate: function() |
- { |
- var remainingNodeInfos = this._remainingNodeInfos; |
- var count = remainingNodeInfos.length; |
- |
- for (var index = 0; index < count; ++index) { |
- var nodeInfo = remainingNodeInfos[index]; |
- var ancestor = nodeInfo.ancestor; |
- var focusNode = nodeInfo.focusNode; |
- var child = this.findChild(ancestor); |
- |
- // If we already have this child, then merge the data together. |
- if (child) { |
- var totalTimeAccountedFor = nodeInfo.totalTimeAccountedFor; |
- |
- child.selfTime += focusNode.selfTime; |
- child.numberOfCalls += focusNode.numberOfCalls; |
- |
- if (!totalTimeAccountedFor) |
- child.totalTime += focusNode.totalTime; |
- } else { |
- // If not, add it as a true ancestor. |
- // In heavy mode, we take our visual identity from ancestor node... |
- var child = new WebInspector.BottomUpProfileDataGridNode(this.profileView, ancestor, this.tree); |
- |
- if (ancestor !== focusNode) { |
- // but the actual statistics from the "root" node (bottom of the callstack). |
- child.selfTime = focusNode.selfTime; |
- child.totalTime = focusNode.totalTime; |
- child.numberOfCalls = focusNode.numberOfCalls; |
- } |
- |
- this.appendChild(child); |
- } |
- |
- var parent = ancestor.parent; |
- if (parent && parent.parent) { |
- nodeInfo.ancestor = parent; |
- child._remainingNodeInfos.push(nodeInfo); |
- } |
- } |
- |
- delete this._remainingNodeInfos; |
- } |
-} |
- |
-WebInspector.BottomUpProfileDataGridNode.prototype.__proto__ = WebInspector.ProfileDataGridNode.prototype; |
- |
-WebInspector.BottomUpProfileDataGridTree = function(/*ProfileView*/ aProfileView, /*ProfileNode*/ aProfileNode) |
-{ |
- WebInspector.ProfileDataGridTree.call(this, aProfileView, aProfileNode); |
- |
- // Iterate each node in pre-order. |
- var profileNodeUIDs = 0; |
- var profileNodeGroups = [[], [aProfileNode]]; |
- var visitedProfileNodesForCallUID = {}; |
- |
- this._remainingNodeInfos = []; |
- |
- for (var profileNodeGroupIndex = 0; profileNodeGroupIndex < profileNodeGroups.length; ++profileNodeGroupIndex) { |
- var parentProfileNodes = profileNodeGroups[profileNodeGroupIndex]; |
- var profileNodes = profileNodeGroups[++profileNodeGroupIndex]; |
- var count = profileNodes.length; |
- |
- for (var index = 0; index < count; ++index) { |
- var profileNode = profileNodes[index]; |
- |
- if (!profileNode.UID) |
- profileNode.UID = ++profileNodeUIDs; |
- |
- if (profileNode.head && profileNode !== profileNode.head) { |
- // The total time of this ancestor is accounted for if we're in any form of recursive cycle. |
- var visitedNodes = visitedProfileNodesForCallUID[profileNode.callUID]; |
- var totalTimeAccountedFor = false; |
- |
- if (!visitedNodes) { |
- visitedNodes = {} |
- visitedProfileNodesForCallUID[profileNode.callUID] = visitedNodes; |
- } else { |
- // The total time for this node has already been accounted for iff one of it's parents has already been visited. |
- // We can do this check in this style because we are traversing the tree in pre-order. |
- var parentCount = parentProfileNodes.length; |
- for (var parentIndex = 0; parentIndex < parentCount; ++parentIndex) { |
- if (visitedNodes[parentProfileNodes[parentIndex].UID]) { |
- totalTimeAccountedFor = true; |
- break; |
- } |
- } |
- } |
- |
- visitedNodes[profileNode.UID] = true; |
- |
- this._remainingNodeInfos.push({ ancestor:profileNode, focusNode:profileNode, totalTimeAccountedFor:totalTimeAccountedFor }); |
- } |
- |
- var children = profileNode.children; |
- if (children.length) { |
- profileNodeGroups.push(parentProfileNodes.concat([profileNode])) |
- profileNodeGroups.push(children); |
- } |
- } |
- } |
- |
- // Populate the top level nodes. |
- WebInspector.BottomUpProfileDataGridNode.prototype._populate.call(this); |
- |
- return this; |
-} |
- |
-WebInspector.BottomUpProfileDataGridTree.prototype = { |
- // When focusing, we keep the entire callstack up to this ancestor. |
- focus: function(/*ProfileDataGridNode*/ profileDataGridNode) |
- { |
- if (!profileDataGridNode) |
- return; |
- |
- this._save(); |
- |
- var currentNode = profileDataGridNode; |
- var focusNode = profileDataGridNode; |
- |
- while (currentNode.parent && (currentNode instanceof WebInspector.ProfileDataGridNode)) { |
- currentNode._takePropertiesFromProfileDataGridNode(profileDataGridNode); |
- |
- focusNode = currentNode; |
- currentNode = currentNode.parent; |
- |
- if (currentNode instanceof WebInspector.ProfileDataGridNode) |
- currentNode._keepOnlyChild(focusNode); |
- } |
- |
- this.children = [focusNode]; |
- this.totalTime = profileDataGridNode.totalTime; |
- }, |
- |
- exclude: function(/*ProfileDataGridNode*/ profileDataGridNode) |
- { |
- if (!profileDataGridNode) |
- return; |
- |
- this._save(); |
- |
- var excludedCallUID = profileDataGridNode.callUID; |
- var excludedTopLevelChild = this.childrenByCallUID[excludedCallUID]; |
- |
- // If we have a top level node that is excluded, get rid of it completely (not keeping children), |
- // since bottom up data relies entirely on the root node. |
- if (excludedTopLevelChild) |
- this.children.remove(excludedTopLevelChild); |
- |
- var children = this.children; |
- var count = children.length; |
- |
- for (var index = 0; index < count; ++index) |
- children[index]._exclude(excludedCallUID); |
- |
- if (this.lastComparator) |
- this.sort(this.lastComparator, true); |
- }, |
- |
- _sharedPopulate: WebInspector.BottomUpProfileDataGridNode.prototype._sharedPopulate |
-} |
- |
-WebInspector.BottomUpProfileDataGridTree.prototype.__proto__ = WebInspector.ProfileDataGridTree.prototype; |
- |