~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/inspector/front-end/BottomUpProfileDataGridTree.js

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 each 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
/**
 
33
 * @constructor
 
34
 * @extends {WebInspector.ProfileDataGridNode}
 
35
 */
 
36
WebInspector.BottomUpProfileDataGridNode = function(/*ProfileView*/ profileView, /*ProfileNode*/ profileNode, /*BottomUpProfileDataGridTree*/ owningTree)
 
37
{
 
38
    WebInspector.ProfileDataGridNode.call(this, profileView, profileNode, owningTree, this._willHaveChildren(profileNode));
 
39
 
 
40
    this._remainingNodeInfos = [];
 
41
}
 
42
 
 
43
WebInspector.BottomUpProfileDataGridNode.prototype = {
 
44
    _takePropertiesFromProfileDataGridNode: function(/*ProfileDataGridNode*/ profileDataGridNode)
 
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
    _restore: function()
 
82
    {
 
83
        WebInspector.ProfileDataGridNode.prototype._restore();
 
84
 
 
85
        if (!this.children.length)
 
86
            this.hasChildren = this._willHaveChildren(this.profileNode);
 
87
    },
 
88
 
 
89
    _merge: function(/*ProfileDataGridNode*/ child, /*Boolean*/ shouldAbsorb)
 
90
    {
 
91
        this.selfTime -= child.selfTime;
 
92
 
 
93
        WebInspector.ProfileDataGridNode.prototype._merge.call(this, child, shouldAbsorb);
 
94
    },
 
95
 
 
96
    _sharedPopulate: function()
 
97
    {
 
98
        var remainingNodeInfos = this._remainingNodeInfos;
 
99
        var count = remainingNodeInfos.length;
 
100
 
 
101
        for (var index = 0; index < count; ++index) {
 
102
            var nodeInfo = remainingNodeInfos[index];
 
103
            var ancestor = nodeInfo.ancestor;
 
104
            var focusNode = nodeInfo.focusNode;
 
105
            var child = this.findChild(ancestor);
 
106
 
 
107
            // If we already have this child, then merge the data together.
 
108
            if (child) {
 
109
                var totalTimeAccountedFor = nodeInfo.totalTimeAccountedFor;
 
110
 
 
111
                child.selfTime += focusNode.selfTime;
 
112
                child.numberOfCalls += focusNode.numberOfCalls;
 
113
 
 
114
                if (!totalTimeAccountedFor)
 
115
                    child.totalTime += focusNode.totalTime;
 
116
            } else {
 
117
                // If not, add it as a true ancestor.
 
118
                // In heavy mode, we take our visual identity from ancestor node...
 
119
                child = new WebInspector.BottomUpProfileDataGridNode(this.profileView, ancestor, this.tree);
 
120
 
 
121
                if (ancestor !== focusNode) {
 
122
                    // but the actual statistics from the "root" node (bottom of the callstack).
 
123
                    child.selfTime = focusNode.selfTime;
 
124
                    child.totalTime = focusNode.totalTime;
 
125
                    child.numberOfCalls = focusNode.numberOfCalls;
 
126
                }
 
127
 
 
128
                this.appendChild(child);
 
129
            }
 
130
 
 
131
            var parent = ancestor.parent;
 
132
            if (parent && parent.parent) {
 
133
                nodeInfo.ancestor = parent;
 
134
                child._remainingNodeInfos.push(nodeInfo);
 
135
            }
 
136
        }
 
137
 
 
138
        delete this._remainingNodeInfos;
 
139
    },
 
140
 
 
141
    _willHaveChildren: function(profileNode)
 
142
    {
 
143
        // In bottom up mode, our parents are our children since we display an inverted tree.
 
144
        // However, we don't want to show the very top parent since it is redundant.
 
145
        return !!(profileNode.parent && profileNode.parent.parent);
 
146
    },
 
147
 
 
148
    __proto__: WebInspector.ProfileDataGridNode.prototype
 
149
}
 
150
 
 
151
/**
 
152
 * @constructor
 
153
 * @extends {WebInspector.ProfileDataGridTree}
 
154
 */
 
155
WebInspector.BottomUpProfileDataGridTree = function(/*ProfileView*/ aProfileView, /*ProfileNode*/ aProfileNode)
 
