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