ddms_importer.html revision b2cbf1594f8d6e4ba32d384cf379f62a74ed7654
1<!DOCTYPE html>
2<!--
3Copyright (c) 2015 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="import" href="/extras/importer/jszip.html">
9<link rel="import" href="/model/model.html">
10<link rel="import" href="/importer/importer.html">
11
12<script>
13/**
14 * @fileoverview Blah.
15 */
16'use strict';
17
18tr.exportTo('tr.e.importer.ddms', function() {
19  var Importer = tr.importer.Importer;
20
21  var kPid = 0;
22  var kCategory = 'java';
23  var kMethodLutEndMarker = '\n*end\n';
24  var kThreadsStart = '\n*threads\n';
25  var kMethodsStart = '\n*methods\n';
26
27  var kTraceMethodEnter = 0x00;       // method entry
28  var kTraceMethodExit = 0x01;        // method exit
29  var kTraceUnroll = 0x02;            // method exited by exception unrolling
30  // 0x03 currently unused
31  var kTraceMethodActionMask = 0x03;  // two bits
32
33  var kTraceHeaderLength = 32;
34  var kTraceMagicValue = 0x574f4c53;
35  var kTraceVersionSingleClock = 2;
36  var kTraceVersionDualClock = 3;
37  var kTraceRecordSizeSingleClock = 10;  // using v2
38  var kTraceRecordSizeDualClock = 14;  // using v3 with two timestamps
39
40  function Reader(string_payload) {
41    this.position_ = 0;
42    this.data_ = JSZip.utils.transformTo('uint8array', string_payload);
43  }
44
45  Reader.prototype = {
46    __proto__: Object.prototype,
47
48    uint8: function() {
49      var result = this.data_[this.position_];
50      this.position_ += 1;
51      return result;
52    },
53
54    uint16: function() {
55      var result = 0;
56      result += this.uint8();
57      result += this.uint8() << 8;
58      return result;
59    },
60
61    uint32: function() {
62      var result = 0;
63      result += this.uint8();
64      result += this.uint8() << 8;
65      result += this.uint8() << 16;
66      result += this.uint8() << 24;
67      return result;
68    },
69
70    uint64: function() {
71      // Javascript isn't able to manage 64-bit numeric values.
72      var low = this.uint32();
73      var high = this.uint32();
74      var low_str = ('0000000' + low.toString(16)).substr(-8);
75      var high_str = ('0000000' + high.toString(16)).substr(-8);
76      var result = high_str + low_str;
77      return result;
78    },
79
80    seekTo: function(position) {
81      this.position_ = position;
82    },
83
84    hasMore: function() {
85      return this.position_ < this.data_.length;
86    }
87  };
88
89  /**
90   * Imports DDMS method tracing events into a specified model.
91   * @constructor
92   */
93  function DdmsImporter(model, data) {
94    this.importPriority = 3;
95    this.model_ = model;
96    this.data_ = data;
97  }
98
99  /**
100   * Guesses whether the provided events is from a DDMS method trace.
101   * @return {boolean} True when events is a DDMS method trace.
102   */
103  DdmsImporter.canImport = function(data) {
104    if (typeof(data) === 'string' || data instanceof String) {
105      var header = data.slice(0, 1000);
106      return header.startsWith('*version\n') &&
107        header.indexOf('\nvm=') >= 0 &&
108        header.indexOf(kThreadsStart) >= 0;
109    }
110    /* key bit */
111    return false;
112  };
113
114  DdmsImporter.prototype = {
115    __proto__: Importer.prototype,
116
117    get model() {
118      return this.model_;
119    },
120
121    /**
122     * Imports the data in this.data_ into this.model_.
123     */
124    importEvents: function(isSecondaryImport) {
125      var divider = this.data_.indexOf(kMethodLutEndMarker) +
126          kMethodLutEndMarker.length;
127      this.metadata_ = this.data_.slice(0, divider);
128      this.methods_ = {};
129      this.parseThreads();
130      this.parseMethods();
131
132      var traceReader = new Reader(this.data_.slice(divider));
133      var magic = traceReader.uint32();
134      if (magic != kTraceMagicValue) {
135        throw Error('Failed to match magic value');
136      }
137      this.version_ = traceReader.uint16();
138      if (this.version_ != kTraceVersionDualClock) {
139        throw Error('Unknown version');
140      }
141      var dataOffest = traceReader.uint16();
142      var startDateTime = traceReader.uint64();
143      var recordSize = traceReader.uint16();
144
145      traceReader.seekTo(dataOffest);
146
147      while (traceReader.hasMore()) {
148        this.parseTraceEntry(traceReader);
149      }
150    },
151
152    parseTraceEntry: function(reader) {
153      var tid = reader.uint16();
154      var methodPacked = reader.uint32();
155      var cpuSinceStart = reader.uint32();
156      var wallClockSinceStart = reader.uint32();
157      var method = methodPacked & ~kTraceMethodActionMask;
158      var action = methodPacked & kTraceMethodActionMask;
159      var thread = this.getTid(tid);
160      method = this.getMethodName(method);
161      if (action == kTraceMethodEnter) {
162        thread.sliceGroup.beginSlice(kCategory, method, wallClockSinceStart,
163            undefined, cpuSinceStart);
164      } else if (thread.sliceGroup.openSliceCount) {
165        thread.sliceGroup.endSlice(wallClockSinceStart, cpuSinceStart);
166      }
167    },
168
169    parseThreads: function() {
170      var threads = this.metadata_.slice(this.metadata_.indexOf(kThreadsStart) +
171          kThreadsStart.length);
172      threads = threads.slice(0, threads.indexOf('\n*'));
173      threads = threads.split('\n');
174      threads.forEach(this.parseThread.bind(this));
175    },
176
177    parseThread: function(thread_line) {
178      var tid = thread_line.slice(0, thread_line.indexOf('\t'));
179      var thread = this.getTid(parseInt(tid));
180      thread.name = thread_line.slice(thread_line.indexOf('\t') + 1);
181    },
182
183    getTid: function(tid) {
184      return this.model_.getOrCreateProcess(kPid)
185        .getOrCreateThread(tid);
186    },
187
188    parseMethods: function() {
189      var methods = this.metadata_.slice(this.metadata_.indexOf(kMethodsStart) +
190          kMethodsStart.length);
191      methods = methods.slice(0, methods.indexOf('\n*'));
192      methods = methods.split('\n');
193      methods.forEach(this.parseMethod.bind(this));
194    },
195
196    parseMethod: function(method_line) {
197      var data = method_line.split('\t');
198      var methodId = parseInt(data[0]);
199      var methodName = data[1] + '.' + data[2] + data[3];
200      this.addMethod(methodId, methodName);
201    },
202
203    addMethod: function(methodId, methodName) {
204      this.methods_[methodId] = methodName;
205    },
206
207    getMethodName: function(methodId) {
208      return this.methods_[methodId];
209    }
210  };
211
212  // Register the DdmsImporter to the Importer.
213  tr.importer.Importer.register(DdmsImporter);
214
215  return {
216    DdmsImporter: DdmsImporter
217  };
218});
219</script>
220