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