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

« back to all changes in this revision

Viewing changes to Source/WebCore/inspector/front-end/ProfileDataGridTree.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
/**
 
27
 * @constructor
 
28
 * @extends {WebInspector.DataGridNode}
 
29
 */
 
30
WebInspector.ProfileDataGridNode = function(profileView, profileNode, owningTree, hasChildren)
 
31
{
 
32
    this.profileView = profileView;
 
33
    this.profileNode = profileNode;
 
34
 
 
35
    WebInspector.DataGridNode.call(this, null, hasChildren);
 
36
 
 
37
    this.addEventListener("populate", this._populate, this);
 
38
 
 
39
    this.tree = owningTree;
 
40
 
 
41
    this.childrenByCallUID = {};
 
42
    this.lastComparator = null;
 
43
 
 
44
    this.callUID = profileNode.callUID;
 
45
    this.selfTime = profileNode.selfTime;
 
46
    this.totalTime = profileNode.totalTime;
 
47
    this.functionName = profileNode.functionName;
 
48
    this.numberOfCalls = profileNode.numberOfCalls;
 
49
    this.url = profileNode.url;
 
50
}
 
51
 
 
52
WebInspector.ProfileDataGridNode.prototype = {
 
53
    get data()
 
54
    {
 
55
        function formatMilliseconds(time)
 
56
        {
 
57
            return Number.secondsToString(time / 1000, !Capabilities.samplingCPUProfiler);
 
58
        }
 
59
 
 
60
        var data = {};
 
61
 
 
62
        data["function"] = this.functionName;
 
63
        data["calls"] = this.numberOfCalls;
 
64
 
 
65
        if (this.profileView.showSelfTimeAsPercent.get())
 
66
            data["self"] = WebInspector.UIString("%.2f%", this.selfPercent);
 
67
        else
 
68
            data["self"] = formatMilliseconds(this.selfTime);
 
69
 
 
70
        if (this.profileView.showTotalTimeAsPercent.get())
 
71
            data["total"] = WebInspector.UIString("%.2f%", this.totalPercent);
 
72
        else
 
73
            data["total"] = formatMilliseconds(this.totalTime);
 
74
 
 
75
        if (this.profileView.showAverageTimeAsPercent.get())
 
76
            data["average"] = WebInspector.UIString("%.2f%", this.averagePercent);
 
77
        else
 
78
            data["average"] = formatMilliseconds(this.averageTime);
 
79
 
 
80
        return data;
 
81
    },
 
82
 
 
83
    createCell: function(columnIdentifier)
 
84
    {
 
85
        var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
 
86
 
 
87
        if (columnIdentifier === "self" && this._searchMatchedSelfColumn)
 
88
            cell.addStyleClass("highlight");
 
89
        else if (columnIdentifier === "total" && this._searchMatchedTotalColumn)
 
90
            cell.addStyleClass("highlight");
 
91
        else if (columnIdentifier === "average" && this._searchMatchedAverageColumn)
 
92
            cell.addStyleClass("highlight");
 
93
        else if (columnIdentifier === "calls" && this._searchMatchedCallsColumn)
 
94
            cell.addStyleClass("highlight");
 
95
 
 
96
        if (columnIdentifier !== "function")
 
97
            return cell;
 
98
 
 
99
        if (this.profileNode._searchMatchedFunctionColumn)
 
100
            cell.addStyleClass("highlight");
 
101
 
 
102
        if (this.profileNode.url) {
 
103
            // FIXME(62725): profileNode should reference a debugger location.
 
104
            var lineNumber = this.profileNode.lineNumber ? this.profileNode.lineNumber - 1 : 0;
 
105
            var urlElement = this.profileView._linkifier.linkifyLocation(this.profileNode.url, lineNumber, 0, "profile-node-file");
 
106
            urlElement.style.maxWidth = "75%";
 
107
            cell.insertBefore(urlElement, cell.firstChild);
 
108
        }
 
109
 
 
110
        return cell;
 
111
    },
 
112
 
 
113
    select: function(supressSelectedEvent)
 
114
    {
 
115
        WebInspector.DataGridNode.prototype.select.call(this, supressSelectedEvent);
 
116
        this.profileView._dataGridNodeSelected(this);
 
117
    },
 
118
 
 
119
    deselect: function(supressDeselectedEvent)
 
120
    {
 
121
        WebInspector.DataGridNode.prototype.deselect.call(this, supressDeselectedEvent);
 
122
        this.profileView._dataGridNodeDeselected(this);
 
123
    },
 
124
 
 
125
    sort: function(/*Function*/ comparator, /*Boolean*/ force)
 
126
    {
 
127
        var gridNodeGroups = [[this]];
 
128
 
 
129
        for (var gridNodeGroupIndex = 0; gridNodeGroupIndex < gridNodeGroups.length; ++gridNodeGroupIndex) {
 
130
            var gridNodes = gridNodeGroups[gridNodeGroupIndex];
 
131
            var count = gridNodes.length;
 
132
 
 
133
            for (var index = 0; index < count; ++index) {
 
134
                var gridNode = gridNodes[index];
 
135
 
 
136
                // If the grid node is collapsed, then don't sort children (save operation for later).
 
137
                // If the grid node has the same sorting as previously, then there is no point in sorting it again.
 
138
                if (!force && (!gridNode.expanded || gridNode.lastComparator === comparator)) {
 
139
                    if (gridNode.children.length)
 
140
                        gridNode.shouldRefreshChildren = true;
 
141
                    continue;
 
142
                }
 
143
 
 
144
                gridNode.lastComparator = comparator;
 
145
 
 
146
                var children = gridNode.children;
 
147
                var childCount = children.length;
 
148
 
 
149
                if (childCount) {
 
150
                    children.sort(comparator);
 
151
 
 
152
                    for (var childIndex = 0; childIndex < childCount; ++childIndex)
 
153
                        children[childIndex]._recalculateSiblings(childIndex);
 
154
 
 
155
                    gridNodeGroups.push(children);
 
156
                }
 
157
            }
 
158
        }
 
159
    },
 
160
 
 
161
    insertChild: function(/*ProfileDataGridNode*/ profileDataGridNode, index)
 
162
    {
 
163
        WebInspector.DataGridNode.prototype.insertChild.call(this, profileDataGridNode, index);
 
164
 
 
165
        this.childrenByCallUID[profileDataGridNode.callUID] = profileDataGridNode;
 
166
    },
 
167
 
 
168
    removeChild: function(/*ProfileDataGridNode*/ profileDataGridNode)
 
169
    {
 
170
        WebInspector.DataGridNode.prototype.removeChild.call(this, profileDataGridNode);
 
171
 
 
172
        delete this.childrenByCallUID[profileDataGridNode.callUID];
 
173
    },
 
174
 
 
175
    removeChildren: function(/*ProfileDataGridNode*/ profileDataGridNode)
 
176
    {
 
177
        WebInspector.DataGridNode.prototype.removeChildren.call(this);
 
178
 
 
179
        this.childrenByCallUID = {};
 
180
    },
 
181
 
 
182
    findChild: function(/*Node*/ node)
 
183
    {
 
184
        if (!node)
 
185
            return null;
 
186
        return this.childrenByCallUID[node.callUID];
 
187
    },
 
188
 
 
189
    get averageTime()
 
190
    {
 
191
        return this.selfTime / Math.max(1, this.numberOfCalls);
 
192
    },
 
193
 
 
194
    get averagePercent()
 
195
    {
 
196
        return this.averageTime / this.tree.totalTime * 100.0;
 
197
    },
 
198
 
 
199
    get selfPercent()
 
200
    {
 
201
        return this.selfTime / this.tree.totalTime * 100.0;
 
202
    },
 
203
 
 
204
    get totalPercent()
 
205
    {
 
206
        return this.totalTime / this.tree.totalTime * 100.0;
 
207
    },
 
208
 
 
209
    get _parent()
 
210
    {
 
211
        return this.parent !== this.dataGrid ? this.parent : this.tree;
 
212
    },
 
213
 
 
214
    _populate: function()
 
215
    {
 
216
        this._sharedPopulate();
 
217
 
 
218
        if (this._parent) {
 
219
            var currentComparator = this._parent.lastComparator;
 
220
 
 
221
            if (currentComparator)
 
222
                this.sort(currentComparator, true);
 
223
        }
 
224
 
 
225
        if (this.removeEventListener)
 
226
            this.removeEventListener("populate", this._populate, this);
 
227
    },
 
228
 
 
229
    // When focusing and collapsing we modify lots of nodes in the tree.
 
230
    // This allows us to restore them all to their original state when we revert.
 
231
    _save: function()
 
232
    {
 
233
        if (this._savedChildren)
 
234
            return;
 
235
 
 
236
        this._savedSelfTime = this.selfTime;
 
237
        this._savedTotalTime = this.totalTime;
 
238
        this._savedNumberOfCalls = this.numberOfCalls;
 
239
 
 
240
        this._savedChildren = this.children.slice();
 
241
    },
 
242
 
 
243
    // When focusing and collapsing we modify lots of nodes in the tree.
 
244
    // This allows us to restore them all to their original state when we revert.
 
245
    _restore: function()
 
246
    {
 
247
        if (!this._savedChildren)
 
248
            return;
 
249
 
 
250
        this.selfTime = this._savedSelfTime;
 
251
        this.totalTime = this._savedTotalTime;
 
252
        this.numberOfCalls = this._savedNumberOfCalls;
 
253
 
 
254
        this.removeChildren();
 
255
 
 
256
        var children = this._savedChildren;
 
257
        var count = children.length;
 
258
 
 
259
        for (var index = 0; index < count; ++index) {
 
260
            children[index]._restore();
 
261
            this.appendChild(children[index]);
 
262
        }
 
263
    },
 
264
 
 
265
    _merge: function(child, shouldAbsorb)
 
266
    {
 
267
        this.selfTime += child.selfTime;
 
268
 
 
269
        if (!shouldAbsorb) {
 
270
            this.totalTime += child.totalTime;
 
271
            this.numberOfCalls += child.numberOfCalls;
 
272
        }
 
273
 
 
274
        var children = this.children.slice();
 
275
 
 
276
        this.removeChildren();
 
277
 
 
278
        var count = children.length;
 
279
 
 
280
        for (var index = 0; index < count; ++index) {
 
281
            if (!shouldAbsorb || children[index] !== child)
 
282
                this.appendChild(children[index]);
 
283
        }
 
284
 
 
285
        children = child.children.slice();
 
286
        count = children.length;
 
287
 
 
288
        for (var index = 0; index < count; ++index) {
 
289
            var orphanedChild = children[index],
 
290
                existingChild = this.childrenByCallUID[orphanedChild.callUID];
 
291
 
 
292
            if (existingChild)
 
293
                existingChild._merge(orphanedChild, false);
 
294
            else
 
295
                this.appendChild(orphanedChild);
 
296
        }
 
297
    },
 
298
 
 
299
    __proto__: WebInspector.DataGridNode.prototype
 
300
}
 
