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