Home | History | Annotate | Download | only in src
      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 base.requireStylesheet('tracing_controller');
     10 base.require('event_target');
     11 base.exportTo('tracing', function() {
     12 
     13   /**
     14    * The tracing controller is responsible for talking to tracing_ui.cc in
     15    * chrome
     16    * @constructor
     17    * @param {function(String, opt_Array.<String>} Function to be used to send
     18    * data to chrome.
     19    */
     20   function TracingController(sendFn) {
     21     this.sendFn_ = sendFn;
     22     this.overlay_ = document.createElement('div');
     23     this.overlay_.className = 'tracing-overlay';
     24 
     25     base.ui.decorate(this.overlay_, tracing.Overlay);
     26 
     27     this.statusDiv_ = document.createElement('div');
     28     this.overlay_.appendChild(this.statusDiv_);
     29 
     30     this.bufferPercentDiv_ = document.createElement('div');
     31     this.overlay_.appendChild(this.bufferPercentDiv_);
     32 
     33     this.stopButton_ = document.createElement('button');
     34     this.stopButton_.onclick = this.endTracing.bind(this);
     35     this.stopButton_.textContent = 'Stop tracing';
     36     this.overlay_.appendChild(this.stopButton_);
     37 
     38     this.traceEvents_ = [];
     39     this.systemTraceEvents_ = [];
     40 
     41     this.onKeydownBoundToThis_ = this.onKeydown_.bind(this);
     42     this.onKeypressBoundToThis_ = this.onKeypress_.bind(this);
     43 
     44     this.supportsSystemTracing_ = base.isChromeOS;
     45 
     46     if (this.sendFn_)
     47       this.sendFn_('tracingControllerInitialized');
     48   }
     49 
     50   TracingController.prototype = {
     51     __proto__: base.EventTarget.prototype,
     52 
     53     gpuInfo_: undefined,
     54     clientInfo_: undefined,
     55     tracingEnabled_: false,
     56     tracingEnding_: false,
     57     systemTraceDataFilename_: undefined,
     58 
     59     get supportsSystemTracing() {
     60       return this.supportsSystemTracing_;
     61     },
     62 
     63     onRequestBufferPercentFullComplete: function(percent_full) {
     64       if (!this.overlay_.visible)
     65         return;
     66 
     67       window.setTimeout(this.beginRequestBufferPercentFull_.bind(this), 250);
     68 
     69       this.bufferPercentDiv_.textContent = 'Buffer usage: ' +
     70           Math.round(100 * percent_full) + '%';
     71     },
     72 
     73     /**
     74      * Begin requesting the buffer fullness
     75      */
     76     beginRequestBufferPercentFull_: function() {
     77       this.sendFn_('beginRequestBufferPercentFull');
     78     },
     79 
     80     /**
     81      * Called by info_view to empty the trace buffer
     82      *
     83      * |opt_trace_categories| is a comma-delimited list of category wildcards.
     84      * A category can have an optional '-' prefix to make it an excluded
     85      * category.  All the same rules apply above, so for example, having both
     86      * included and excluded categories in the same list would not be
     87      * supported.
     88      *
     89      * Example: beginTracing("test_MyTest*");
     90      * Example: beginTracing("test_MyTest*,test_OtherStuff");
     91      * Example: beginTracing("-excluded_category1,-excluded_category2");
     92      */
     93     beginTracing: function(opt_systemTracingEnabled, opt_trace_categories) {
     94       if (this.tracingEnabled_)
     95         throw new Error('Tracing already begun.');
     96 
     97       this.stopButton_.hidden = false;
     98       this.statusDiv_.textContent = 'Tracing active.';
     99       this.overlay_.visible = true;
    100       this.overlay_.defaultClickShouldClose = false;
    101 
    102       this.tracingEnabled_ = true;
    103 
    104       console.log('Beginning to trace...');
    105       this.statusDiv_.textContent = 'Tracing active.';
    106 
    107       this.traceEvents_ = [];
    108       this.systemTraceEvents_ = [];
    109       this.sendFn_(
    110           'beginTracing',
    111           [
    112            opt_systemTracingEnabled || false,
    113            opt_trace_categories || '-test_*'
    114           ]
    115       );
    116       this.beginRequestBufferPercentFull_();
    117 
    118       var e = new base.Event('traceBegun');
    119       e.events = this.traceEvents_;
    120       this.dispatchEvent(e);
    121 
    122       e = new base.Event('traceEventsChanged');
    123       e.numEvents = this.traceEvents_.length;
    124       this.dispatchEvent(e);
    125 
    126       window.addEventListener('keypress', this.onKeypressBoundToThis_);
    127       window.addEventListener('keydown', this.onKeydownBoundToThis_);
    128     },
    129 
    130     onKeydown_: function(e) {
    131       if (e.keyCode == 27) {
    132         this.endTracing();
    133       }
    134     },
    135 
    136     onKeypress_: function(e) {
    137       if (e.keyIdentifier == 'Enter') {
    138         this.endTracing();
    139       }
    140     },
    141 
    142     /**
    143      * Called from gpu c++ code when ClientInfo is updated.
    144      */
    145     onClientInfoUpdate: function(clientInfo) {
    146       this.clientInfo_ = clientInfo;
    147     },
    148 
    149     /**
    150      * Called from gpu c++ code when GPU Info is updated.
    151      */
    152     onGpuInfoUpdate: function(gpuInfo) {
    153       this.gpuInfo_ = gpuInfo;
    154     },
    155 
    156     /**
    157      * Checks whether tracing is enabled
    158      */
    159     get isTracingEnabled() {
    160       return this.tracingEnabled_;
    161     },
    162 
    163     /**
    164      * Gets the currently traced events. If tracing is active, then
    165      * this can change on the fly.
    166      */
    167     get traceEvents() {
    168       return this.traceEvents_;
    169     },
    170 
    171     /**
    172      * Called by tracing c++ code when new trace data arrives.
    173      */
    174     onTraceDataCollected: function(events) {
    175       this.statusDiv_.textContent = 'Processing trace...';
    176       this.traceEvents_.push.apply(this.traceEvents_, events);
    177     },
    178 
    179     /**
    180      * Called to finish tracing and update all views.
    181      */
    182     endTracing: function() {
    183       if (!this.tracingEnabled_) throw new Error('Tracing not begun.');
    184       if (this.tracingEnding_) return;
    185       this.tracingEnding_ = true;
    186 
    187       this.statusDiv_.textContent = 'Ending trace...';
    188       console.log('Finishing trace');
    189       this.statusDiv_.textContent = 'Downloading trace data...';
    190       this.stopButton_.hidden = true;
    191       // delay sending endTracingAsync until we get a chance to
    192       // update the screen...
    193       var that = this;
    194       window.setTimeout(function() {
    195         that.sendFn_('endTracingAsync');
    196       }, 100);
    197     },
    198 
    199     /**
    200      * Called by the browser when all processes complete tracing.
    201      */
    202     onEndTracingComplete: function() {
    203       window.removeEventListener('keydown', this.onKeydownBoundToThis_);
    204       window.removeEventListener('keypress', this.onKeypressBoundToThis_);
    205       this.overlay_.visible = false;
    206       this.tracingEnabled_ = false;
    207       this.tracingEnding_ = false;
    208       console.log('onEndTracingComplete p1 with ' +
    209                   this.traceEvents_.length + ' events.');
    210       var e = new base.Event('traceEnded');
    211       e.events = this.traceEvents_;
    212       this.dispatchEvent(e);
    213     },
    214 
    215     /**
    216      * Called by tracing c++ code when new system trace data arrives.
    217      */
    218     onSystemTraceDataCollected: function(events) {
    219       console.log('onSystemTraceDataCollected with ' +
    220                   events.length + ' chars of data.');
    221       this.systemTraceEvents_ = events;
    222     },
    223 
    224     /**
    225      * Gets the currentl system trace events. If tracing is active, then
    226      * this can change on the fly.
    227      */
    228     get systemTraceEvents() {
    229       return this.systemTraceEvents_;
    230     },
    231 
    232     /**
    233      * Tells browser to put up a load dialog and load the trace file
    234      */
    235     beginLoadTraceFile: function() {
    236       this.sendFn_('loadTraceFile');
    237     },
    238 
    239     /**
    240      * Called by the browser when a trace file is loaded.
    241      */
    242     onLoadTraceFileComplete: function(data) {
    243       if (data.traceEvents) {
    244         this.traceEvents_ = data.traceEvents;
    245       } else { // path for loading traces saved without metadata
    246         if (!data.length)
    247           console.log('Expected an array when loading the trace file');
    248         else
    249           this.traceEvents_ = data;
    250       }
    251 
    252       if (data.systemTraceEvents)
    253         this.systemTraceEvents_ = data.systemTraceEvents;
    254       else
    255         this.systemTraceEvents_ = [];
    256 
    257       var e = new base.Event('loadTraceFileComplete');
    258       e.events = this.traceEvents_;
    259       this.dispatchEvent(e);
    260     },
    261 
    262     /**
    263      * Called by the browser when loading a trace file was canceled.
    264      */
    265     onLoadTraceFileCanceled: function() {
    266       base.dispatchSimpleEvent(this, 'loadTraceFileCanceled');
    267     },
    268 
    269     /**
    270      * Tells browser to put up a save dialog and save the trace file
    271      */
    272     beginSaveTraceFile: function(traceEvents, systemTraceEvents) {
    273       var data = {
    274         traceEvents: this.traceEvents_,
    275         systemTraceEvents: this.systemTraceEvents_,
    276         clientInfo: this.clientInfo_,
    277         gpuInfo: this.gpuInfo_
    278       };
    279       this.sendFn_('saveTraceFile', [JSON.stringify(data)]);
    280     },
    281 
    282     /**
    283      * Called by the browser when a trace file is saveed.
    284      */
    285     onSaveTraceFileComplete: function() {
    286       base.dispatchSimpleEvent(this, 'saveTraceFileComplete');
    287     },
    288 
    289     /**
    290      * Called by the browser when saving a trace file was canceled.
    291      */
    292     onSaveTraceFileCanceled: function() {
    293       base.dispatchSimpleEvent(this, 'saveTraceFileCanceled');
    294     }
    295   };
    296   return {
    297     TracingController: TracingController
    298   };
    299 });
    300