diff options
Diffstat (limited to 'tools/stream-trace-converter.py')
-rwxr-xr-x | tools/stream-trace-converter.py | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/tools/stream-trace-converter.py b/tools/stream-trace-converter.py new file mode 100755 index 0000000..951b05b --- /dev/null +++ b/tools/stream-trace-converter.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +# +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Script that parses a trace filed produced in streaming mode. The file is broken up into + a header and body part, which, when concatenated, make up a non-streaming trace file that + can be used with traceview.""" + +import sys + +class MyException(Exception): + pass + +class BufferUnderrun(Exception): + pass + +def ReadShortLE(f): + byte1 = f.read(1) + if not byte1: + raise BufferUnderrun() + byte2 = f.read(1) + if not byte2: + raise BufferUnderrun() + return ord(byte1) + (ord(byte2) << 8); + +def WriteShortLE(f, val): + bytes = [ (val & 0xFF), ((val >> 8) & 0xFF) ] + asbytearray = bytearray(bytes) + f.write(asbytearray) + +def ReadIntLE(f): + byte1 = f.read(1) + if not byte1: + raise BufferUnderrun() + byte2 = f.read(1) + if not byte2: + raise BufferUnderrun() + byte3 = f.read(1) + if not byte3: + raise BufferUnderrun() + byte4 = f.read(1) + if not byte4: + raise BufferUnderrun() + return ord(byte1) + (ord(byte2) << 8) + (ord(byte3) << 16) + (ord(byte4) << 24); + +def WriteIntLE(f, val): + bytes = [ (val & 0xFF), ((val >> 8) & 0xFF), ((val >> 16) & 0xFF), ((val >> 24) & 0xFF) ] + asbytearray = bytearray(bytes) + f.write(asbytearray) + +def Copy(input, output, length): + buf = input.read(length) + if len(buf) != length: + raise BufferUnderrun() + output.write(buf) + +class Rewriter: + + def PrintHeader(self, header): + header.write('*version\n'); + header.write('3\n'); + header.write('data-file-overflow=false\n'); + header.write('clock=dual\n'); + header.write('vm=art\n'); + + def ProcessDataHeader(self, input, body): + magic = ReadIntLE(input) + if magic != 0x574f4c53: + raise MyException("Magic wrong") + + WriteIntLE(body, magic) + + version = ReadShortLE(input) + if (version & 0xf0) != 0xf0: + raise MyException("Does not seem to be a streaming trace: %d." % version) + version = version ^ 0xf0 + + if version != 3: + raise MyException("Only support version 3") + + WriteShortLE(body, version) + + # read offset + offsetToData = ReadShortLE(input) - 16 + WriteShortLE(body, offsetToData + 16) + + # copy startWhen + Copy(input, body, 8) + + if version == 1: + self._mRecordSize = 9; + elif version == 2: + self._mRecordSize = 10; + else: + self._mRecordSize = ReadShortLE(input) + WriteShortLE(body, self._mRecordSize) + offsetToData -= 2; + + # Skip over offsetToData bytes + Copy(input, body, offsetToData) + + def ProcessMethod(self, input): + stringLength = ReadShortLE(input) + str = input.read(stringLength) + self._methods.append(str) + print 'New method: %s' % str + + def ProcessThread(self, input): + tid = ReadShortLE(input) + stringLength = ReadShortLE(input) + str = input.read(stringLength) + self._threads.append('%d\t%s\n' % (tid, str)) + print 'New thread: %d/%s' % (tid, str) + + def ProcessSpecial(self, input): + code = ord(input.read(1)) + if code == 1: + self.ProcessMethod(input) + elif code == 2: + self.ProcessThread(input) + else: + raise MyException("Unknown special!") + + def Process(self, input, body): + try: + while True: + threadId = ReadShortLE(input) + if threadId == 0: + self.ProcessSpecial(input) + else: + # Regular package, just copy + WriteShortLE(body, threadId) + Copy(input, body, self._mRecordSize - 2) + except BufferUnderrun: + print 'Buffer underrun, file was probably truncated. Results should still be usable.' + + def Finalize(self, header): + header.write('*threads\n') + for t in self._threads: + header.write(t) + header.write('*methods\n') + for m in self._methods: + header.write(m) + header.write('*end\n') + + def ProcessFile(self, filename): + input = open(filename, 'rb') # Input file + header = open(filename + '.header', 'w') # Header part + body = open(filename + '.body', 'wb') # Body part + + self.PrintHeader(header) + + self.ProcessDataHeader(input, body) + + self._methods = [] + self._threads = [] + self.Process(input, body) + + self.Finalize(header) + + input.close() + header.close() + body.close() + +def main(): + Rewriter().ProcessFile(sys.argv[1]) + header_name = sys.argv[1] + '.header' + body_name = sys.argv[1] + '.body' + print 'Results have been written to %s and %s.' % (header_name, body_name) + print 'Concatenate the files to get a result usable with traceview.' + sys.exit(0) + +if __name__ == '__main__': + main()
\ No newline at end of file |