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