140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe#!/usr/bin/env python 240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# 340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# Copyright (C) 2014 The Android Open Source Project 440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# 540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# Licensed under the Apache License, Version 2.0 (the "License"); 640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# you may not use this file except in compliance with the License. 740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# You may obtain a copy of the License at 840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# 940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# http://www.apache.org/licenses/LICENSE-2.0 1040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# 1140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# Unless required by applicable law or agreed to in writing, software 1240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# distributed under the License is distributed on an "AS IS" BASIS, 1340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# See the License for the specific language governing permissions and 1540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe# limitations under the License. 1640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 1740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe"""Script that parses a trace filed produced in streaming mode. The file is broken up into 1840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe a header and body part, which, when concatenated, make up a non-streaming trace file that 1940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe can be used with traceview.""" 2040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 2140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampeimport sys 2240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 2340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampeclass MyException(Exception): 2440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe pass 2540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 2640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampeclass BufferUnderrun(Exception): 2740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe pass 2840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 2940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampedef ReadShortLE(f): 3040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe byte1 = f.read(1) 3140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe if not byte1: 3240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe raise BufferUnderrun() 3340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe byte2 = f.read(1) 3440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe if not byte2: 3540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe raise BufferUnderrun() 3640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe return ord(byte1) + (ord(byte2) << 8); 3740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 3840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampedef WriteShortLE(f, val): 3940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe bytes = [ (val & 0xFF), ((val >> 8) & 0xFF) ] 4040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe asbytearray = bytearray(bytes) 4140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe f.write(asbytearray) 4240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 4340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampedef ReadIntLE(f): 4440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe byte1 = f.read(1) 4540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe if not byte1: 4640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe raise BufferUnderrun() 4740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe byte2 = f.read(1) 4840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe if not byte2: 4940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe raise BufferUnderrun() 5040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe byte3 = f.read(1) 5140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe if not byte3: 5240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe raise BufferUnderrun() 5340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe byte4 = f.read(1) 5440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe if not byte4: 5540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe raise BufferUnderrun() 5640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe return ord(byte1) + (ord(byte2) << 8) + (ord(byte3) << 16) + (ord(byte4) << 24); 5740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 5840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampedef WriteIntLE(f, val): 5940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe bytes = [ (val & 0xFF), ((val >> 8) & 0xFF), ((val >> 16) & 0xFF), ((val >> 24) & 0xFF) ] 6040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe asbytearray = bytearray(bytes) 6140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe f.write(asbytearray) 6240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 6340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampedef Copy(input, output, length): 6440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe buf = input.read(length) 6540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe if len(buf) != length: 6640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe raise BufferUnderrun() 6740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe output.write(buf) 6840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 6940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampeclass Rewriter: 7040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 7140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe def PrintHeader(self, header): 7240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe header.write('*version\n'); 7340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe header.write('3\n'); 7440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe header.write('data-file-overflow=false\n'); 7540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe header.write('clock=dual\n'); 7640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe header.write('vm=art\n'); 7740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 7840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe def ProcessDataHeader(self, input, body): 7940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe magic = ReadIntLE(input) 8040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe if magic != 0x574f4c53: 8140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe raise MyException("Magic wrong") 8240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 8340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe WriteIntLE(body, magic) 8440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 8540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe version = ReadShortLE(input) 8640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe if (version & 0xf0) != 0xf0: 8740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe raise MyException("Does not seem to be a streaming trace: %d." % version) 8840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe version = version ^ 0xf0 8940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 9040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe if version != 3: 9140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe raise MyException("Only support version 3") 9240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 9340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe WriteShortLE(body, version) 9440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 9540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe # read offset 9640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe offsetToData = ReadShortLE(input) - 16 9740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe WriteShortLE(body, offsetToData + 16) 9840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 9940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe # copy startWhen 10040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe Copy(input, body, 8) 10140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 10240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe if version == 1: 10340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self._mRecordSize = 9; 10440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe elif version == 2: 10540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self._mRecordSize = 10; 10640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe else: 10740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self._mRecordSize = ReadShortLE(input) 10840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe WriteShortLE(body, self._mRecordSize) 10940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe offsetToData -= 2; 11040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 11140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe # Skip over offsetToData bytes 11240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe Copy(input, body, offsetToData) 11340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 11440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe def ProcessMethod(self, input): 11540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe stringLength = ReadShortLE(input) 11640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe str = input.read(stringLength) 11740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self._methods.append(str) 11840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe print 'New method: %s' % str 11940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 12040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe def ProcessThread(self, input): 12140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe tid = ReadShortLE(input) 12240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe stringLength = ReadShortLE(input) 12340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe str = input.read(stringLength) 12440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self._threads.append('%d\t%s\n' % (tid, str)) 12540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe print 'New thread: %d/%s' % (tid, str) 12640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 1278a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou def ProcessTraceSummary(self, input): 1288a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou summaryLength = ReadIntLE(input) 1298a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou str = input.read(summaryLength) 1308a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou self._summary = str 1318a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou print 'Summary: \"%s\"' % str 1328a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou 13340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe def ProcessSpecial(self, input): 13440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe code = ord(input.read(1)) 13540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe if code == 1: 13640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self.ProcessMethod(input) 13740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe elif code == 2: 13840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self.ProcessThread(input) 1398a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou elif code == 3: 1408a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou self.ProcessTraceSummary(input) 14140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe else: 14240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe raise MyException("Unknown special!") 14340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 14440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe def Process(self, input, body): 14540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe try: 14640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe while True: 14740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe threadId = ReadShortLE(input) 14840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe if threadId == 0: 14940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self.ProcessSpecial(input) 15040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe else: 15140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe # Regular package, just copy 15240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe WriteShortLE(body, threadId) 15340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe Copy(input, body, self._mRecordSize - 2) 15440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe except BufferUnderrun: 15540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe print 'Buffer underrun, file was probably truncated. Results should still be usable.' 15640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 15740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe def Finalize(self, header): 1588a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou # If the summary is present in the input file, use it as the header except 1598a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou # for the methods section which is emtpy in the input file. If not present, 1608a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou # apppend header with the threads that are recorded in the input stream. 1618a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou if (self._summary): 1628a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou # Erase the contents that's already written earlier by PrintHeader. 1638a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou header.seek(0) 1648a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou header.truncate() 1658a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou # Copy the lines from the input summary to the output header until 1668a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou # the methods section is seen. 1678a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou for line in self._summary.splitlines(True): 1688a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou if line == "*methods\n": 1698a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou break 1708a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou else: 1718a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou header.write(line) 1728a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou else: 1738a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou header.write('*threads\n') 1748a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou for t in self._threads: 1758a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou header.write(t) 17640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe header.write('*methods\n') 17740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe for m in self._methods: 17840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe header.write(m) 17940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe header.write('*end\n') 18040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 18140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe def ProcessFile(self, filename): 18240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe input = open(filename, 'rb') # Input file 18340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe header = open(filename + '.header', 'w') # Header part 18440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe body = open(filename + '.body', 'wb') # Body part 18540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 18640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self.PrintHeader(header) 18740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 18840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self.ProcessDataHeader(input, body) 18940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 19040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self._methods = [] 19140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self._threads = [] 1928a5ab9102fe705b63eda6e6bcfe98ee1c03e5a6cShukang Zhou self._summary = None 19340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self.Process(input, body) 19440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 19540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe self.Finalize(header) 19640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 19740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe input.close() 19840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe header.close() 19940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe body.close() 20040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 20140da286d3207d88ed8ff3f5caac4873874603428Andreas Gampedef main(): 20240da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe Rewriter().ProcessFile(sys.argv[1]) 20340da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe header_name = sys.argv[1] + '.header' 20440da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe body_name = sys.argv[1] + '.body' 20540da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe print 'Results have been written to %s and %s.' % (header_name, body_name) 20640da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe print 'Concatenate the files to get a result usable with traceview.' 20740da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe sys.exit(0) 20840da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe 20940da286d3207d88ed8ff3f5caac4873874603428Andreas Gampeif __name__ == '__main__': 21040da286d3207d88ed8ff3f5caac4873874603428Andreas Gampe main()