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.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