android_parser.js revision 6833e18b1d4077bf3a727b4422cc2acdbeee35a7
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 */
11base.require('tracing.importer.linux_perf.parser');
12base.require('tracing.trace_model.counter_series');
13
14base.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          var ppid = this.ppids_[pid];
170          if (ppid === undefined) {
171            // Silently ignore unmatched F events.
172            break;
173          }
174
175          var thread = this.model_.getOrCreateProcess(ppid)
176            .getOrCreateThread(pid);
177
178          var name = eventData[2];
179          var cookie = parseInt(eventData[3]);
180
181          this.closeAsyncSlice(thread, name, cookie, ts);
182
183          break;
184
185        default:
186          return false;
187      }
188
189      return true;
190    }
191  };
192
193  Parser.registerSubtype(AndroidParser);
194
195  return {
196    AndroidParser: AndroidParser
197  };
198});
199