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 State and UI for trace data collection. 8 */ 9 cr.define('gpu', function() { 10 11 function TracingController() { 12 this.overlay_ = document.createElement('div'); 13 this.overlay_.className = 'gpu-tracing-overlay'; 14 15 cr.ui.decorate(this.overlay_, gpu.Overlay); 16 17 this.statusDiv_ = document.createElement('div'); 18 this.overlay_.appendChild(this.statusDiv_); 19 20 this.bufferPercentDiv_ = document.createElement('div'); 21 this.overlay_.appendChild(this.bufferPercentDiv_); 22 23 this.stopButton_ = document.createElement('button'); 24 this.stopButton_.onclick = this.endTracing.bind(this); 25 this.stopButton_.innerText = 'Stop tracing'; 26 this.overlay_.appendChild(this.stopButton_); 27 28 this.traceEvents_ = []; 29 30 if (browserBridge.debugMode) { 31 var tracingControllerTests = document.createElement('script'); 32 tracingControllerTests.src = 33 './gpu_internals/tracing_controller_tests.js'; 34 document.body.appendChild(tracingControllerTests); 35 } 36 37 this.onKeydownBoundToThis_ = this.onKeydown_.bind(this); 38 this.onKeypressBoundToThis_ = this.onKeypress_.bind(this); 39 } 40 41 TracingController.prototype = { 42 __proto__: cr.EventTarget.prototype, 43 44 tracingEnabled_: false, 45 tracingEnding_: false, 46 47 onRequestBufferPercentFullComplete: function(percent_full) { 48 if (!this.overlay_.visible) 49 return; 50 51 window.setTimeout(this.beginRequestBufferPercentFull_.bind(this), 250); 52 53 this.bufferPercentDiv_.textContent = 'Buffer usage: ' + 54 Math.round(100 * percent_full) + '%'; 55 }, 56 57 /** 58 * Begin requesting the buffer fullness 59 */ 60 beginRequestBufferPercentFull_: function() { 61 chrome.send('beginRequestBufferPercentFull'); 62 }, 63 64 /** 65 * Called by info_view to empty the trace buffer 66 */ 67 beginTracing: function() { 68 if (this.tracingEnabled_) 69 throw Error('Tracing already begun.'); 70 71 this.stopButton_.hidden = false; 72 this.statusDiv_.textContent = 'Tracing active.'; 73 this.overlay_.visible = true; 74 75 this.tracingEnabled_ = true; 76 console.log('Beginning to trace...'); 77 this.statusDiv_.textContent = 'Tracing active.'; 78 79 this.traceEvents_ = []; 80 if (!browserBridge.debugMode) { 81 chrome.send('beginTracing'); 82 this.beginRequestBufferPercentFull_(); 83 } 84 85 this.tracingEnabled_ = true; 86 87 var e = new cr.Event('traceBegun'); 88 e.events = this.traceEvents_; 89 this.dispatchEvent(e); 90 91 e = new cr.Event('traceEventsChanged'); 92 e.numEvents = this.traceEvents_.length; 93 this.dispatchEvent(e); 94 95 window.addEventListener('keypress', this.onKeypressBoundToThis_); 96 window.addEventListener('keydown', this.onKeydownBoundToThis_); 97 98 // In debug mode, stop tracing automatically 99 if (browserBridge.debugMode) 100 window.setTimeout(this.endTracing.bind(this), 100); 101 }, 102 103 onKeydown_: function(e) { 104 if (e.keyCode == 27) { 105 this.endTracing(); 106 } 107 }, 108 109 onKeypress_: function(e) { 110 if (e.keyIdentifier == 'Enter') { 111 this.endTracing(); 112 } 113 }, 114 /** 115 * Checks whether tracing is enabled 116 */ 117 get isTracingEnabled() { 118 return this.tracingEnabled_; 119 }, 120 121 /** 122 * Gets the currently traced events. If tracing is active, then 123 * this can change on the fly. 124 */ 125 get traceEvents() { 126 return this.traceEvents_; 127 }, 128 129 /** 130 * Callbed by gpu c++ code when new GPU trace data arrives. 131 */ 132 onTraceDataCollected: function(events) { 133 this.statusDiv_.textContent = 'Processing trace...'; 134 this.traceEvents_.push.apply(this.traceEvents_, events); 135 }, 136 137 /** 138 * Called by info_view to finish tracing and update all views. 139 */ 140 endTracing: function() { 141 if (!this.tracingEnabled_) throw new Error('Tracing not begun.'); 142 if (this.tracingEnding_) return; 143 this.tracingEnding_ = true; 144 145 this.statusDiv_.textContent = 'Ending trace...'; 146 console.log('Finishing trace'); 147 this.statusDiv_.textContent = 'Downloading trace data...'; 148 this.stopButton_.hidden = true; 149 if (!browserBridge.debugMode) { 150 // delay sending endTracingAsync until we get a chance to 151 // update the screen... 152 window.setTimeout(function() { 153 chrome.send('endTracingAsync'); 154 }, 100); 155 } else { 156 var events = tracingControllerTestEvents; 157 this.onTraceDataCollected(events); 158 window.setTimeout(this.onEndTracingComplete.bind(this), 250); 159 } 160 }, 161 162 163 /** 164 * Called by the browser when all processes complete tracing. 165 */ 166 onEndTracingComplete: function() { 167 window.removeEventListener('keydown', this.onKeydownBoundToThis_); 168 window.removeEventListener('keypress', this.onKeypressBoundToThis_); 169 this.overlay_.visible = false; 170 this.tracingEnabled_ = false; 171 this.tracingEnding_ = false; 172 console.log('onEndTracingComplete p1 with ' + 173 this.traceEvents_.length + ' events.'); 174 var e = new cr.Event('traceEnded'); 175 e.events = this.traceEvents_; 176 this.dispatchEvent(e); 177 }, 178 179 /** 180 * Tells browser to put up a load dialog and load the trace file 181 */ 182 beginLoadTraceFile: function() { 183 chrome.send('loadTraceFile'); 184 }, 185 186 /** 187 * Called by the browser when a trace file is loaded. 188 */ 189 onLoadTraceFileComplete: function(data) { 190 if (data.traceEvents) { 191 this.traceEvents_ = data.traceEvents; 192 } else { // path for loading traces saved without metadata 193 if (!data.length) 194 console.log('Expected an array when loading the trace file'); 195 else 196 this.traceEvents_ = data; 197 } 198 var e = new cr.Event('loadTraceFileComplete'); 199 e.events = this.traceEvents_; 200 this.dispatchEvent(e); 201 }, 202 203 /** 204 * Called by the browser when loading a trace file was canceled. 205 */ 206 onLoadTraceFileCanceled: function() { 207 cr.dispatchSimpleEvent(this, 'loadTraceFileCanceled'); 208 }, 209 210 /** 211 * Tells browser to put up a save dialog and save the trace file 212 */ 213 beginSaveTraceFile: function(traceEvents) { 214 var data = { 215 traceEvents: traceEvents, 216 clientInfo: browserBridge.clientInfo, 217 gpuInfo: browserBridge.gpuInfo 218 }; 219 chrome.send('saveTraceFile', [JSON.stringify(data)]); 220 }, 221 222 /** 223 * Called by the browser when a trace file is saveed. 224 */ 225 onSaveTraceFileComplete: function() { 226 cr.dispatchSimpleEvent(this, 'saveTraceFileComplete'); 227 }, 228 229 /** 230 * Called by the browser when saving a trace file was canceled. 231 */ 232 onSaveTraceFileCanceled: function() { 233 cr.dispatchSimpleEvent(this, 'saveTraceFileCanceled'); 234 }, 235 236 selfTest: function() { 237 this.beginTracing(); 238 window.setTimeout(this.endTracing.bind(This), 500); 239 } 240 }; 241 return { 242 TracingController: TracingController 243 }; 244 }); 245 246