301
 
 
302
/**
 
303
 * @constructor
 
304
 */
 
305
WebInspector.ProfileDataGridTree = function(profileView, profileNode)
 
306
{
 
307
    this.tree = this;
 
308
    this.children = [];
 
309
 
 
310
    this.profileView = profileView;
 
311
 
 
312
    this.totalTime = profileNode.totalTime;
 
313
    this.lastComparator = null;
 
314
 
 
315
    this.childrenByCallUID = {};
 
316
}
 
317
 
 
318
WebInspector.ProfileDataGridTree.prototype = {
 
319
    get expanded()
 
320
    {
 
321
        return true;
 
322
    },
 
323
 
 
324
    appendChild: function(child)
 
325
    {
 
326
        this.insertChild(child, this.children.length);
 
327
    },
 
328
 
 
329
    insertChild: function(child, index)
 
330
    {
 
331
        this.children.splice(index, 0, child);
 
332
        this.childrenByCallUID[child.callUID] = child;
 
333
    },
 
334
 
 
335
    removeChildren: function()
 
336
    {
 
337
        this.children = [];
 
338
        this.childrenByCallUID = {};
 
339
    },
 
340
 
 
341
    findChild: WebInspector.ProfileDataGridNode.prototype.findChild,
 
342
    sort: WebInspector.ProfileDataGridNode.prototype.sort,
 
343
 
 
344
    _save: function()
 
345
    {
 
346
        if (this._savedChildren)
 
347
            return;
 
348
 
 
349
        this._savedTotalTime = this.totalTime;
 
350
        this._savedChildren = this.children.slice();
 
351
    },
 
352
 
 
353
    restore: function()
 
354
    {
 
355
        if (!this._savedChildren)
 
356
            return;
 
357
 
 
358
        this.children = this._savedChildren;
 
359
        this.totalTime = this._savedTotalTime;
 
360
 
 
361
        var children = this.children;
 
362
        var count = children.length;
 
363
 
 
364
        for (var index = 0; index < count; ++index)
 
365
            children[index]._restore();
 
366
 
 
367
        this._savedChildren = null;
 
368
    }
 
369
}
 
