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.summary_ = document.createElement('pre'); 57 this.summary_.className = 'summary'; 58 59 summaryContainer_.appendChild(this.summary_); 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 var outputDiv = this.summary_; 92 if (!selection.length) { 93 outputDiv.textContent = timeline.keyHelp; 94 return; 95 } 96 97 var text = ''; 98 if (selection.length == 1) { 99 var c0Width = 10; 100 var slice = selection[0].slice; 101 text = 'Selected item:\n'; 102 text += leftAlign('Title', c0Width) + ': ' + slice.title + '\n'; 103 text += leftAlign('Start', c0Width) + ': ' + 104 tsRound(slice.start) + ' ms\n'; 105 text += leftAlign('Duration', c0Width) + ': ' + 106 tsRound(slice.duration) + ' ms\n'; 107 108 var n = 0; 109 for (var argName in slice.args) { 110 n += 1; 111 } 112 if (n > 0) { 113 text += leftAlign('Args', c0Width) + ':\n'; 114 for (var argName in slice.args) { 115 var argVal = slice.args[argName]; 116 text += leftAlign(' ' + argName, c0Width) + ': ' + argVal + '\n'; 117 } 118 } 119 } else { 120 var c0Width = 55; 121 var c1Width = 12; 122 var c2Width = 5; 123 text = 'Selection summary:\n'; 124 var tsLo = Math.min.apply(Math, selection.map( 125 function(s) {return s.slice.start;})); 126 var tsHi = Math.max.apply(Math, selection.map( 127 function(s) {return s.slice.end;})); 128 129 // compute total selection duration 130 var titles = selection.map(function(i) { return i.slice.title; }); 131 132 var slicesByTitle = {}; 133 for (var i = 0; i < selection.length; i++) { 134 var slice = selection[i].slice; 135 if (!slicesByTitle[slice.title]) 136 slicesByTitle[slice.title] = { 137 slices: [] 138 }; 139 slicesByTitle[slice.title].slices.push(slice); 140 } 141 var totalDuration = 0; 142 for (var sliceGroupTitle in slicesByTitle) { 143 var sliceGroup = slicesByTitle[sliceGroupTitle]; 144 var duration = 0; 145 for (i = 0; i < sliceGroup.slices.length; i++) 146 duration += sliceGroup.slices[i].duration; 147 totalDuration += duration; 148 149 text += ' ' + 150 leftAlign(sliceGroupTitle, c0Width) + ': ' + 151 rightAlign(tsRound(duration) + 'ms', c1Width) + ' ' + 152 rightAlign(String(sliceGroup.slices.length), c2Width) + 153 ' occurrences' + '\n'; 154 } 155 156 text += leftAlign('*Totals', c0Width) + ' : ' + 157 rightAlign(tsRound(totalDuration) + 'ms', c1Width) + ' ' + 158 rightAlign(String(selection.length), c2Width) + ' occurrences' + 159 '\n'; 160 161 text += '\n'; 162 163 text += leftAlign('Selection start', c0Width) + ' : ' + 164 rightAlign(tsRound(tsLo) + 'ms', c1Width) + 165 '\n'; 166 text += leftAlign('Selection extent', c0Width) + ' : ' + 167 rightAlign(tsRound(tsHi - tsLo) + 'ms', c1Width) + 168 '\n'; 169 } 170 171 // done 172 outputDiv.textContent = text; 173 } 174 }; 175 176 return { 177 TimelineView: TimelineView 178 }; 179 }); 180