OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 | |
6 /** | |
7 * @fileoverview TimelineView visualizes GPU_TRACE events using the | |
8 * gpu.Timeline component. | |
9 */ | |
10 cr.define('gpu', function() { | |
11 function tsRound(ts) { | |
12 return Math.round(ts * 1000.0) / 1000.0; | |
13 } | |
14 function getPadding(text, width) { | |
15 width = width || 0; | |
16 | |
17 if (typeof text != 'string') | |
18 text = String(text); | |
19 | |
20 if (text.length >= width) | |
21 return ''; | |
22 | |
23 var pad = ''; | |
24 for (var i = 0; i < width - text.length; i++) | |
25 pad += ' '; | |
26 return pad; | |
27 } | |
28 | |
29 function leftAlign(text, width) { | |
30 return text + getPadding(text, width); | |
31 } | |
32 | |
33 function rightAlign(text, width) { | |
34 return getPadding(text, width) + text; | |
35 } | |
36 | |
37 /** | |
38 * TimelineView | |
39 * @constructor | |
40 * @extends {HTMLDivElement} | |
41 */ | |
42 TimelineView = cr.ui.define('div'); | |
43 | |
44 TimelineView.prototype = { | |
45 __proto__: HTMLDivElement.prototype, | |
46 | |
47 decorate: function() { | |
48 this.className = 'timeline-view'; | |
49 | |
50 this.timelineContainer_ = document.createElement('div'); | |
51 this.timelineContainer_.className = 'timeline-container'; | |
52 | |
53 var summaryContainer_ = document.createElement('div'); | |
54 summaryContainer_.className = 'summary-container'; | |
55 | |
56 this.summaryEl_ = document.createElement('pre'); | |
57 this.summaryEl_.className = 'summary'; | |
58 | |
59 summaryContainer_.appendChild(this.summaryEl_); | |
60 this.appendChild(this.timelineContainer_); | |
61 this.appendChild(summaryContainer_); | |
62 | |
63 this.onSelectionChangedBoundToThis_ = this.onSelectionChanged_.bind(this); | |
64 }, | |
65 | |
66 set traceEvents(traceEvents) { | |
67 console.log('TimelineView.refresh'); | |
68 this.timelineModel_ = new gpu.TimelineModel(traceEvents); | |
69 | |
70 // remove old timeline | |
71 this.timelineContainer_.textContent = ''; | |
72 | |
73 // create new timeline if needed | |
74 if (traceEvents.length) { | |
75 this.timeline_ = new gpu.Timeline(); | |
76 this.timeline_.model = this.timelineModel_; | |
77 this.timelineContainer_.appendChild(this.timeline_); | |
78 this.timeline_.onResize(); | |
79 this.timeline_.addEventListener('selectionChange', | |
80 this.onSelectionChangedBoundToThis_); | |
81 this.onSelectionChanged_(); | |
82 } else { | |
83 this.timeline_ = null; | |
84 } | |
85 }, | |
86 | |
87 onSelectionChanged_: function(e) { | |
88 console.log('selection changed'); | |
89 var timeline = this.timeline_; | |
90 var selection = timeline.selection; | |
91 if (!selection.length) { | |
92 var oldScrollTop = this.timelineContainer_.scrollTop; | |
93 this.summaryEl_.textContent = timeline.keyHelp; | |
94 this.timelineContainer_.scrollTop = oldScrollTop; | |
95 return; | |
96 } | |
97 | |
98 var text = ''; | |
99 if (selection.length == 1) { | |
100 var c0Width = 10; | |
101 var slice = selection[0].slice; | |
102 text = 'Selected item:\n'; | |
103 text += leftAlign('Title', c0Width) + ': ' + slice.title + '\n'; | |
104 text += leftAlign('Start', c0Width) + ': ' + | |
105 tsRound(slice.start) + ' ms\n'; | |
106 text += leftAlign('Duration', c0Width) + ': ' + | |
107 tsRound(slice.duration) + ' ms\n'; | |
108 | |
109 var n = 0; | |
110 for (var argName in slice.args) { | |
111 n += 1; | |
112 } | |
113 if (n > 0) { | |
114 text += leftAlign('Args', c0Width) + ':\n'; | |
115 for (var argName in slice.args) { | |
116 var argVal = slice.args[argName]; | |
117 text += leftAlign(' ' + argName, c0Width) + ': ' + argVal + '\n'; | |
118 } | |
119 } | |
120 } else { | |
121 var c0Width = 55; | |
122 var c1Width = 12; | |
123 var c2Width = 5; | |
124 text = 'Selection summary:\n'; | |
125 var tsLo = Math.min.apply(Math, selection.map( | |
126 function(s) {return s.slice.start;})); | |
127 var tsHi = Math.max.apply(Math, selection.map( | |
128 function(s) {return s.slice.end;})); | |
129 | |
130 // compute total selection duration | |
131 var titles = selection.map(function(i) { return i.slice.title; }); | |
132 | |
133 var slicesByTitle = {}; | |
134 for (var i = 0; i < selection.length; i++) { | |
135 var slice = selection[i].slice; | |
136 if (!slicesByTitle[slice.title]) | |
137 slicesByTitle[slice.title] = { | |
138 slices: [] | |
139 }; | |
140 slicesByTitle[slice.title].slices.push(slice); | |
141 } | |
142 var totalDuration = 0; | |
143 for (var sliceGroupTitle in slicesByTitle) { | |
144 var sliceGroup = slicesByTitle[sliceGroupTitle]; | |
145 var duration = 0; | |
146 for (i = 0; i < sliceGroup.slices.length; i++) | |
147 duration += sliceGroup.slices[i].duration; | |
148 totalDuration += duration; | |
149 | |
150 text += ' ' + | |
151 leftAlign(sliceGroupTitle, c0Width) + ': ' + | |
152 rightAlign(tsRound(duration) + 'ms', c1Width) + ' ' + | |
153 rightAlign(String(sliceGroup.slices.length), c2Width) + | |
154 ' occurrences' + '\n'; | |
155 } | |
156 | |
157 text += leftAlign('*Totals', c0Width) + ' : ' + | |
158 rightAlign(tsRound(totalDuration) + 'ms', c1Width) + ' ' + | |
159 rightAlign(String(selection.length), c2Width) + ' occurrences' + | |
160 '\n'; | |
161 | |
162 text += '\n'; | |
163 | |
164 text += leftAlign('Selection start', c0Width) + ' : ' + | |
165 rightAlign(tsRound(tsLo) + 'ms', c1Width) + | |
166 '\n'; | |
167 text += leftAlign('Selection extent', c0Width) + ' : ' + | |
168 rightAlign(tsRound(tsHi - tsLo) + 'ms', c1Width) + | |
169 '\n'; | |
170 } | |
171 | |
172 // done | |
173 var oldScrollTop = this.timelineContainer_.scrollTop; | |
174 this.summaryEl_.textContent = text; | |
175 this.timelineContainer_.scrollTop = oldScrollTop; | |
176 } | |
177 }; | |
178 | |
179 return { | |
180 TimelineView: TimelineView | |
181 }; | |
182 }); | |
OLD | NEW |