Home | History | Annotate | Download | only in linux_perf
      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 'use strict';
      6 
      7 /**
      8  * @fileoverview Parses trace_marker events that were inserted in the trace by
      9  * userland.
     10  */
     11 base.require('tracing.importer.linux_perf.parser');
     12 base.require('tracing.trace_model.counter_series');
     13 
     14 base.exportTo('tracing.importer.linux_perf', function() {
     15 
     16   var Parser = tracing.importer.linux_perf.Parser;
     17 
     18   /**
     19    * Parses linux trace mark events that were inserted in the trace by userland.
     20    * @constructor
     21    */
     22   function AndroidParser(importer) {
     23     Parser.call(this, importer);
     24 
     25     importer.registerEventHandler('tracing_mark_write:android',
     26         AndroidParser.prototype.traceMarkWriteAndroidEvent.bind(this));
     27     importer.registerEventHandler('0:android',
     28         AndroidParser.prototype.traceMarkWriteAndroidEvent.bind(this));
     29 
     30     this.model_ = importer.model_;
     31     this.ppids_ = {};
     32   }
     33 
     34   function parseArgs(argsString) {
     35     var args = {};
     36     if (argsString) {
     37       var argsArray = argsString.split(';');
     38       for (var i = 0; i < argsArray.length; ++i) {
     39         var parts = argsArray[i].split('=');
     40         if (parts[0])
     41           args[parts.shift()] = parts.join('=');
     42       }
     43     }
     44     return args;
     45   }
     46 
     47   AndroidParser.prototype = {
     48     __proto__: Parser.prototype,
     49 
     50     openAsyncSlice: function(thread, category, name, cookie, ts) {
     51       var slice = new tracing.trace_model.AsyncSlice(
     52           category, name, tracing.getStringColorId(name), ts);
     53       var key = name + ':' + cookie;
     54       slice.id = cookie;
     55       slice.startThread = thread;
     56 
     57 
     58       if (!this.openAsyncSlices) {
     59         this.openAsyncSlices = { };
     60       }
     61       this.openAsyncSlices[key] = slice;
     62     },
     63 
     64     closeAsyncSlice: function(thread, name, cookie, ts) {
     65       if (!this.openAsyncSlices) {
     66         // No async slices have been started.
     67         return;
     68       }
     69 
     70       var key = name + ':' + cookie;
     71       var slice = this.openAsyncSlices[key];
     72       if (!slice) {
     73         // No async slices w/ this key have been started.
     74         return;
     75       }
     76 
     77       slice.endThread = thread;
     78       slice.duration = ts - slice.start;
     79       slice.startThread.asyncSliceGroup.push(slice);
     80       slice.subSlices = [new tracing.trace_model.Slice(slice.category,
     81           slice.title, slice.colorId, slice.start, slice.args, slice.duration)];
     82       delete this.openAsyncSlices[key];
     83     },
     84 
     85     traceMarkWriteAndroidEvent: function(eventName, cpuNumber, pid, ts,
     86                                   eventBase) {
     87       var eventData = eventBase.details.split('|');
     88       switch (eventData[0]) {
     89         case 'B':
     90           var ppid = parseInt(eventData[1]);
     91           var category = eventData[4];
     92           var title = eventData[2];
     93           var thread = this.model_.getOrCreateProcess(ppid)
     94             .getOrCreateThread(pid);
     95           thread.name = eventBase.threadName;
     96           if (!thread.sliceGroup.isTimestampValidForBeginOrEnd(ts)) {
     97             this.model_.importErrors.push(
     98                 'Timestamps are moving backward.');
     99             return false;
    100           }
    101 
    102           this.ppids_[pid] = ppid;
    103           thread.sliceGroup.beginSlice(
    104               category, title, ts, parseArgs(eventData[3]));
    105 
    106           break;
    107         case 'E':
    108           var ppid = this.ppids_[pid];
    109           if (ppid === undefined) {
    110             // Silently ignore unmatched E events.
    111             break;
    112           }
    113 
    114           var thread = this.model_.getOrCreateProcess(ppid)
    115             .getOrCreateThread(pid);
    116           if (!thread.sliceGroup.openSliceCount) {
    117             // Silently ignore unmatched E events.
    118             break;
    119           }
    120 
    121           var slice = thread.sliceGroup.endSlice(ts);
    122 
    123           var args = parseArgs(eventData[3]);
    124           for (var arg in args) {
    125             if (slice.args[arg] !== undefined) {
    126               this.model_.importErrors.push(
    127                   'Both the B and E events of ' + slice.title +
    128                   'provided values for argument ' + arg + '. ' +
    129                   'The value of the E event will be used.');
    130             }
    131             slice.args[arg] = args[arg];
    132           }
    133 
    134           break;
    135         case 'C':
    136           var ppid = parseInt(eventData[1]);
    137           var name = eventData[2];
    138           var value = parseInt(eventData[3]);
    139           var category = eventData[4];
    140 
    141           var ctr = this.model_.getOrCreateProcess(ppid)
    142               .getOrCreateCounter(category, name);
    143           // Initialize the counter's series fields if needed.
    144           if (ctr.numSeries === 0) {
    145             ctr.addSeries(new tracing.trace_model.CounterSeries(value,
    146                 tracing.getStringColorId(ctr.name + '.' + 'value')));
    147           }
    148 
    149           ctr.series.forEach(function(series) {
    150             series.addSample(ts, value);
    151           });
    152 
    153           break;
    154 
    155         case 'S':
    156           var ppid = parseInt(eventData[1]);
    157           var name = eventData[2];
    158           var cookie = parseInt(eventData[3]);
    159           var thread = this.model_.getOrCreateProcess(ppid)
    160             .getOrCreateThread(pid);
    161           thread.name = eventBase.threadName;
    162 
    163           this.ppids_[pid] = ppid;
    164           this.openAsyncSlice(thread, null, name, cookie, ts);
    165 
    166           break;
    167 
    168         case 'F':
    169           // Note: An async slice may end on a different thread from the one
    170           // that started it so this thread may not have been seen yet.
    171           var ppid = parseInt(eventData[1]);
    172           var name = eventData[2];
    173           var cookie = parseInt(eventData[3]);
    174           var thread = this.model_.getOrCreateProcess(ppid)
    175             .getOrCreateThread(pid);
    176           thread.name = eventBase.threadName;
    177 
    178           this.ppids_[pid] = ppid;
    179           this.closeAsyncSlice(thread, name, cookie, ts);
    180 
    181           break;
    182 
    183         default:
    184           return false;
    185       }
    186 
    187       return true;
    188     }
    189   };
    190 
    191   Parser.registerSubtype(AndroidParser);
    192 
    193   return {
    194     AndroidParser: AndroidParser
    195   };
    196 });
    197