Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(67)

Side by Side Diff: chrome/browser/resources/tracing/timeline_view.js

Issue 10161025: Allow about:tracing Counters to be selected (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixen. Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 'use strict'; 5 'use strict';
6 6
7 /** 7 /**
8 * @fileoverview TimelineView visualizes TRACE_EVENT events using the 8 * @fileoverview TimelineView visualizes TRACE_EVENT events using the
9 * tracing.Timeline component and adds in selection summary and control buttons. 9 * tracing.Timeline component and adds in selection summary and control buttons.
10 */ 10 */
11 cr.define('tracing', function() { 11 cr.define('tracing', function() {
12 function tsRound(ts) {
13 return Math.round(ts * 1000.0) / 1000.0;
14 }
15 function getPadding(text, width) {
16 width = width || 0;
17
18 if (typeof text != 'string')
19 text = String(text);
20
21 if (text.length >= width)
22 return '';
23
24 var pad = '';
25 for (var i = 0; i < width - text.length; i++)
26 pad += ' ';
27 return pad;
28 }
29
30 function leftAlign(text, width) {
31 return text + getPadding(text, width);
32 }
33
34 function rightAlign(text, width) {
35 return getPadding(text, width) + text;
36 }
37
38 /** 12 /**
39 * TimelineFindControl 13 * TimelineFindControl
40 * @constructor 14 * @constructor
41 * @extends {tracing.Overlay} 15 * @extends {tracing.Overlay}
42 */ 16 */
43 var TimelineFindControl = cr.ui.define('div'); 17 var TimelineFindControl = cr.ui.define('div');
44 18
45 TimelineFindControl.prototype = { 19 TimelineFindControl.prototype = {
46 __proto__: tracing.Overlay.prototype, 20 __proto__: tracing.Overlay.prototype,
47 21
48 decorate: function() { 22 decorate: function() {
49 tracing.Overlay.prototype.decorate.call(this); 23 tracing.Overlay.prototype.decorate.call(this);
50 24
51 this.className = 'timeline-find-control'; 25 this.className = 'timeline-find-control';
52 26
53 this.hitCountEl_ = document.createElement('span'); 27 this.hitCountEl_ = document.createElement('div');
54 this.hitCountEl_.className = 'hit-count-label'; 28 this.hitCountEl_.className = 'hit-count-label';
55 this.hitCountEl_.textContent = '1 of 7'; 29 this.hitCountEl_.textContent = '1 of 7';
56 30
57 var findPreviousBn = document.createElement('span'); 31 var findPreviousBn = document.createElement('div');
58 findPreviousBn.className = 'find-button find-previous'; 32 findPreviousBn.className = 'timeline-button find-previous';
59 findPreviousBn.textContent = '\u2190'; 33 findPreviousBn.textContent = '\u2190';
60 findPreviousBn.addEventListener('click', function() { 34 findPreviousBn.addEventListener('click', function() {
61 this.controller.findPrevious(); 35 this.controller.findPrevious();
62 this.updateHitCountEl_(); 36 this.updateHitCountEl_();
63 }.bind(this)); 37 }.bind(this));
64 38
65 var findNextBn = document.createElement('span'); 39 var findNextBn = document.createElement('div');
66 findNextBn.className = 'find-button find-next'; 40 findNextBn.className = 'timeline-button find-next';
67 findNextBn.textContent = '\u2192'; 41 findNextBn.textContent = '\u2192';
68 findNextBn.addEventListener('click', function() { 42 findNextBn.addEventListener('click', function() {
69 this.controller.findNext(); 43 this.controller.findNext();
70 this.updateHitCountEl_(); 44 this.updateHitCountEl_();
71 }.bind(this)); 45 }.bind(this));
72 46
73 // Filter input element. 47 // Filter input element.
74 this.filterEl_ = document.createElement('input'); 48 this.filterEl_ = document.createElement('input');
75 this.filterEl_.type = 'input'; 49 this.filterEl_.type = 'input';
76 50
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 this.hitCountEl_.textContent = '0 of 0'; 106 this.hitCountEl_.textContent = '0 of 0';
133 else 107 else
134 this.hitCountEl_.textContent = (i + 1) + ' of ' + n; 108 this.hitCountEl_.textContent = (i + 1) + ' of ' + n;
135 } 109 }
136 }; 110 };
137 111
138 function TimelineFindController() { 112 function TimelineFindController() {
139 this.timeline_ = undefined; 113 this.timeline_ = undefined;
140 this.model_ = undefined; 114 this.model_ = undefined;
141 this.filterText_ = ''; 115 this.filterText_ = '';
116 this.filterHits_ = new tracing.TimelineSelection();
142 this.filterHitsDirty_ = true; 117 this.filterHitsDirty_ = true;
143 this.currentHitIndex_ = 0; 118 this.currentHitIndex_ = 0;
144 }; 119 };
145 120
146 TimelineFindController.prototype = { 121 TimelineFindController.prototype = {
147 __proto__: Object.prototype, 122 __proto__: Object.prototype,
148 123
149 get timeline() { 124 get timeline() {
150 return this.timeline_; 125 return this.timeline_;
151 }, 126 },
(...skipping 13 matching lines...) Expand all
165 this.filterText_ = f; 140 this.filterText_ = f;
166 this.filterHitsDirty_ = true; 141 this.filterHitsDirty_ = true;
167 this.findNext(); 142 this.findNext();
168 }, 143 },
169 144
170 get filterHits() { 145 get filterHits() {
171 if (this.filterHitsDirty_) { 146 if (this.filterHitsDirty_) {
172 this.filterHitsDirty_ = false; 147 this.filterHitsDirty_ = false;
173 if (this.timeline_) { 148 if (this.timeline_) {
174 var filter = new tracing.TimelineFilter(this.filterText); 149 var filter = new tracing.TimelineFilter(this.filterText);
175 this.filterHits_ = this.timeline.findAllObjectsMatchingFilter(filter); 150 this.filterHits_.clear();
151 this.timeline.addAllObjectsMatchingFilterToSelection(
152 filter, this.filterHits_);
176 this.currentHitIndex_ = this.filterHits_.length - 1; 153 this.currentHitIndex_ = this.filterHits_.length - 1;
177 } else { 154 } else {
178 this.filterHits_ = []; 155 this.filterHits_.clear();
179 this.currentHitIndex_ = 0; 156 this.currentHitIndex_ = 0;
180 } 157 }
181 } 158 }
182 return this.filterHits_; 159 return this.filterHits_;
183 }, 160 },
184 161
185 get currentHitIndex() { 162 get currentHitIndex() {
186 return this.currentHitIndex_; 163 return this.currentHitIndex_;
187 }, 164 },
188 165
189 find_: function(dir) { 166 find_: function(dir) {
190 if (!this.timeline) 167 if (!this.timeline)
191 return; 168 return;
192 169
193 var N = this.filterHits.length; 170 var N = this.filterHits.length;
194 this.currentHitIndex_ = this.currentHitIndex_ + dir; 171 this.currentHitIndex_ = this.currentHitIndex_ + dir;
195 172
196 if (this.currentHitIndex_ < 0) this.currentHitIndex_ = N - 1; 173 if (this.currentHitIndex_ < 0) this.currentHitIndex_ = N - 1;
197 if (this.currentHitIndex_ >= N) this.currentHitIndex_ = 0; 174 if (this.currentHitIndex_ >= N) this.currentHitIndex_ = 0;
198 175
199 if (this.currentHitIndex_ < 0 || this.currentHitIndex_ >= N) { 176 if (this.currentHitIndex_ < 0 || this.currentHitIndex_ >= N) {
200 this.timeline.selection = []; 177 this.timeline.selection = new tracing.TimelineSelection();
201 return; 178 return;
202 } 179 }
203 180
204 var hit = this.filterHits[this.currentHitIndex_];
205
206 // We allow the zoom level to change on the first hit level. But, when 181 // We allow the zoom level to change on the first hit level. But, when
207 // then cycling through subsequent changes, restrict it to panning. 182 // then cycling through subsequent changes, restrict it to panning.
208 var zoomAllowed = this.currentHitIndex_ == 0; 183 var zoomAllowed = this.currentHitIndex_ == 0;
209 this.timeline.setSelectionAndMakeVisible([hit], zoomAllowed); 184 var subSelection = this.filterHits.subSelection(this.currentHitIndex_);
185 this.timeline.setSelectionAndMakeVisible(subSelection, zoomAllowed);
210 }, 186 },
211 187
212 findNext: function() { 188 findNext: function() {
213 this.find_(1); 189 this.find_(1);
214 }, 190 },
215 191
216 findPrevious: function() { 192 findPrevious: function() {
217 this.find_(-1); 193 this.find_(-1);
218 }, 194 },
219 }; 195 };
220 196
221 /** 197 /**
222 * TimelineView 198 * TimelineView
223 * @constructor 199 * @constructor
224 * @extends {HTMLDivElement} 200 * @extends {HTMLDivElement}
225 */ 201 */
226 var TimelineView = cr.ui.define('div'); 202 var TimelineView = cr.ui.define('div');
227 203
228 TimelineView.prototype = { 204 TimelineView.prototype = {
229 __proto__: HTMLDivElement.prototype, 205 __proto__: HTMLDivElement.prototype,
230 206
231 decorate: function() { 207 decorate: function() {
232 this.classList.add('timeline-view'); 208 this.classList.add('timeline-view');
233 209
234 // Create individual elements. 210 // Create individual elements.
235 this.titleEl_ = document.createElement('span'); 211 this.titleEl_ = document.createElement('div');
236 this.titleEl_.textContent = 'Tracing: '; 212 this.titleEl_.textContent = 'Tracing: ';
237 213
238 this.controlDiv_ = document.createElement('div'); 214 this.controlDiv_ = document.createElement('div');
239 this.controlDiv_.className = 'control'; 215 this.controlDiv_.className = 'control';
240 216
241 this.leftControlsEl_ = document.createElement('div'); 217 this.leftControlsEl_ = document.createElement('div');
218 this.leftControlsEl_.className = 'controls';
242 this.rightControlsEl_ = document.createElement('div'); 219 this.rightControlsEl_ = document.createElement('div');
220 this.rightControlsEl_.className = 'controls';
243 221
244 var spacingEl = document.createElement('div'); 222 var spacingEl = document.createElement('div');
245 spacingEl.className = 'spacer'; 223 spacingEl.className = 'spacer';
246 224
247 this.timelineContainer_ = document.createElement('div'); 225 this.timelineContainer_ = document.createElement('div');
248 this.timelineContainer_.className = 'timeline-container'; 226 this.timelineContainer_.className = 'timeline-container';
249 227
250 var summaryContainer_ = document.createElement('div'); 228 var analysisContainer_ = document.createElement('div');
251 summaryContainer_.className = 'summary-container'; 229 analysisContainer_.className = 'analysis-container';
252 230
253 this.summaryEl_ = document.createElement('pre'); 231 this.analysisEl_ = new tracing.TimelineAnalysisView();
254 this.summaryEl_.className = 'summary';
255 232
256 this.findCtl_ = new TimelineFindControl(); 233 this.findCtl_ = new TimelineFindControl();
257 this.findCtl_.controller = new TimelineFindController(); 234 this.findCtl_.controller = new TimelineFindController();
258 235
259 // Connect everything up. 236 // Connect everything up.
260 this.rightControls.appendChild(this.findCtl_); 237 this.rightControls.appendChild(this.findCtl_);
261 this.controlDiv_.appendChild(this.titleEl_); 238 this.controlDiv_.appendChild(this.titleEl_);
262 this.controlDiv_.appendChild(this.leftControlsEl_); 239 this.controlDiv_.appendChild(this.leftControlsEl_);
263 this.controlDiv_.appendChild(spacingEl); 240 this.controlDiv_.appendChild(spacingEl);
264 this.controlDiv_.appendChild(this.rightControlsEl_); 241 this.controlDiv_.appendChild(this.rightControlsEl_);
265 this.appendChild(this.controlDiv_); 242 this.appendChild(this.controlDiv_);
266 243
267 this.appendChild(this.timelineContainer_); 244 this.appendChild(this.timelineContainer_);
268 245
269 summaryContainer_.appendChild(this.summaryEl_); 246 analysisContainer_.appendChild(this.analysisEl_);
270 this.appendChild(summaryContainer_); 247 this.appendChild(analysisContainer_);
248
249 this.rightControls.appendChild(this.createHelpButton_());
271 250
272 // Bookkeeping. 251 // Bookkeeping.
273 this.onSelectionChangedBoundToThis_ = this.onSelectionChanged_.bind(this); 252 this.onSelectionChangedBoundToThis_ = this.onSelectionChanged_.bind(this);
274 document.addEventListener('keypress', this.onKeypress_.bind(this), true); 253 document.addEventListener('keypress', this.onKeypress_.bind(this), true);
275 }, 254 },
276 255
256 createHelpButton_: function() {
257 var dlg = new tracing.Overlay();
258 dlg.classList.add('timeline-view-help-overlay');
259
260 var showHelpEl = document.createElement('div');
261 showHelpEl.className = 'timeline-button timeline-view-help-button';
262 showHelpEl.textContent = '?';
263
264 var helpTextEl = document.createElement('div');
265 helpTextEl.style.whiteSpace = 'pre';
266 helpTextEl.style.fontFamily = 'monospace';
267
268 function onClick() {
269 dlg.visible = true;
270 helpTextEl.textContent = this.timeline_.keyHelp;
271 document.addEventListener('keydown', onKey, true);
272 }
273
274 function onKey(e) {
275 if (!dlg.visible)
276 return;
277
278 if (e.keyCode == 27 || e.keyCode == '?'.charCodeAt(0)) {
279 e.preventDefault();
280 document.removeEventListener('keydown', onKey);
281 dlg.visible = false;
282 }
283 }
284 showHelpEl.addEventListener('click', onClick.bind(this));
285
286 dlg.appendChild(helpTextEl);
287
288 return showHelpEl;
289 },
290
277 get leftControls() { 291 get leftControls() {
278 return this.leftControlsEl_; 292 return this.leftControlsEl_;
279 }, 293 },
280 294
281 get rightControls() { 295 get rightControls() {
282 return this.rightControlsEl_; 296 return this.rightControlsEl_;
283 }, 297 },
284 298
285 get title() { 299 get title() {
286 return this.titleEl_.textContent.substring( 300 return this.titleEl_.textContent.substring(
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 return true; 382 return true;
369 if (this.focusElement.tabIndex >= 0) 383 if (this.focusElement.tabIndex >= 0)
370 return document.activeElement == this.focusElement; 384 return document.activeElement == this.focusElement;
371 return true; 385 return true;
372 }, 386 },
373 387
374 onKeypress_: function(e) { 388 onKeypress_: function(e) {
375 if (!this.listenToKeys_) 389 if (!this.listenToKeys_)
376 return; 390 return;
377 391
378 if (event.keyCode == 47) { 392 if (event.keyCode == '/'.charCodeAt(0)) { // / key
379 this.findCtl_.focus(); 393 this.findCtl_.focus();
380 event.preventDefault(); 394 event.preventDefault();
381 return; 395 return;
396 } else if (e.keyCode == '?'.charCodeAt(0)) {
397 this.querySelector('.timeline-view-help-button').click();
398 e.preventDefault();
382 } 399 }
383 }, 400 },
384 401
385 beginFind: function() { 402 beginFind: function() {
386 if (this.findInProgress_) 403 if (this.findInProgress_)
387 return; 404 return;
388 this.findInProgress_ = true; 405 this.findInProgress_ = true;
389 var dlg = TimelineFindControl(); 406 var dlg = TimelineFindControl();
390 dlg.controller = new TimelineFindController(); 407 dlg.controller = new TimelineFindController();
391 dlg.controller.timeline = this.timeline; 408 dlg.controller.timeline = this.timeline;
392 dlg.visible = true; 409 dlg.visible = true;
393 dlg.addEventListener('close', function() { 410 dlg.addEventListener('close', function() {
394 this.findInProgress_ = false; 411 this.findInProgress_ = false;
395 }.bind(this)); 412 }.bind(this));
396 dlg.addEventListener('findNext', function() { 413 dlg.addEventListener('findNext', function() {
397 }); 414 });
398 dlg.addEventListener('findPrevious', function() { 415 dlg.addEventListener('findPrevious', function() {
399 }); 416 });
400 }, 417 },
401 418
402 onSelectionChanged_: function(e) { 419 onSelectionChanged_: function(e) {
403 var timeline = this.timeline_;
404 var selection = timeline.selection;
405 if (!selection.length) {
406 var oldScrollTop = this.timelineContainer_.scrollTop;
407 this.summaryEl_.textContent = timeline.keyHelp;
408 this.timelineContainer_.scrollTop = oldScrollTop;
409 return;
410 }
411
412 var text = '';
413 if (selection.length == 1) {
414 var c0Width = 14;
415 var slice = selection[0].slice;
416 text = 'Selected item:\n';
417 text += leftAlign('Title', c0Width) + ': ' + slice.title + '\n';
418 text += leftAlign('Start', c0Width) + ': ' +
419 tsRound(slice.start) + ' ms\n';
420 text += leftAlign('Duration', c0Width) + ': ' +
421 tsRound(slice.duration) + ' ms\n';
422 if (slice.durationInUserTime)
423 text += leftAlign('Duration (U)', c0Width) + ': ' +
424 tsRound(slice.durationInUserTime) + ' ms\n';
425
426 var n = 0;
427 for (var argName in slice.args) {
428 n += 1;
429 }
430 if (n > 0) {
431 text += leftAlign('Args', c0Width) + ':\n';
432 for (var argName in slice.args) {
433 var argVal = slice.args[argName];
434 text += leftAlign(' ' + argName, c0Width) + ': ' + argVal + '\n';
435 }
436 }
437 } else {
438 var c0Width = 55;
439 var c1Width = 12;
440 var c2Width = 5;
441 text = 'Selection summary:\n';
442 var tsLo = Math.min.apply(Math, selection.map(
443 function(s) {return s.slice.start;}));
444 var tsHi = Math.max.apply(Math, selection.map(
445 function(s) {return s.slice.end;}));
446
447 // compute total selection duration
448 var titles = selection.map(function(i) { return i.slice.title; });
449
450 var slicesByTitle = {};
451 for (var i = 0; i < selection.length; i++) {
452 var slice = selection[i].slice;
453 if (!slicesByTitle[slice.title])
454 slicesByTitle[slice.title] = {
455 slices: []
456 };
457 slicesByTitle[slice.title].slices.push(slice);
458 }
459 var totalDuration = 0;
460 for (var sliceGroupTitle in slicesByTitle) {
461 var sliceGroup = slicesByTitle[sliceGroupTitle];
462 var duration = 0;
463 for (i = 0; i < sliceGroup.slices.length; i++)
464 duration += sliceGroup.slices[i].duration;
465 totalDuration += duration;
466
467 text += ' ' +
468 leftAlign(sliceGroupTitle, c0Width) + ': ' +
469 rightAlign(tsRound(duration) + 'ms', c1Width) + ' ' +
470 rightAlign(String(sliceGroup.slices.length), c2Width) +
471 ' occurrences' + '\n';
472 }
473
474 text += leftAlign('*Totals', c0Width) + ' : ' +
475 rightAlign(tsRound(totalDuration) + 'ms', c1Width) + ' ' +
476 rightAlign(String(selection.length), c2Width) + ' occurrences' +
477 '\n';
478
479 text += '\n';
480
481 text += leftAlign('Selection start', c0Width) + ' : ' +
482 rightAlign(tsRound(tsLo) + 'ms', c1Width) +
483 '\n';
484 text += leftAlign('Selection extent', c0Width) + ' : ' +
485 rightAlign(tsRound(tsHi - tsLo) + 'ms', c1Width) +
486 '\n';
487 }
488
489 // done
490 var oldScrollTop = this.timelineContainer_.scrollTop; 420 var oldScrollTop = this.timelineContainer_.scrollTop;
491 this.summaryEl_.textContent = text; 421 this.analysisEl_.selection = this.timeline_.selection;
492 this.timelineContainer_.scrollTop = oldScrollTop; 422 this.timelineContainer_.scrollTop = oldScrollTop;
493 } 423 }
494 }; 424 };
495 425
496 return { 426 return {
497 TimelineFindControl: TimelineFindControl, 427 TimelineFindControl: TimelineFindControl,
498 TimelineFindController: TimelineFindController, 428 TimelineFindController: TimelineFindController,
499 TimelineView: TimelineView 429 TimelineView: TimelineView
500 }; 430 };
501 }); 431 });
OLDNEW
« no previous file with comments | « chrome/browser/resources/tracing/timeline_view.css ('k') | chrome/browser/resources/tracing/timeline_view_test.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698