1<!DOCTYPE html> 2<!-- 3Copyright (c) 2012 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/linux_perf/parser.html"> 9<link rel="import" href="/tracing/model/counter_series.html"> 10 11<script> 12'use strict'; 13 14/** 15 * @fileoverview Parses trace_marker events that were inserted in the trace by 16 * userland. 17 */ 18tr.exportTo('tr.e.importer.linux_perf', function() { 19 var ColorScheme = tr.b.ColorScheme; 20 var Parser = tr.e.importer.linux_perf.Parser; 21 22 /** 23 * Parses linux trace mark events that were inserted in the trace by userland. 24 * @constructor 25 */ 26 function AndroidParser(importer) { 27 Parser.call(this, importer); 28 29 importer.registerEventHandler('tracing_mark_write:android', 30 AndroidParser.prototype.traceMarkWriteAndroidEvent.bind(this)); 31 importer.registerEventHandler('0:android', 32 AndroidParser.prototype.traceMarkWriteAndroidEvent.bind(this)); 33 34 this.model_ = importer.model_; 35 this.ppids_ = {}; 36 } 37 38 function parseArgs(argsString) { 39 var args = {}; 40 if (argsString) { 41 var argsArray = argsString.split(';'); 42 for (var i = 0; i < argsArray.length; ++i) { 43 var parts = argsArray[i].split('='); 44 if (parts[0]) 45 args[parts.shift()] = parts.join('='); 46 } 47 } 48 return args; 49 } 50 51 AndroidParser.prototype = { 52 __proto__: Parser.prototype, 53 54 openAsyncSlice: function(thread, category, name, cookie, ts, args) { 55 var asyncSliceConstructor = 56 tr.model.AsyncSlice.getConstructor( 57 category, name); 58 var slice = new asyncSliceConstructor( 59 category, name, 60 ColorScheme.getColorIdForGeneralPurposeString(name), ts, args); 61 var key = category + ':' + name + ':' + cookie; 62 slice.id = cookie; 63 slice.startThread = thread; 64 65 if (!this.openAsyncSlices) { 66 this.openAsyncSlices = { }; 67 } 68 this.openAsyncSlices[key] = slice; 69 }, 70 71 closeAsyncSlice: function(thread, category, name, cookie, ts, args) { 72 if (!this.openAsyncSlices) { 73 // No async slices have been started. 74 return; 75 } 76 77 var key = category + ':' + name + ':' + cookie; 78 var slice = this.openAsyncSlices[key]; 79 if (!slice) { 80 // No async slices w/ this key have been started. 81 return; 82 } 83 84 for (var arg in args) { 85 if (slice.args[arg] !== undefined) { 86 this.model_.importWarning({ 87 type: 'parse_error', 88 message: 'Both the S and F events of ' + slice.title + 89 ' provided values for argument ' + arg + '.' + 90 ' The value of the F event will be used.' 91 }); 92 } 93 slice.args[arg] = args[arg]; 94 } 95 96 slice.endThread = thread; 97 slice.duration = ts - slice.start; 98 slice.startThread.asyncSliceGroup.push(slice); 99 slice.subSlices = [new tr.model.AsyncSlice(slice.category, 100 slice.title, slice.colorId, slice.start, slice.args, slice.duration)]; 101 delete this.openAsyncSlices[key]; 102 }, 103 104 traceMarkWriteAndroidEvent: function(eventName, cpuNumber, pid, ts, 105 eventBase) { 106 var eventData = eventBase.details.split('|'); 107 switch (eventData[0]) { 108 case 'B': 109 var ppid = parseInt(eventData[1]); 110 var title = eventData[2]; 111 var args = parseArgs(eventData[3]); 112 var category = eventData[4]; 113 if (category === undefined) 114 category = 'android'; 115 116 var thread = this.model_.getOrCreateProcess(ppid) 117 .getOrCreateThread(pid); 118 thread.name = eventBase.threadName; 119 if (!thread.sliceGroup.isTimestampValidForBeginOrEnd(ts)) { 120 this.model_.importWarning({ 121 type: 'parse_error', 122 message: 'Timestamps are moving backward.' 123 }); 124 return false; 125 } 126 127 this.ppids_[pid] = ppid; 128 thread.sliceGroup.beginSlice(category, title, ts, args); 129 130 break; 131 132 case 'E': 133 var ppid = this.ppids_[pid]; 134 if (ppid === undefined) { 135 // Silently ignore unmatched E events. 136 break; 137 } 138 139 var thread = this.model_.getOrCreateProcess(ppid) 140 .getOrCreateThread(pid); 141 if (!thread.sliceGroup.openSliceCount) { 142 // Silently ignore unmatched E events. 143 break; 144 } 145 146 var slice = thread.sliceGroup.endSlice(ts); 147 148 var args = parseArgs(eventData[3]); 149 for (var arg in args) { 150 if (slice.args[arg] !== undefined) { 151 this.model_.importWarning({ 152 type: 'parse_error', 153 message: 'Both the B and E events of ' + slice.title + 154 ' provided values for argument ' + arg + '.' + 155 ' The value of the E event will be used.' 156 }); 157 } 158 slice.args[arg] = args[arg]; 159 } 160 161 break; 162 163 case 'C': 164 var ppid = parseInt(eventData[1]); 165 var name = eventData[2]; 166 var value = parseInt(eventData[3]); 167 var category = eventData[4]; 168 if (category === undefined) 169 category = 'android'; 170 171 var ctr = this.model_.getOrCreateProcess(ppid) 172 .getOrCreateCounter(category, name); 173 // Initialize the counter's series fields if needed. 174 if (ctr.numSeries === 0) { 175 ctr.addSeries(new tr.model.CounterSeries(value, 176 ColorScheme.getColorIdForGeneralPurposeString( 177 ctr.name + '.' + 'value'))); 178 } 179 180 ctr.series.forEach(function(series) { 181 series.addCounterSample(ts, value); 182 }); 183 184 break; 185 186 case 'S': 187 var ppid = parseInt(eventData[1]); 188 var name = eventData[2]; 189 var cookie = parseInt(eventData[3]); 190 var args = parseArgs(eventData[4]); 191 var category = eventData[5]; 192 if (category === undefined) 193 category = 'android'; 194 195 196 var thread = this.model_.getOrCreateProcess(ppid) 197 .getOrCreateThread(pid); 198 thread.name = eventBase.threadName; 199 200 this.ppids_[pid] = ppid; 201 this.openAsyncSlice(thread, category, name, cookie, ts, args); 202 203 break; 204 205 case 'F': 206 // Note: An async slice may end on a different thread from the one 207 // that started it so this thread may not have been seen yet. 208 var ppid = parseInt(eventData[1]); 209 210 var name = eventData[2]; 211 var cookie = parseInt(eventData[3]); 212 var args = parseArgs(eventData[4]); 213 var category = eventData[5]; 214 if (category === undefined) 215 category = 'android'; 216 217 var thread = this.model_.getOrCreateProcess(ppid) 218 .getOrCreateThread(pid); 219 thread.name = eventBase.threadName; 220 221 this.ppids_[pid] = ppid; 222 this.closeAsyncSlice(thread, category, name, cookie, ts, args); 223 224 break; 225 226 default: 227 return false; 228 } 229 230 return true; 231 } 232 }; 233 234 Parser.register(AndroidParser); 235 236 return { 237 AndroidParser: AndroidParser 238 }; 239}); 240</script> 241