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.SDKModel} 34 * @param {!WebInspector.Target} target 35 */ 36 WebInspector.TimelineManager = function(target) 37 { 38 WebInspector.SDKModel.call(this, WebInspector.TimelineManager, target); 39 this._dispatcher = new WebInspector.TimelineDispatcher(this); 40 this._enablementCount = 0; 41 this._jsProfilerStarted = false; 42 target.timelineAgent().enable(); 43 } 44 45 WebInspector.TimelineManager.EventTypes = { 46 TimelineStarted: "TimelineStarted", 47 TimelineStopped: "TimelineStopped", 48 TimelineEventRecorded: "TimelineEventRecorded", 49 TimelineProgress: "TimelineProgress" 50 } 51 52 WebInspector.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 {string=} liveEvents 64 * @param {boolean=} includeCounters 65 * @param {boolean=} includeGPUEvents 66 * @param {function(?Protocol.Error)=} callback 67 */ 68 start: function(maxCallStackDepth, liveEvents, includeCounters, includeGPUEvents, callback) 69 { 70 this._enablementCount++; 71 WebInspector.profilingLock().acquire(); 72 if (Runtime.experiments.isEnabled("timelineJSCPUProfile") && maxCallStackDepth) { 73 this._configureCpuProfilerSamplingInterval(); 74 this._jsProfilerStarted = true; 75 this.target().profilerAgent().start(); 76 } 77 if (this._enablementCount === 1) 78 this.target().timelineAgent().start(maxCallStackDepth, true, liveEvents, includeCounters, includeGPUEvents, callback); 79 else if (callback) 80 callback(null); 81 }, 82 83 /** 84 * @param {function(?Protocol.Error,?ProfilerAgent.CPUProfile)} callback 85 */ 86 stop: function(callback) 87 { 88 this._enablementCount--; 89 if (this._enablementCount < 0) { 90 console.error("WebInspector.TimelineManager start/stop calls are unbalanced " + new Error().stack); 91 return; 92 } 93 94 var masterError = null; 95 var masterProfile = null; 96 var callbackBarrier = new CallbackBarrier(); 97 98 if (this._jsProfilerStarted) { 99 this.target().profilerAgent().stop(callbackBarrier.createCallback(profilerCallback)); 100 this._jsProfilerStarted = false; 101 } 102 if (!this._enablementCount) 103 this.target().timelineAgent().stop(callbackBarrier.createCallback(timelineCallback)); 104 105 callbackBarrier.callWhenDone(allDoneCallback); 106 107 /** 108 * @param {?Protocol.Error} error 109 */ 110 function timelineCallback(error) 111 { 112 masterError = masterError || error; 113 } 114 115 /** 116 * @param {?Protocol.Error} error 117 * @param {!ProfilerAgent.CPUProfile} profile 118 */ 119 function profilerCallback(error, profile) 120 { 121 masterError = masterError || error; 122 masterProfile = profile; 123 } 124 125 function allDoneCallback() 126 { 127 WebInspector.profilingLock().release(); 128 callback(masterError, masterProfile); 129 } 130 }, 131 132 /** 133 * @param {boolean=} consoleTimeline 134 * @param {!Array.<!TimelineAgent.TimelineEvent>=} events 135 */ 136 _stopped: function(consoleTimeline, events) 137 { 138 var data = { 139 consoleTimeline: consoleTimeline, 140 events: events || [] 141 }; 142 this.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineStopped, data); 143 }, 144 145 _configureCpuProfilerSamplingInterval: function() 146 { 147 var intervalUs = WebInspector.settings.highResolutionCpuProfiling.get() ? 100 : 1000; 148 this.target().profilerAgent().setSamplingInterval(intervalUs, didChangeInterval); 149 150 function didChangeInterval(error) 151 { 152 if (error) 153 WebInspector.console.error(error); 154 } 155 }, 156 157 __proto__: WebInspector.SDKModel.prototype 158 } 159 160 /** 161 * @constructor 162 * @implements {TimelineAgent.Dispatcher} 163 */ 164 WebInspector.TimelineDispatcher = function(manager) 165 { 166 this._manager = manager; 167 this._manager.target().registerTimelineDispatcher(this); 168 } 169 170 WebInspector.TimelineDispatcher.prototype = { 171 /** 172 * @param {!TimelineAgent.TimelineEvent} record 173 */ 174 eventRecorded: function(record) 175 { 176 this._manager.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineEventRecorded, record); 177 }, 178 179 /** 180 * @return {boolean} 181 */ 182 isStarted: function() 183 { 184 return !!this._started; 185 }, 186 187 /** 188 * @param {boolean=} consoleTimeline 189 */ 190 started: function(consoleTimeline) 191 { 192 if (consoleTimeline) { 193 // Wake up timeline panel module. 194 self.runtime.loadModule("timeline"); 195 } 196 this._started = true; 197 this._manager.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineStarted, consoleTimeline); 198 }, 199 200 /** 201 * @param {boolean=} consoleTimeline 202 * @param {!Array.<!TimelineAgent.TimelineEvent>=} events 203 */ 204 stopped: function(consoleTimeline, events) 205 { 206 this._started = false; 207 this._manager._stopped(consoleTimeline, events); 208 }, 209 210 /** 211 * @param {number} count 212 */ 213 progress: function(count) 214 { 215 this._manager.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineProgress, count); 216 } 217 } 218