1/* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31/** 32 * @constructor 33 * @extends {WebInspector.TargetAwareObject} 34 * @param {!WebInspector.Target} target 35 */ 36WebInspector.TimelineManager = function(target) 37{ 38 WebInspector.TargetAwareObject.call(this, target); 39 this._dispatcher = new WebInspector.TimelineDispatcher(this); 40 this._enablementCount = 0; 41 this._jsProfilerStarted = false; 42 TimelineAgent.enable(); 43} 44 45WebInspector.TimelineManager.EventTypes = { 46 TimelineStarted: "TimelineStarted", 47 TimelineStopped: "TimelineStopped", 48 TimelineEventRecorded: "TimelineEventRecorded", 49 TimelineProgress: "TimelineProgress" 50} 51 52WebInspector.TimelineManager.prototype = { 53 /** 54 * @return {boolean} 55 */ 56 isStarted: function() 57 { 58 return this._dispatcher.isStarted(); 59 }, 60 61 /** 62 * @param {number=} maxCallStackDepth 63 * @param {boolean=} bufferEvents 64 * @param {string=} liveEvents 65 * @param {boolean=} includeCounters 66 * @param {boolean=} includeGPUEvents 67 * @param {function(?Protocol.Error)=} callback 68 */ 69 start: function(maxCallStackDepth, bufferEvents, liveEvents, includeCounters, includeGPUEvents, callback) 70 { 71 this._enablementCount++; 72 this.target().profilingLock.acquire(); 73 if (WebInspector.experimentsSettings.timelineJSCPUProfile.isEnabled() && maxCallStackDepth) { 74 this._configureCpuProfilerSamplingInterval(); 75 this._jsProfilerStarted = true; 76 ProfilerAgent.start(); 77 } 78 if (this._enablementCount === 1) 79 TimelineAgent.start(maxCallStackDepth, bufferEvents, liveEvents, includeCounters, includeGPUEvents, callback); 80 else if (callback) 81 callback(null); 82 }, 83 84 /** 85 * @param {function(?Protocol.Error,?ProfilerAgent.CPUProfile)} callback 86 */ 87 stop: function(callback) 88 { 89 this._enablementCount--; 90 if (this._enablementCount < 0) { 91 console.error("WebInspector.TimelineManager start/stop calls are unbalanced " + new Error().stack); 92 return; 93 } 94 95 var masterError = null; 96 var masterProfile = null; 97 var callbackBarrier = new CallbackBarrier(); 98 99 if (this._jsProfilerStarted) { 100 ProfilerAgent.stop(callbackBarrier.createCallback(profilerCallback)); 101 this._jsProfilerStarted = false; 102 } 103 if (!this._enablementCount) 104 TimelineAgent.stop(callbackBarrier.createCallback(this._processBufferedEvents.bind(this, timelineCallback))); 105 106 callbackBarrier.callWhenDone(allDoneCallback.bind(this)); 107 108 /** 109 * @param {?Protocol.Error} error 110 */ 111 function timelineCallback(error) 112 { 113 masterError = masterError || error; 114 } 115 116 /** 117 * @param {?Protocol.Error} error 118 * @param {!ProfilerAgent.CPUProfile} profile 119 */ 120 function profilerCallback(error, profile) 121 { 122 masterError = masterError || error; 123 masterProfile = profile; 124 } 125 126 /** 127 * @this {WebInspector.TimelineManager} 128 */ 129 function allDoneCallback() 130 { 131 this.target().profilingLock.release(); 132 callback(masterError, masterProfile); 133 } 134 }, 135 136 /** 137 * @param {function(?Protocol.Error)|undefined} callback 138 * @param {?Protocol.Error} error 139 * @param {!Array.<!TimelineAgent.TimelineEvent>=} events 140 */ 141 _processBufferedEvents: function(callback, error, events) 142 { 143 if (events) { 144 for (var i = 0; i < events.length; ++i) 145 this._dispatcher.eventRecorded(events[i]); 146 } 147 if (callback) 148 callback(error); 149 }, 150 151 _configureCpuProfilerSamplingInterval: function() 152 { 153 var intervalUs = WebInspector.settings.highResolutionCpuProfiling.get() ? 100 : 1000; 154 ProfilerAgent.setSamplingInterval(intervalUs, didChangeInterval.bind(this)); 155 156 /** 157 * @this {WebInspector.TimelineManager} 158 */ 159 function didChangeInterval(error) 160 { 161 if (error) 162 this.target().consoleModel.showErrorMessage(error); 163 } 164 }, 165 166 __proto__: WebInspector.TargetAwareObject.prototype 167} 168 169/** 170 * @constructor 171 * @implements {TimelineAgent.Dispatcher} 172 */ 173WebInspector.TimelineDispatcher = function(manager) 174{ 175 this._manager = manager; 176 InspectorBackend.registerTimelineDispatcher(this); 177} 178 179WebInspector.TimelineDispatcher.prototype = { 180 /** 181 * @param {!TimelineAgent.TimelineEvent} record 182 */ 183 eventRecorded: function(record) 184 { 185 this._manager.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineEventRecorded, record); 186 }, 187 188 /** 189 * @return {boolean} 190 */ 191 isStarted: function() 192 { 193 return !!this._started; 194 }, 195 196 /** 197 * @param {boolean=} consoleTimeline 198 */ 199 started: function(consoleTimeline) 200 { 201 if (consoleTimeline) { 202 // Wake up timeline panel module. 203 WebInspector.moduleManager.loadModule("timeline"); 204 } 205 this._started = true; 206 this._manager.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineStarted, consoleTimeline); 207 }, 208 209 /** 210 * @param {boolean=} consoleTimeline 211 */ 212 stopped: function(consoleTimeline) 213 { 214 this._started = false; 215 this._manager.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineStopped, consoleTimeline); 216 }, 217 218 /** 219 * @param {number} count 220 */ 221 progress: function(count) 222 { 223 this._manager.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineProgress, count); 224 } 225} 226 227/** 228 * @type {!WebInspector.TimelineManager} 229 */ 230WebInspector.timelineManager; 231