blob: 4e29572e6e059a6ed0ac75d05ec0491dba39b7da [file] [log] [blame]
Jamie Gennis664f21b2013-06-03 16:40:54 -07001#!/usr/bin/env python
2
3# Copyright (c) 2011 The Chromium Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""Android system-wide tracing utility.
8
9This is a tool for capturing a trace that includes data from both userland and
10the kernel. It creates an HTML file for visualizing the trace.
11"""
12
13import errno, optparse, os, select, subprocess, sys, time, zlib
14
15# This list is based on the tags in frameworks/native/include/utils/Trace.h.
16trace_tag_bits = {
17 'gfx': 1<<1,
18 'input': 1<<2,
19 'view': 1<<3,
20 'webview': 1<<4,
21 'wm': 1<<5,
22 'am': 1<<6,
23 'sync': 1<<7,
24 'audio': 1<<8,
25 'video': 1<<9,
26 'camera': 1<<10,
27}
28
Chris Craik93216d02015-03-05 13:58:42 -080029flattened_html_file = 'systrace_trace_viewer.html'
Jamie Gennis664f21b2013-06-03 16:40:54 -070030
31def add_adb_serial(command, serial):
32 if serial != None:
33 command.insert(1, serial)
34 command.insert(1, '-s')
35
36def main():
37 parser = optparse.OptionParser()
38 parser.add_option('-o', dest='output_file', help='write HTML to FILE',
39 default='trace.html', metavar='FILE')
40 parser.add_option('-t', '--time', dest='trace_time', type='int',
41 help='trace for N seconds', metavar='N')
42 parser.add_option('-b', '--buf-size', dest='trace_buf_size', type='int',
43 help='use a trace buffer size of N KB', metavar='N')
44 parser.add_option('-d', '--disk', dest='trace_disk', default=False,
45 action='store_true', help='trace disk I/O (requires root)')
46 parser.add_option('-f', '--cpu-freq', dest='trace_cpu_freq', default=False,
47 action='store_true', help='trace CPU frequency changes')
48 parser.add_option('-i', '--cpu-idle', dest='trace_cpu_idle', default=False,
49 action='store_true', help='trace CPU idle events')
50 parser.add_option('-l', '--cpu-load', dest='trace_cpu_load', default=False,
51 action='store_true', help='trace CPU load')
52 parser.add_option('-s', '--no-cpu-sched', dest='trace_cpu_sched', default=True,
53 action='store_false', help='inhibit tracing CPU ' +
54 'scheduler (allows longer trace times by reducing data ' +
55 'rate into buffer)')
56 parser.add_option('-u', '--bus-utilization', dest='trace_bus_utilization',
57 default=False, action='store_true',
58 help='trace bus utilization (requires root)')
59 parser.add_option('-w', '--workqueue', dest='trace_workqueue', default=False,
60 action='store_true', help='trace the kernel workqueues ' +
61 '(requires root)')
62 parser.add_option('--set-tags', dest='set_tags', action='store',
63 help='set the enabled trace tags and exit; set to a ' +
64 'comma separated list of: ' +
65 ', '.join(trace_tag_bits.iterkeys()))
66 parser.add_option('--link-assets', dest='link_assets', default=False,
67 action='store_true', help='link to original CSS or JS resources '
68 'instead of embedding them')
69 parser.add_option('--from-file', dest='from_file', action='store',
70 help='read the trace from a file rather than running a live trace')
71 parser.add_option('--asset-dir', dest='asset_dir', default='trace-viewer',
72 type='string', help='')
73 parser.add_option('-e', '--serial', dest='device_serial', type='string',
74 help='adb device serial number')
75 options, args = parser.parse_args()
76
Chris Craik93216d02015-03-05 13:58:42 -080077 if options.link_assets or options.asset_dir != 'trace-viewer':
78 parser.error('--link-assets and --asset-dir is deprecated.')
79
Jamie Gennis664f21b2013-06-03 16:40:54 -070080 if options.set_tags:
81 flags = 0
82 tags = options.set_tags.split(',')
83 for tag in tags:
84 try:
85 flags |= trace_tag_bits[tag]
86 except KeyError:
87 parser.error('unrecognized tag: %s\nknown tags are: %s' %
88 (tag, ', '.join(trace_tag_bits.iterkeys())))
89 atrace_args = ['adb', 'shell', 'setprop', 'debug.atrace.tags.enableflags', hex(flags)]
90 add_adb_serial(atrace_args, options.device_serial)
91 try:
92 subprocess.check_call(atrace_args)
93 except subprocess.CalledProcessError, e:
94 print >> sys.stderr, 'unable to set tags: %s' % e
95 print '\nSet enabled tags to: %s\n' % ', '.join(tags)
96 print ('You will likely need to restart the Android framework for this to ' +
97 'take effect:\n\n adb shell stop\n adb shell ' +
98 'start\n')
99 return
100
101 atrace_args = ['adb', 'shell', 'atrace', '-z']
102 add_adb_serial(atrace_args, options.device_serial)
103
104 if options.trace_disk:
105 atrace_args.append('-d')
106 if options.trace_cpu_freq:
107 atrace_args.append('-f')
108 if options.trace_cpu_idle:
109 atrace_args.append('-i')
110 if options.trace_cpu_load:
111 atrace_args.append('-l')
112 if options.trace_cpu_sched:
113 atrace_args.append('-s')
114 if options.trace_bus_utilization:
115 atrace_args.append('-u')
116 if options.trace_workqueue:
117 atrace_args.append('-w')
118 if options.trace_time is not None:
119 if options.trace_time > 0:
120 atrace_args.extend(['-t', str(options.trace_time)])
121 else:
122 parser.error('the trace time must be a positive number')
123 if options.trace_buf_size is not None:
124 if options.trace_buf_size > 0:
125 atrace_args.extend(['-b', str(options.trace_buf_size)])
126 else:
127 parser.error('the trace buffer size must be a positive number')
128
129 if options.from_file is not None:
130 atrace_args = ['cat', options.from_file]
131
132 script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
133
Chris Craik93216d02015-03-05 13:58:42 -0800134 with open(os.path.join(script_dir, flattened_html_file), 'r') as f:
135 trace_viewer_html = f.read()
Jamie Gennis664f21b2013-06-03 16:40:54 -0700136
137 html_filename = options.output_file
138
139 trace_started = False
140 leftovers = ''
141 adb = subprocess.Popen(atrace_args, stdout=subprocess.PIPE,
142 stderr=subprocess.PIPE)
143 dec = zlib.decompressobj()
144 while True:
145 ready = select.select([adb.stdout, adb.stderr], [], [adb.stdout, adb.stderr])
146 if adb.stderr in ready[0]:
147 err = os.read(adb.stderr.fileno(), 4096)
148 sys.stderr.write(err)
149 sys.stderr.flush()
150 if adb.stdout in ready[0]:
151 out = leftovers + os.read(adb.stdout.fileno(), 4096)
152 if options.from_file is None:
153 out = out.replace('\r\n', '\n')
154 if out.endswith('\r'):
155 out = out[:-1]
156 leftovers = '\r'
157 else:
158 leftovers = ''
159 if not trace_started:
160 lines = out.splitlines(True)
161 out = ''
162 for i, line in enumerate(lines):
163 if line == 'TRACE:\n':
164 sys.stdout.write("downloading trace...")
165 sys.stdout.flush()
166 out = ''.join(lines[i+1:])
Siva Velusamy9c39c342013-07-19 14:10:13 -0700167 html_prefix = read_asset(script_dir, 'prefix.html')
Jamie Gennis664f21b2013-06-03 16:40:54 -0700168 html_file = open(html_filename, 'w')
Chris Craik93216d02015-03-05 13:58:42 -0800169 html_file.write(
170 html_prefix.replace("{{SYSTRACE_TRACE_VIEWER_HTML}}",
171 trace_viewer_html))
Chris Craikad0b04f2015-07-21 13:44:22 -0700172 html_file.write('<!-- BEGIN TRACE -->\n' +
173 ' <script class="trace-data" type="application/text">\n')
Jamie Gennis664f21b2013-06-03 16:40:54 -0700174 trace_started = True
175 break
176 elif 'TRACE:'.startswith(line) and i == len(lines) - 1:
177 leftovers = line + leftovers
178 else:
179 sys.stdout.write(line)
180 sys.stdout.flush()
181 if len(out) > 0:
182 out = dec.decompress(out)
183 html_out = out.replace('\n', '\\n\\\n')
184 if len(html_out) > 0:
185 html_file.write(html_out)
186 result = adb.poll()
187 if result is not None:
188 break
189 if result != 0:
190 print >> sys.stderr, 'adb returned error code %d' % result
191 elif trace_started:
192 html_out = dec.flush().replace('\n', '\\n\\\n').replace('\r', '')
193 if len(html_out) > 0:
194 html_file.write(html_out)
Chris Craikad0b04f2015-07-21 13:44:22 -0700195 html_file.write(' </script>\n<!-- END TRACE -->\n')
Siva Velusamy9c39c342013-07-19 14:10:13 -0700196 html_suffix = read_asset(script_dir, 'suffix.html')
Jamie Gennis664f21b2013-06-03 16:40:54 -0700197 html_file.write(html_suffix)
198 html_file.close()
Jamie Gennis66a37682013-07-15 18:29:18 -0700199 print " done\n\n wrote file://%s\n" % (os.path.abspath(options.output_file))
Jamie Gennis664f21b2013-06-03 16:40:54 -0700200 else:
201 print >> sys.stderr, ('An error occured while capturing the trace. Output ' +
202 'file was not written.')
203
Siva Velusamy9c39c342013-07-19 14:10:13 -0700204def read_asset(src_dir, filename):
205 return open(os.path.join(src_dir, filename)).read()
206
Jamie Gennis664f21b2013-06-03 16:40:54 -0700207if __name__ == '__main__':
208 main()