1010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis// Use of this source code is governed by a BSD-style license that can be
3010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis// found in the LICENSE file.
4010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
5010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis/**
6010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis * @fileoverview TraceEventImporter imports TraceEvent-formatted data
7010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis * into the provided timeline model.
8010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis */
92da489cd246702bee5938545b18a6f710ed214bcJamie Gennisbase.require('timeline_model');
102da489cd246702bee5938545b18a6f710ed214bcJamie Gennisbase.require('timeline_color_scheme');
112da489cd246702bee5938545b18a6f710ed214bcJamie Gennisbase.exportTo('tracing', function() {
12010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
13010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis  function TraceEventImporter(model, eventData) {
142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    this.importPriority = 1;
15010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    this.model_ = model;
16010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
17010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    if (typeof(eventData) === 'string' || eventData instanceof String) {
18010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      // If the event data begins with a [, then we know it should end with a ].
19010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      // The reason we check for this is because some tracing implementations
20010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      // cannot guarantee that a ']' gets written to the trace file. So, we are
21010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      // forgiving and if this is obviously the case, we fix it up before
22010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      // throwing the string at JSON.parse.
23010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      if (eventData[0] == '[') {
24010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        n = eventData.length;
252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        if (eventData[n - 1] == '\n') {
262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          eventData = eventData.substring(0, n - 1);
272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          n--;
282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          if (eventData[n - 1] == '\r') {
302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            eventData = eventData.substring(0, n - 1);
312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            n--;
322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          }
33010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        }
342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        if (eventData[n - 1] == ',')
362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          eventData = eventData.substring(0, n - 1);
372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        if (eventData[n - 1] != ']')
382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          eventData = eventData + ']';
39010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      }
402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
41010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      this.events_ = JSON.parse(eventData);
42010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
43010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    } else {
44010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      this.events_ = eventData;
45010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    }
46010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
47010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    // Some trace_event implementations put the actual trace events
48010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    // inside a container. E.g { ... , traceEvents: [ ] }
49010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    // If we see that, just pull out the trace events.
502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if (this.events_.traceEvents) {
51010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      this.events_ = this.events_.traceEvents;
522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      for (fieldName in this.events_) {
532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        if (fieldName == 'traceEvents')
542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          continue;
552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        this.model_.metadata.push({name: fieldName,
562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          value: this.events_[fieldName]});
572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      }
582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    }
59010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
60010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    // Async events need to be processed durign finalizeEvents
61010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    this.allAsyncEvents_ = [];
62010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis  }
63010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
64010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis  /**
65010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis   * @return {boolean} Whether obj is a TraceEvent array.
66010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis   */
67010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis  TraceEventImporter.canImport = function(eventData) {
68010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    // May be encoded JSON. But we dont want to parse it fully yet.
69010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    // Use a simple heuristic:
70010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    //   - eventData that starts with [ are probably trace_event
71010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    //   - eventData that starts with { are probably trace_event
72010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    // May be encoded JSON. Treat files that start with { as importable by us.
73010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    if (typeof(eventData) === 'string' || eventData instanceof String) {
74010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      return eventData[0] == '{' || eventData[0] == '[';
75010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    }
76010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
77010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    // Might just be an array of events
78010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    if (eventData instanceof Array && eventData.length && eventData[0].ph)
79010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      return true;
80010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
81010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    // Might be an object with a traceEvents field in it.
82010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    if (eventData.traceEvents)
83010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      return eventData.traceEvents instanceof Array &&
84010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          eventData.traceEvents[0].ph;
85010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
86010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    return false;
87010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis  };
88010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
89010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis  TraceEventImporter.prototype = {
90010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
91010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    __proto__: Object.prototype,
92010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
93010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    /**
94010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis     * Helper to process an 'async finish' event, which will close an open slice
95010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis     * on a TimelineAsyncSliceGroup object.
962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis     */
972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    processAsyncEvent: function(index, event) {
98010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      var thread = this.model_.getOrCreateProcess(event.pid).
99010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          getOrCreateThread(event.tid);
100010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      this.allAsyncEvents_.push({
101010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        event: event,
102010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        thread: thread});
103010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    },
104010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
105010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    /**
106010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis     * Helper that creates and adds samples to a TimelineCounter object based on
107010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis     * 'C' phase events.
108010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis     */
109010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    processCounterEvent: function(event) {
110010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      var ctr_name;
111010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      if (event.id !== undefined)
112010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        ctr_name = event.name + '[' + event.id + ']';
113010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      else
114010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        ctr_name = event.name;
115010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
116010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      var ctr = this.model_.getOrCreateProcess(event.pid)
117010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          .getOrCreateCounter(event.cat, ctr_name);
118010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      // Initialize the counter's series fields if needed.
119010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      if (ctr.numSeries == 0) {
120010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        for (var seriesName in event.args) {
121010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          ctr.seriesNames.push(seriesName);
122010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          ctr.seriesColors.push(
123010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              tracing.getStringColorId(ctr.name + '.' + seriesName));
124010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        }
125010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        if (ctr.numSeries == 0) {
126010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          this.model_.importErrors.push('Expected counter ' + event.name +
127010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              ' to have at least one argument to use as a value.');
128010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          // Drop the counter.
129010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          delete ctr.parent.counters[ctr.name];
130010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          return;
131010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        }
132010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      }
133010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
134010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      // Add the sample values.
135010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      ctr.timestamps.push(event.ts / 1000);
136010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      for (var i = 0; i < ctr.numSeries; i++) {
137010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        var seriesName = ctr.seriesNames[i];
138010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        if (event.args[seriesName] === undefined) {
139010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          ctr.samples.push(0);
140010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          continue;
141010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        }
142010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        ctr.samples.push(event.args[seriesName]);
143010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      }
144010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    },
145010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
146010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    /**
147010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis     * Walks through the events_ list and outputs the structures discovered to
148010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis     * model_.
149010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis     */
150010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    importEvents: function() {
151010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      // Walk through events
152010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      var events = this.events_;
153010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      // Some events cannot be handled until we have done a first pass over the
154010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      // data set.  So, accumulate them into a temporary data structure.
155010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      var second_pass_events = [];
156010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      for (var eI = 0; eI < events.length; eI++) {
157010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        var event = events[eI];
158010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        if (event.ph == 'B') {
1592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          var thread = this.model_.getOrCreateProcess(event.pid)
1602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            .getOrCreateThread(event.tid);
1612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          if (!thread.isTimestampValidForBeginOrEnd(event.ts / 1000)) {
1622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            this.model_.importErrors.push(
1632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                'Timestamps are moving backward.');
1642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            continue;
1652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          }
1662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          thread.beginSlice(event.cat, event.name, event.ts / 1000, event.args);
167010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        } else if (event.ph == 'E') {
1682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          var thread = this.model_.getOrCreateProcess(event.pid)
1692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            .getOrCreateThread(event.tid);
1702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          if (!thread.isTimestampValidForBeginOrEnd(event.ts / 1000)) {
1712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            this.model_.importErrors.push(
1722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                'Timestamps are moving backward.');
1732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            continue;
1742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          }
1752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          if (!thread.openSliceCount) {
1762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            this.model_.importErrors.push(
1772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                'E phase event without a matching B phase event.');
1782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            continue;
1792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          }
1802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          var slice = thread.endSlice(event.ts / 1000);
1822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          for (var arg in event.args) {
1832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            if (slice.args[arg] !== undefined) {
1842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis              this.model_.importErrors.push(
1852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                  'Both the B and E phases of ' + slice.name +
1862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                  'provided values for argument ' + arg + '. ' +
1872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                  'The value of the E phase event will be used.');
1882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            }
1892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            slice.args[arg] = event.args[arg];
1902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          }
1912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
192010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        } else if (event.ph == 'S') {
1932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          this.processAsyncEvent(eI, event);
194010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        } else if (event.ph == 'F') {
1952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          this.processAsyncEvent(eI, event);
196010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        } else if (event.ph == 'T') {
1972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          this.processAsyncEvent(eI, event);
198010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        } else if (event.ph == 'I') {
199010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          // Treat an Instant event as a duration 0 slice.
200010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          // TimelineSliceTrack's redraw() knows how to handle this.
2012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          var thread = this.model_.getOrCreateProcess(event.pid)
2022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            .getOrCreateThread(event.tid);
2032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          thread.beginSlice(event.cat, event.name, event.ts / 1000, event.args);
2042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          thread.endSlice(event.ts / 1000);
205010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        } else if (event.ph == 'C') {
206010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          this.processCounterEvent(event);
207010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        } else if (event.ph == 'M') {
208010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          if (event.name == 'thread_name') {
209010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            var thread = this.model_.getOrCreateProcess(event.pid)
210010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                             .getOrCreateThread(event.tid);
211010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            thread.name = event.args.name;
212010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          } else {
213010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            this.model_.importErrors.push(
214010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                'Unrecognized metadata name: ' + event.name);
215010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          }
21657a636a44b62b6d8aece3b27aee6ddac2c8c4d8bErik Gilling        } else if (event.ph == 's') {
21757a636a44b62b6d8aece3b27aee6ddac2c8c4d8bErik Gilling          // NB: toss until there's proper support
21857a636a44b62b6d8aece3b27aee6ddac2c8c4d8bErik Gilling        } else if (event.ph == 't') {
21957a636a44b62b6d8aece3b27aee6ddac2c8c4d8bErik Gilling          // NB: toss until there's proper support
22057a636a44b62b6d8aece3b27aee6ddac2c8c4d8bErik Gilling        } else if (event.ph == 'f') {
22157a636a44b62b6d8aece3b27aee6ddac2c8c4d8bErik Gilling          // NB: toss until there's proper support
222010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        } else {
223010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          this.model_.importErrors.push(
224010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              'Unrecognized event phase: ' + event.ph +
225010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              '(' + event.name + ')');
226010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        }
227010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      }
228010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    },
229010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
230010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    /**
231010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis     * Called by the TimelineModel after all other importers have imported their
2322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis     * events.
233010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis     */
234010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    finalizeImport: function() {
2352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.createAsyncSlices_();
2362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
2372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    createAsyncSlices_: function() {
239010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      if (this.allAsyncEvents_.length == 0)
240010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        return;
241010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
242010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      this.allAsyncEvents_.sort(function(x, y) {
243010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        return x.event.ts - y.event.ts;
244010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      });
245010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
246010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      var asyncEventStatesByNameThenID = {};
247010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
248010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      var allAsyncEvents = this.allAsyncEvents_;
249010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      for (var i = 0; i < allAsyncEvents.length; i++) {
250010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        var asyncEventState = allAsyncEvents[i];
251010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
252010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        var event = asyncEventState.event;
253010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        var name = event.name;
254010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        if (name === undefined) {
255010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          this.model_.importErrors.push(
256010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              'Async events (ph: S, T or F) require an name parameter.');
257010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          continue;
258010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        }
259010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
260010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        var id = event.id;
261010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        if (id === undefined) {
262010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          this.model_.importErrors.push(
263010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              'Async events (ph: S, T or F) require an id parameter.');
264010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          continue;
265010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        }
266010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
267010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        // TODO(simonjam): Add a synchronous tick on the appropriate thread.
268010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
269010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        if (event.ph == 'S') {
270010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          if (asyncEventStatesByNameThenID[name] === undefined)
271010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            asyncEventStatesByNameThenID[name] = {};
272010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          if (asyncEventStatesByNameThenID[name][id]) {
273010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            this.model_.importErrors.push(
2742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                'At ' + event.ts + ', a slice of the same id ' + id +
275010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                ' was alrady open.');
276010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            continue;
277010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          }
278010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          asyncEventStatesByNameThenID[name][id] = [];
279010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          asyncEventStatesByNameThenID[name][id].push(asyncEventState);
280010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        } else {
281010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          if (asyncEventStatesByNameThenID[name] === undefined) {
282010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            this.model_.importErrors.push(
283010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                'At ' + event.ts + ', no slice named ' + name +
284010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                ' was open.');
285010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            continue;
286010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          }
287010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          if (asyncEventStatesByNameThenID[name][id] === undefined) {
288010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            this.model_.importErrors.push(
289010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                'At ' + event.ts + ', no slice named ' + name +
290010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                ' with id=' + id + ' was open.');
291010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            continue;
292010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          }
293010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          var events = asyncEventStatesByNameThenID[name][id];
294010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          events.push(asyncEventState);
295010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
296010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          if (event.ph == 'F') {
297010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            // Create a slice from start to end.
298010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            var slice = new tracing.TimelineAsyncSlice(
2992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                events[0].event.cat,
300010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                name,
301010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                tracing.getStringColorId(name),
302010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                events[0].event.ts / 1000);
303010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
304010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            slice.duration = (event.ts / 1000) - (events[0].event.ts / 1000);
305010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
306010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            slice.startThread = events[0].thread;
307010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            slice.endThread = asyncEventState.thread;
308010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            slice.id = id;
309010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            slice.args = events[0].event.args;
310010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            slice.subSlices = [];
311010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
312010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            // Create subSlices for each step.
313010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            for (var j = 1; j < events.length; ++j) {
314010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              var subName = name;
315010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              if (events[j - 1].event.ph == 'T')
316010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                subName = name + ':' + events[j - 1].event.args.step;
317010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              var subSlice = new tracing.TimelineAsyncSlice(
3182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                  events[0].event.cat,
319010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                  subName,
320010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                  tracing.getStringColorId(name + j),
321010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                  events[j - 1].event.ts / 1000);
322010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
323010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              subSlice.duration =
324010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis                  (events[j].event.ts / 1000) - (events[j - 1].event.ts / 1000);
325010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
326010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              subSlice.startThread = events[j - 1].thread;
327010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              subSlice.endThread = events[j].thread;
328010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              subSlice.id = id;
329010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              subSlice.args = events[j - 1].event.args;
330010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
331010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              slice.subSlices.push(subSlice);
332010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            }
333010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
334010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            // The args for the finish event go in the last subSlice.
335010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            var lastSlice = slice.subSlices[slice.subSlices.length - 1];
336010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            for (var arg in event.args)
337010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis              lastSlice.args[arg] = event.args[arg];
338010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
339010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            // Add |slice| to the start-thread's asyncSlices.
340010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            slice.startThread.asyncSlices.push(slice);
341010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis            delete asyncEventStatesByNameThenID[name][id];
342010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis          }
343010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis        }
344010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis      }
345010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    }
346010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis  };
347010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
348010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis  tracing.TimelineModel.registerImporter(TraceEventImporter);
349010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis
350010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis  return {
351010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis    TraceEventImporter: TraceEventImporter
352010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis  };
353010583560e0e6db74fe50b840bce46ba6537de63Jamie Gennis});
354