1*795d594fSAndroid Build Coastguard Worker#!/usr/bin/env python 2*795d594fSAndroid Build Coastguard Worker# 3*795d594fSAndroid Build Coastguard Worker# Copyright (C) 2014 The Android Open Source Project 4*795d594fSAndroid Build Coastguard Worker# 5*795d594fSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*795d594fSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*795d594fSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*795d594fSAndroid Build Coastguard Worker# 9*795d594fSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*795d594fSAndroid Build Coastguard Worker# 11*795d594fSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*795d594fSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*795d594fSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*795d594fSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*795d594fSAndroid Build Coastguard Worker# limitations under the License. 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker"""Script that parses a trace filed produced in streaming mode. The file is broken up into 18*795d594fSAndroid Build Coastguard Worker a header and body part, which, when concatenated, make up a non-streaming trace file that 19*795d594fSAndroid Build Coastguard Worker can be used with traceview.""" 20*795d594fSAndroid Build Coastguard Worker 21*795d594fSAndroid Build Coastguard Workerimport sys 22*795d594fSAndroid Build Coastguard Worker 23*795d594fSAndroid Build Coastguard Workerclass MyException(Exception): 24*795d594fSAndroid Build Coastguard Worker pass 25*795d594fSAndroid Build Coastguard Worker 26*795d594fSAndroid Build Coastguard Workerclass BufferUnderrun(Exception): 27*795d594fSAndroid Build Coastguard Worker pass 28*795d594fSAndroid Build Coastguard Worker 29*795d594fSAndroid Build Coastguard Workerdef ReadShortLE(f): 30*795d594fSAndroid Build Coastguard Worker byte1 = f.read(1) 31*795d594fSAndroid Build Coastguard Worker if not byte1: 32*795d594fSAndroid Build Coastguard Worker raise BufferUnderrun() 33*795d594fSAndroid Build Coastguard Worker byte2 = f.read(1) 34*795d594fSAndroid Build Coastguard Worker if not byte2: 35*795d594fSAndroid Build Coastguard Worker raise BufferUnderrun() 36*795d594fSAndroid Build Coastguard Worker return ord(byte1) + (ord(byte2) << 8); 37*795d594fSAndroid Build Coastguard Worker 38*795d594fSAndroid Build Coastguard Workerdef WriteShortLE(f, val): 39*795d594fSAndroid Build Coastguard Worker bytes = [ (val & 0xFF), ((val >> 8) & 0xFF) ] 40*795d594fSAndroid Build Coastguard Worker asbytearray = bytearray(bytes) 41*795d594fSAndroid Build Coastguard Worker f.write(asbytearray) 42*795d594fSAndroid Build Coastguard Worker 43*795d594fSAndroid Build Coastguard Workerdef ReadIntLE(f): 44*795d594fSAndroid Build Coastguard Worker byte1 = f.read(1) 45*795d594fSAndroid Build Coastguard Worker if not byte1: 46*795d594fSAndroid Build Coastguard Worker raise BufferUnderrun() 47*795d594fSAndroid Build Coastguard Worker byte2 = f.read(1) 48*795d594fSAndroid Build Coastguard Worker if not byte2: 49*795d594fSAndroid Build Coastguard Worker raise BufferUnderrun() 50*795d594fSAndroid Build Coastguard Worker byte3 = f.read(1) 51*795d594fSAndroid Build Coastguard Worker if not byte3: 52*795d594fSAndroid Build Coastguard Worker raise BufferUnderrun() 53*795d594fSAndroid Build Coastguard Worker byte4 = f.read(1) 54*795d594fSAndroid Build Coastguard Worker if not byte4: 55*795d594fSAndroid Build Coastguard Worker raise BufferUnderrun() 56*795d594fSAndroid Build Coastguard Worker return ord(byte1) + (ord(byte2) << 8) + (ord(byte3) << 16) + (ord(byte4) << 24); 57*795d594fSAndroid Build Coastguard Worker 58*795d594fSAndroid Build Coastguard Workerdef WriteIntLE(f, val): 59*795d594fSAndroid Build Coastguard Worker bytes = [ (val & 0xFF), ((val >> 8) & 0xFF), ((val >> 16) & 0xFF), ((val >> 24) & 0xFF) ] 60*795d594fSAndroid Build Coastguard Worker asbytearray = bytearray(bytes) 61*795d594fSAndroid Build Coastguard Worker f.write(asbytearray) 62*795d594fSAndroid Build Coastguard Worker 63*795d594fSAndroid Build Coastguard Workerdef Copy(input, output, length): 64*795d594fSAndroid Build Coastguard Worker buf = input.read(length) 65*795d594fSAndroid Build Coastguard Worker if len(buf) != length: 66*795d594fSAndroid Build Coastguard Worker raise BufferUnderrun() 67*795d594fSAndroid Build Coastguard Worker output.write(buf) 68*795d594fSAndroid Build Coastguard Worker 69*795d594fSAndroid Build Coastguard Workerclass Rewriter: 70*795d594fSAndroid Build Coastguard Worker 71*795d594fSAndroid Build Coastguard Worker def PrintHeader(self, header): 72*795d594fSAndroid Build Coastguard Worker header.write('*version\n'); 73*795d594fSAndroid Build Coastguard Worker header.write('3\n'); 74*795d594fSAndroid Build Coastguard Worker header.write('data-file-overflow=false\n'); 75*795d594fSAndroid Build Coastguard Worker header.write('clock=dual\n'); 76*795d594fSAndroid Build Coastguard Worker header.write('vm=art\n'); 77*795d594fSAndroid Build Coastguard Worker 78*795d594fSAndroid Build Coastguard Worker def ProcessDataHeader(self, input, body): 79*795d594fSAndroid Build Coastguard Worker magic = ReadIntLE(input) 80*795d594fSAndroid Build Coastguard Worker if magic != 0x574f4c53: 81*795d594fSAndroid Build Coastguard Worker raise MyException("Magic wrong") 82*795d594fSAndroid Build Coastguard Worker 83*795d594fSAndroid Build Coastguard Worker WriteIntLE(body, magic) 84*795d594fSAndroid Build Coastguard Worker 85*795d594fSAndroid Build Coastguard Worker version = ReadShortLE(input) 86*795d594fSAndroid Build Coastguard Worker if (version & 0xf0) != 0xf0: 87*795d594fSAndroid Build Coastguard Worker raise MyException("Does not seem to be a streaming trace: %d." % version) 88*795d594fSAndroid Build Coastguard Worker version = version ^ 0xf0 89*795d594fSAndroid Build Coastguard Worker 90*795d594fSAndroid Build Coastguard Worker if version != 3: 91*795d594fSAndroid Build Coastguard Worker raise MyException("Only support version 3") 92*795d594fSAndroid Build Coastguard Worker 93*795d594fSAndroid Build Coastguard Worker WriteShortLE(body, version) 94*795d594fSAndroid Build Coastguard Worker 95*795d594fSAndroid Build Coastguard Worker # read offset 96*795d594fSAndroid Build Coastguard Worker offsetToData = ReadShortLE(input) - 16 97*795d594fSAndroid Build Coastguard Worker WriteShortLE(body, offsetToData + 16) 98*795d594fSAndroid Build Coastguard Worker 99*795d594fSAndroid Build Coastguard Worker # copy startWhen 100*795d594fSAndroid Build Coastguard Worker Copy(input, body, 8) 101*795d594fSAndroid Build Coastguard Worker 102*795d594fSAndroid Build Coastguard Worker if version == 1: 103*795d594fSAndroid Build Coastguard Worker self._mRecordSize = 9; 104*795d594fSAndroid Build Coastguard Worker elif version == 2: 105*795d594fSAndroid Build Coastguard Worker self._mRecordSize = 10; 106*795d594fSAndroid Build Coastguard Worker else: 107*795d594fSAndroid Build Coastguard Worker self._mRecordSize = ReadShortLE(input) 108*795d594fSAndroid Build Coastguard Worker WriteShortLE(body, self._mRecordSize) 109*795d594fSAndroid Build Coastguard Worker offsetToData -= 2; 110*795d594fSAndroid Build Coastguard Worker 111*795d594fSAndroid Build Coastguard Worker # Skip over offsetToData bytes 112*795d594fSAndroid Build Coastguard Worker Copy(input, body, offsetToData) 113*795d594fSAndroid Build Coastguard Worker 114*795d594fSAndroid Build Coastguard Worker def ProcessMethod(self, input): 115*795d594fSAndroid Build Coastguard Worker stringLength = ReadShortLE(input) 116*795d594fSAndroid Build Coastguard Worker str = input.read(stringLength) 117*795d594fSAndroid Build Coastguard Worker self._methods.append(str) 118*795d594fSAndroid Build Coastguard Worker print 'New method: %s' % str 119*795d594fSAndroid Build Coastguard Worker 120*795d594fSAndroid Build Coastguard Worker def ProcessThread(self, input): 121*795d594fSAndroid Build Coastguard Worker tid = ReadShortLE(input) 122*795d594fSAndroid Build Coastguard Worker stringLength = ReadShortLE(input) 123*795d594fSAndroid Build Coastguard Worker str = input.read(stringLength) 124*795d594fSAndroid Build Coastguard Worker self._threads.append('%d\t%s\n' % (tid, str)) 125*795d594fSAndroid Build Coastguard Worker print 'New thread: %d/%s' % (tid, str) 126*795d594fSAndroid Build Coastguard Worker 127*795d594fSAndroid Build Coastguard Worker def ProcessTraceSummary(self, input): 128*795d594fSAndroid Build Coastguard Worker summaryLength = ReadIntLE(input) 129*795d594fSAndroid Build Coastguard Worker str = input.read(summaryLength) 130*795d594fSAndroid Build Coastguard Worker self._summary = str 131*795d594fSAndroid Build Coastguard Worker print 'Summary: \"%s\"' % str 132*795d594fSAndroid Build Coastguard Worker 133*795d594fSAndroid Build Coastguard Worker def ProcessSpecial(self, input): 134*795d594fSAndroid Build Coastguard Worker code = ord(input.read(1)) 135*795d594fSAndroid Build Coastguard Worker if code == 1: 136*795d594fSAndroid Build Coastguard Worker self.ProcessMethod(input) 137*795d594fSAndroid Build Coastguard Worker elif code == 2: 138*795d594fSAndroid Build Coastguard Worker self.ProcessThread(input) 139*795d594fSAndroid Build Coastguard Worker elif code == 3: 140*795d594fSAndroid Build Coastguard Worker self.ProcessTraceSummary(input) 141*795d594fSAndroid Build Coastguard Worker else: 142*795d594fSAndroid Build Coastguard Worker raise MyException("Unknown special!") 143*795d594fSAndroid Build Coastguard Worker 144*795d594fSAndroid Build Coastguard Worker def Process(self, input, body): 145*795d594fSAndroid Build Coastguard Worker try: 146*795d594fSAndroid Build Coastguard Worker while True: 147*795d594fSAndroid Build Coastguard Worker threadId = ReadShortLE(input) 148*795d594fSAndroid Build Coastguard Worker if threadId == 0: 149*795d594fSAndroid Build Coastguard Worker self.ProcessSpecial(input) 150*795d594fSAndroid Build Coastguard Worker else: 151*795d594fSAndroid Build Coastguard Worker # Regular package, just copy 152*795d594fSAndroid Build Coastguard Worker WriteShortLE(body, threadId) 153*795d594fSAndroid Build Coastguard Worker Copy(input, body, self._mRecordSize - 2) 154*795d594fSAndroid Build Coastguard Worker except BufferUnderrun: 155*795d594fSAndroid Build Coastguard Worker print 'Buffer underrun, file was probably truncated. Results should still be usable.' 156*795d594fSAndroid Build Coastguard Worker 157*795d594fSAndroid Build Coastguard Worker def Finalize(self, header): 158*795d594fSAndroid Build Coastguard Worker # If the summary is present in the input file, use it as the header except 159*795d594fSAndroid Build Coastguard Worker # for the methods section which is emtpy in the input file. If not present, 160*795d594fSAndroid Build Coastguard Worker # apppend header with the threads that are recorded in the input stream. 161*795d594fSAndroid Build Coastguard Worker if (self._summary): 162*795d594fSAndroid Build Coastguard Worker # Erase the contents that's already written earlier by PrintHeader. 163*795d594fSAndroid Build Coastguard Worker header.seek(0) 164*795d594fSAndroid Build Coastguard Worker header.truncate() 165*795d594fSAndroid Build Coastguard Worker # Copy the lines from the input summary to the output header until 166*795d594fSAndroid Build Coastguard Worker # the methods section is seen. 167*795d594fSAndroid Build Coastguard Worker for line in self._summary.splitlines(True): 168*795d594fSAndroid Build Coastguard Worker if line == "*methods\n": 169*795d594fSAndroid Build Coastguard Worker break 170*795d594fSAndroid Build Coastguard Worker else: 171*795d594fSAndroid Build Coastguard Worker header.write(line) 172*795d594fSAndroid Build Coastguard Worker else: 173*795d594fSAndroid Build Coastguard Worker header.write('*threads\n') 174*795d594fSAndroid Build Coastguard Worker for t in self._threads: 175*795d594fSAndroid Build Coastguard Worker header.write(t) 176*795d594fSAndroid Build Coastguard Worker header.write('*methods\n') 177*795d594fSAndroid Build Coastguard Worker for m in self._methods: 178*795d594fSAndroid Build Coastguard Worker header.write(m) 179*795d594fSAndroid Build Coastguard Worker header.write('*end\n') 180*795d594fSAndroid Build Coastguard Worker 181*795d594fSAndroid Build Coastguard Worker def ProcessFile(self, filename): 182*795d594fSAndroid Build Coastguard Worker input = open(filename, 'rb') # Input file 183*795d594fSAndroid Build Coastguard Worker header = open(filename + '.header', 'w') # Header part 184*795d594fSAndroid Build Coastguard Worker body = open(filename + '.body', 'wb') # Body part 185*795d594fSAndroid Build Coastguard Worker 186*795d594fSAndroid Build Coastguard Worker self.PrintHeader(header) 187*795d594fSAndroid Build Coastguard Worker 188*795d594fSAndroid Build Coastguard Worker self.ProcessDataHeader(input, body) 189*795d594fSAndroid Build Coastguard Worker 190*795d594fSAndroid Build Coastguard Worker self._methods = [] 191*795d594fSAndroid Build Coastguard Worker self._threads = [] 192*795d594fSAndroid Build Coastguard Worker self._summary = None 193*795d594fSAndroid Build Coastguard Worker self.Process(input, body) 194*795d594fSAndroid Build Coastguard Worker 195*795d594fSAndroid Build Coastguard Worker self.Finalize(header) 196*795d594fSAndroid Build Coastguard Worker 197*795d594fSAndroid Build Coastguard Worker input.close() 198*795d594fSAndroid Build Coastguard Worker header.close() 199*795d594fSAndroid Build Coastguard Worker body.close() 200*795d594fSAndroid Build Coastguard Worker 201*795d594fSAndroid Build Coastguard Workerdef main(): 202*795d594fSAndroid Build Coastguard Worker Rewriter().ProcessFile(sys.argv[1]) 203*795d594fSAndroid Build Coastguard Worker header_name = sys.argv[1] + '.header' 204*795d594fSAndroid Build Coastguard Worker body_name = sys.argv[1] + '.body' 205*795d594fSAndroid Build Coastguard Worker print 'Results have been written to %s and %s.' % (header_name, body_name) 206*795d594fSAndroid Build Coastguard Worker print 'Concatenate the files to get a result usable with traceview.' 207*795d594fSAndroid Build Coastguard Worker sys.exit(0) 208*795d594fSAndroid Build Coastguard Worker 209*795d594fSAndroid Build Coastguard Workerif __name__ == '__main__': 210*795d594fSAndroid Build Coastguard Worker main()