370
 
 
371
WebInspector.ProfileDataGridTree.propertyComparators = [{}, {}];
 
372
 
 
373
WebInspector.ProfileDataGridTree.propertyComparator = function(/*String*/ property, /*Boolean*/ isAscending)
 
374
{
 
375
    var comparator = WebInspector.ProfileDataGridTree.propertyComparators[(isAscending ? 1 : 0)][property];
 
376
 
 
377
    if (!comparator) {
 
378
        if (isAscending) {
 
379
            comparator = function(lhs, rhs)
 
380
            {
 
381
                if (lhs[property] < rhs[property])
 
382
                    return -1;
 
383
 
 
384
                if (lhs[property] > rhs[property])
 
385
                    return 1;
 
386
 
 
387
                return 0;
 
388
            }
 
389
        } else {
 
390
            comparator = function(lhs, rhs)
 
391
            {
 
392
                if (lhs[property] > rhs[property])
 
393
                    return -1;
 
394
 
 
395
                if (lhs[property] < rhs[property])
 
396
                    return 1;
 
397
 
 
398
                return 0;
 
399
            }
 
400
        }
 
401
 
 
402
        WebInspector.ProfileDataGridTree.propertyComparators[(isAscending ? 1 : 0)][property] = comparator;
 
403
    }
 
404
 
 
405
    return comparator;
 
406
}