blob: ddaaa630cb3bd6acb36a93ac467815383bfeadb6 [file] [log] [blame]
Jamie Gennis92791472012-03-05 17:33:58 -08001#!/usr/bin/env python
2
3#
4# Copyright 2012, The Android Open Source Project
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19"""Android system-wide tracing utility.
20
21This is a tool for capturing a trace that includes data from both userland and
22the kernel. It creates an HTML file for visualizing the trace.
23"""
24
Jamie Gennis1bf4a492012-03-13 18:07:36 -070025import errno, optparse, os, select, subprocess, sys, time
Jamie Gennis92791472012-03-05 17:33:58 -080026
27def main():
28 parser = optparse.OptionParser()
29 parser.add_option('-o', dest='output_file', help='write HTML to FILE',
30 default='trace.html', metavar='FILE')
31 parser.add_option('-t', '--time', dest='trace_time', type='int',
32 help='trace for N seconds', metavar='N')
Jamie Gennis98ef97d2012-03-07 16:06:53 -080033 parser.add_option('-b', '--buf-size', dest='trace_buf_size', type='int',
34 help='use a trace buffer size of N KB', metavar='N')
35 parser.add_option('-f', '--cpu-freq', dest='trace_cpu_freq', default=False,
36 action='store_true', help='trace CPU frequency changes')
37 parser.add_option('-l', '--cpu-load', dest='trace_cpu_load', default=False,
38 action='store_true', help='trace CPU load')
Jamie Gennis92791472012-03-05 17:33:58 -080039 parser.add_option('-w', '--workqueue', dest='trace_workqueue', default=False,
40 action='store_true', help='trace the kernel workqueues')
41 options, args = parser.parse_args()
42
43 atrace_args = ['adb', 'shell', 'atrace', '-s']
Jamie Gennis98ef97d2012-03-07 16:06:53 -080044 if options.trace_cpu_freq:
45 atrace_args.append('-f')
46 if options.trace_cpu_load:
47 atrace_args.append('-l')
Jamie Gennis92791472012-03-05 17:33:58 -080048 if options.trace_workqueue:
49 atrace_args.append('-w')
50 if options.trace_time is not None:
51 if options.trace_time > 0:
52 atrace_args.extend(['-t', str(options.trace_time)])
53 else:
54 parser.error('the trace time must be a positive number')
Jamie Gennis98ef97d2012-03-07 16:06:53 -080055 if options.trace_buf_size is not None:
56 if options.trace_buf_size > 0:
57 atrace_args.extend(['-b', str(options.trace_buf_size)])
58 else:
59 parser.error('the trace buffer size must be a positive number')
Jamie Gennis92791472012-03-05 17:33:58 -080060
61 html_filename = options.output_file
62 html_file = open(html_filename, 'w')
63 html_file.write(html_prefix)
64
65 trace_started = False
Jamie Gennis1bf4a492012-03-13 18:07:36 -070066 leftovers = ''
67 adb = subprocess.Popen(atrace_args, stdout=subprocess.PIPE,
Jamie Gennis92791472012-03-05 17:33:58 -080068 stderr=subprocess.PIPE)
69 while True:
Jamie Gennis1bf4a492012-03-13 18:07:36 -070070 ready = select.select([adb.stdout, adb.stderr], [], [adb.stdout, adb.stderr])
71 if adb.stderr in ready[0]:
72 err = os.read(adb.stderr.fileno(), 4096)
73 sys.stderr.write(err)
74 sys.stderr.flush()
75 if adb.stdout in ready[0]:
76 out = os.read(adb.stdout.fileno(), 4096)
Jamie Gennis92791472012-03-05 17:33:58 -080077 if not trace_started:
Jamie Gennis1bf4a492012-03-13 18:07:36 -070078 out = leftovers + out
79 lines = out.splitlines(True)
80 out, leftovers = '', ''
Jamie Gennis92791472012-03-05 17:33:58 -080081 for i, line in enumerate(lines):
Jamie Gennis1bf4a492012-03-13 18:07:36 -070082 if line.replace('\r', '') == 'TRACE:\n':
83 sys.stdout.write("downloading trace...")
Jamie Gennis92791472012-03-05 17:33:58 -080084 sys.stdout.flush()
Jamie Gennis1bf4a492012-03-13 18:07:36 -070085 out = ''.join(lines[i+1:])
Jamie Gennis92791472012-03-05 17:33:58 -080086 trace_started = True
87 break
Jamie Gennis1bf4a492012-03-13 18:07:36 -070088 elif 'TRACE:'.startswith(line) and i == len(lines) - 1:
89 leftovers = line
Jamie Gennis92791472012-03-05 17:33:58 -080090 else:
Jamie Gennis1bf4a492012-03-13 18:07:36 -070091 sys.stdout.write(line)
Jamie Gennis92791472012-03-05 17:33:58 -080092 sys.stdout.flush()
Jamie Gennis1bf4a492012-03-13 18:07:36 -070093 html_out = out.replace('\n', '\\n\\\n').replace('\r', '')
94 if len(html_out) > 0:
95 html_file.write(html_out)
96 result = adb.poll()
Jamie Gennis92791472012-03-05 17:33:58 -080097 if result is not None:
98 break
99 if result != 0:
100 print sys.stderr, 'adb returned error code %d' % result
101 else:
102 html_file.write(html_suffix)
103 html_file.close()
Jamie Gennis1bf4a492012-03-13 18:07:36 -0700104 print " done\n\n wrote file://%s/%s\n" % (os.getcwd(), options.output_file)
Jamie Gennis92791472012-03-05 17:33:58 -0800105
106html_prefix = """<!DOCTYPE HTML>
107<html>
108<head i18n-values="dir:textdirection;">
109<title>Android System Trace</title>
Jamie Gennis1bf4a492012-03-13 18:07:36 -0700110<link rel="stylesheet" href="http://www.corp.google.com/~jgennis/android_tracing/0.1/viewer/timeline.css">
111<link rel="stylesheet" href="http://www.corp.google.com/~jgennis/android_tracing/0.1/viewer/timeline_view.css">
Jamie Gennis92791472012-03-05 17:33:58 -0800112<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/shared/js/cr.js"></script>
113<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/shared/js/cr/event_target.js"></script>
114<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/shared/js/cr/ui.js"></script>
115<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/shared/js/util.js"></script>
116<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/viewer/timeline_model.js"></script>
117<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/viewer/linux_perf_importer.js"></script>
118<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/viewer/trace_event_importer.js"></script>
119<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/viewer/sorted_array_utils.js"></script>
120<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/viewer/measuring_stick.js"></script>
121<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/viewer/timeline.js"></script>
122<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/viewer/timeline_track.js"></script>
123<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/viewer/timeline_view.js"></script>
124<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/viewer/fast_rect_renderer.js"></script>
125<script src="http://www.corp.google.com/~jgennis/android_tracing/0.1/viewer/test_utils.js"></script>
126<style>
127 .view {
128 overflow: hidden;
129 position: absolute;
130 top: 0;
131 bottom: 0;
132 left: 0;
133 right: 0;
134 }
135</style>
136</head>
137<body>
138 <div class="view">
139 </div>
140 <script>
141 var linuxPerfData = "\\
142"""
143
Jamie Gennis1bf4a492012-03-13 18:07:36 -0700144html_suffix = """ dummy-0000 [000] 0.0: 0: trace_event_clock_sync: parent_ts=0.0\\n";
Jamie Gennis92791472012-03-05 17:33:58 -0800145 var timelineViewEl;
146 function onLoad() {
147 reload();
148 }
149 function reload() {
150 if (!linuxPerfData)
151 return;
152
153 var m = new tracing.TimelineModel();
154 m.importEvents("[]", true, [linuxPerfData]);
155
156 timelineViewEl = document.querySelector('.view');
157 cr.ui.decorate(timelineViewEl, tracing.TimelineView);
158 timelineViewEl.model = m;
159 timelineViewEl.tabIndex = 1;
160 timelineViewEl.timeline.focusElement = timelineViewEl;
161 }
162
163 document.addEventListener('DOMContentLoaded', onLoad);
164 </script>
165</body>
166</html>
167"""
168
169if __name__ == '__main__':
170 main()