Index: chrome_frame/tools/test/reference_build/chrome/resources/inspector/BottomUpProfileDataGridTree.js |
=================================================================== |
--- chrome_frame/tools/test/reference_build/chrome/resources/inspector/BottomUpProfileDataGridTree.js (revision 0) |
+++ chrome_frame/tools/test/reference_build/chrome/resources/inspector/BottomUpProfileDataGridTree.js (revision 0) |
@@ -0,0 +1,252 @@ |
+/* |
+ * 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.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); |
+ } |
+} |
+ |
+WebInspector.BottomUpProfileDataGridTree.prototype.__proto__ = WebInspector.ProfileDataGridTree.prototype; |
+ |
+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); |
+ }, |
+ |
+ _populate: function(event) |
+ { |
+ 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; |
+ |
+ if (this.removeEventListener) |
+ this.removeEventListener("populate", this._populate, this); |
+ } |
+} |
+ |
+WebInspector.BottomUpProfileDataGridNode.prototype.__proto__ = WebInspector.ProfileDataGridNode.prototype; |