1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 'use strict'; 6 7 /** 8 * @fileoverview Parses trace_marker events that were inserted in the trace by 9 * userland. 10 */ 11 base.require('tracing.importer.linux_perf.parser'); 12 base.require('tracing.trace_model.counter_series'); 13 14 base.exportTo('tracing.importer.linux_perf', function() { 15 16 var Parser = tracing.importer.linux_perf.Parser; 17 18 /** 19 * Parses linux trace mark events that were inserted in the trace by userland. 20 * @constructor 21 */ 22 function AndroidParser(importer) { 23 Parser.call(this, importer); 24 25 importer.registerEventHandler('tracing_mark_write:android', 26 AndroidParser.prototype.traceMarkWriteAndroidEvent.bind(this)); 27 importer.registerEventHandler('0:android', 28 AndroidParser.prototype.traceMarkWriteAndroidEvent.bind(this)); 29 30 this.model_ = importer.model_; 31 this.ppids_ = {}; 32 } 33 34 function parseArgs(argsString) { 35 var args = {}; 36 if (argsString) { 37 var argsArray = argsString.split(';'); 38 for (var i = 0; i < argsArray.length; ++i) { 39 var parts = argsArray[i].split('='); 40 if (parts[0]) 41 args[parts.shift()] = parts.join('='); 42 } 43 } 44 return args; 45 } 46 47 AndroidParser.prototype = { 48 __proto__: Parser.prototype, 49 50 openAsyncSlice: function(thread, category, name, cookie, ts) { 51 var slice = new tracing.trace_model.AsyncSlice( 52 category, name, tracing.getStringColorId(name), ts); 53 var key = name + ':' + cookie; 54 slice.id = cookie; 55 slice.startThread = thread; 56 57 58 if (!this.openAsyncSlices) { 59 this.openAsyncSlices = { }; 60 } 61 this.openAsyncSlices[key] = slice; 62 }, 63 64 closeAsyncSlice: function(thread, name, cookie, ts) { 65 if (!this.openAsyncSlices) { 66 // No async slices have been started. 67 return; 68 } 69 70 var key = name + ':' + cookie; 71 var slice = this.openAsyncSlices[key]; 72 if (!slice) { 73 // No async slices w/ this key have been started. 74 return; 75 } 76 77 slice.endThread = thread; 78 slice.duration = ts - slice.start; 79 slice.startThread.asyncSliceGroup.push(slice); 80 slice.subSlices = [new tracing.trace_model.Slice(slice.category, 81 slice.title, slice.colorId, slice.start, slice.args, slice.duration)]; 82 delete this.openAsyncSlices[key]; 83 }, 84 85 traceMarkWriteAndroidEvent: function(eventName, cpuNumber, pid, ts, 86 eventBase) { 87 var eventData = eventBase.details.split('|'); 88 switch (eventData[0]) { 89 case 'B': 90 var ppid = parseInt(eventData[1]); 91 var category = eventData[4]; 92 var title = eventData[2]; 93 var thread = this.model_.getOrCreateProcess(ppid) 94 .getOrCreateThread(pid); 95 thread.name = eventBase.threadName; 96 if (!thread.sliceGroup.isTimestampValidForBeginOrEnd(ts)) { 97 this.model_.importErrors.push( 98 'Timestamps are moving backward.'); 99 return false; 100 } 101 102 this.ppids_[pid] = ppid; 103 thread.sliceGroup.beginSlice( 104 category, title, ts, parseArgs(eventData[3])); 105 106 break; 107 case 'E': 108 var ppid = this.ppids_[pid]; 109 if (ppid === undefined) { 110 // Silently ignore unmatched E events. 111 break; 112 } 113 114 var thread = this.model_.getOrCreateProcess(ppid) 115 .getOrCreateThread(pid); 116 if (!thread.sliceGroup.openSliceCount) { 117 // Silently ignore unmatched E events. 118 break; 119 } 120 121 var slice = thread.sliceGroup.endSlice(ts); 122 123 var args = parseArgs(eventData[3]); 124 for (var arg in args) { 125 if (slice.args[arg] !== undefined) { 126 this.model_.importErrors.push( 127 'Both the B and E events of ' + slice.title + 128 'provided values for argument ' + arg + '. ' + 129 'The value of the E event will be used.'); 130 } 131 slice.args[arg] = args[arg]; 132 } 133 134 break; 135 case 'C': 136 var ppid = parseInt(eventData[1]); 137 var name = eventData[2]; 138 var value = parseInt(eventData[3]); 139 var category = eventData[4]; 140 141 var ctr = this.model_.getOrCreateProcess(ppid) 142 .getOrCreateCounter(category, name); 143 // Initialize the counter's series fields if needed. 144 if (ctr.numSeries === 0) { 145 ctr.addSeries(new tracing.trace_model.CounterSeries(value, 146 tracing.getStringColorId(ctr.name + '.' + 'value'))); 147 } 148 149 ctr.series.forEach(function(series) { 150 series.addSample(ts, value); 151 }); 152 153 break; 154 155 case 'S': 156 var ppid = parseInt(eventData[1]); 157 var name = eventData[2]; 158 var cookie = parseInt(eventData[3]); 159 var thread = this.model_.getOrCreateProcess(ppid) 160 .getOrCreateThread(pid); 161 thread.name = eventBase.threadName; 162 163 this.ppids_[pid] = ppid; 164 this.openAsyncSlice(thread, null, name, cookie, ts); 165 166 break; 167 168 case 'F': 169 var ppid = this.ppids_[pid]; 170 if (ppid === undefined) { 171 // Silently ignore unmatched F events. 172 break; 173 } 174 175 var thread = this.model_.getOrCreateProcess(ppid) 176 .getOrCreateThread(pid); 177 178 var name = eventData[2]; 179 var cookie = parseInt(eventData[3]); 180 181 this.closeAsyncSlice(thread, name, cookie, ts); 182 183 break; 184 185 default: 186 return false; 187 } 188 189 return true; 190 } 191 }; 192 193 Parser.registerSubtype(AndroidParser); 194 195 return { 196 AndroidParser: AndroidParser 197 }; 198 }); 199