156
{
 
157
    WebInspector.ProfileDataGridTree.call(this, aProfileView, aProfileNode);
 
158
 
 
159
    // Iterate each node in pre-order.
 
160
    var profileNodeUIDs = 0;
 
161
    var profileNodeGroups = [[], [aProfileNode]];
 
162
    var visitedProfileNodesForCallUID = {};
 
163
 
 
164
    this._remainingNodeInfos = [];
 
165
 
 
166
    for (var profileNodeGroupIndex = 0; profileNodeGroupIndex < profileNodeGroups.length; ++profileNodeGroupIndex) {
 
167
        var parentProfileNodes = profileNodeGroups[profileNodeGroupIndex];
 
168
        var profileNodes = profileNodeGroups[++profileNodeGroupIndex];
 
169
        var count = profileNodes.length;
 
170
 
 
171
        for (var index = 0; index < count; ++index) {
 
172
            var profileNode = profileNodes[index];
 
173
 
 
174
            if (!profileNode.UID)
 
175
                profileNode.UID = ++profileNodeUIDs;
 
176
 
 
177
            if (profileNode.head && profileNode !== profileNode.head) {
 
178
                // The total time of this ancestor is accounted for if we're in any form of recursive cycle.
 
179
                var visitedNodes = visitedProfileNodesForCallUID[profileNode.callUID];
 
180
                var totalTimeAccountedFor = false;
 
181
 
 
182
                if (!visitedNodes) {
 
183
                    visitedNodes = {}
 
184
                    visitedProfileNodesForCallUID[profileNode.callUID] = visitedNodes;
 
185
                } else {
 
186
                    // The total time for this node has already been accounted for iff one of it's parents has already been visited.
 
187
                    // We can do this check in this style because we are traversing the tree in pre-order.
 
188
                    var parentCount = parentProfileNodes.length;
 
189
                    for (var parentIndex = 0; parentIndex < parentCount; ++parentIndex) {
 
190
                        if (visitedNodes[parentProfileNodes[parentIndex].UID]) {
 
191
                            totalTimeAccountedFor = true;
 
192
                            break;
 
193
                        }
 
194
                    }
 
195
                }
 
196
 
 
197
                visitedNodes[profileNode.UID] = true;
 
198
 
 
199
                this._remainingNodeInfos.push({ ancestor:profileNode, focusNode:profileNode, totalTimeAccountedFor:totalTimeAccountedFor });
 
200
            }
 
201
 
 
202
            var children = profileNode.children;
 
203
            if (children.length) {
 
204
                profileNodeGroups.push(parentProfileNodes.concat([profileNode]))
 
205
                profileNodeGroups.push(children);
 
206
            }
 
207
        }
 
208
    }
 
209
 
 
210
    // Populate the top level nodes.
 
211
    var any = /** @type{*} */this;
 
212
    var node = /** @type{WebInspector.ProfileDataGridNode} */any;
 
213
    WebInspector.BottomUpProfileDataGridNode.prototype._populate.call(node);
 
214
 
 
215
    return this;
 
216
}
 
217
 
 
218
WebInspector.BottomUpProfileDataGridTree.prototype = {
 
219
    // When focusing, we keep the entire callstack up to this ancestor.
 
220
    focus: function(/*ProfileDataGridNode*/ profileDataGridNode)
 
221
    {
 
222
        if (!profileDataGridNode)
 
223
            return;
 
224
 
 
225
        this._save();
 
226
 
 
227
        var currentNode = profileDataGridNode;
 
228
        var focusNode = profileDataGridNode;
 
229
 
 
230
        while (currentNode.parent && (currentNode instanceof WebInspector.ProfileDataGridNode)) {
 
231
            currentNode._takePropertiesFromProfileDataGridNode(profileDataGridNode);
 
232
 
 
233
            focusNode = currentNode;
 
234
            currentNode = currentNode.parent;
 
235
 
 
236
            if (currentNode instanceof WebInspector.ProfileDataGridNode)
 
237
                currentNode._keepOnlyChild(focusNode);
 
238
        }
 
239
 
 
240
        this.children = [focusNode];
 
241
        this.totalTime = profileDataGridNode.totalTime;
 
242
    },
 
243
 
 
244
    exclude: function(/*ProfileDataGridNode*/ profileDataGridNode)
 
245
    {
 
246
        if (!profileDataGridNode)
 
247
            return;
 
248
 
 
249
        this._save();
 
250
 
 
251
        var excludedCallUID = profileDataGridNode.callUID;
 
252
        var excludedTopLevelChild = this.childrenByCallUID[excludedCallUID];
 
253
 
 
254
        // If we have a top level node that is excluded, get rid of it completely (not keeping children),
 
255
        // since bottom up data relies entirely on the root node.
 
256
        if (excludedTopLevelChild)
 
257
            this.children.remove(excludedTopLevelChild);
 
258
 
 
259
        var children = this.children;
 
260
        var count = children.length;
 
261
 
 
262
        for (var index = 0; index < count; ++index)
 
263
            children[index]._exclude(excludedCallUID);
 
264
 
 
265
        if (this.lastComparator)
 
266
            this.sort(this.lastComparator, true);
 
267
    },
 
268
 
 
269
    _sharedPopulate: WebInspector.BottomUpProfileDataGridNode.prototype._sharedPopulate,
 
270
 
 
271
    __proto__: WebInspector.ProfileDataGridTree.prototype
 
272
}