Home | History | Annotate | Download | only in sdk
      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  */
     36 WebInspector.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 
     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 {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  */
    173 WebInspector.TimelineDispatcher = function(manager)
    174 {
    175     this._manager = manager;
    176     InspectorBackend.registerTimelineDispatcher(this);
    177 }
    178 
    179 WebInspector.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  */
    230 WebInspector.timelineManager;
    231