xref: /aosp_15_r20/art/tools/stream-trace-converter.py (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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()