blob: 38443febd1a20726c56b218e49ac455937982e94 [file] [log] [blame]
Jamie Gennis92791472012-03-05 17:33:58 -08001#!/usr/bin/env python
2
Jamie Gennis4b56a2b2012-04-28 01:06:56 -07003# 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.
Jamie Gennis92791472012-03-05 17:33:58 -08006
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
Chris Craikad0b04f2015-07-21 13:44:22 -070013import sys
Jamie Gennis92791472012-03-05 17:33:58 -080014
Chris Craikad0b04f2015-07-21 13:44:22 -070015# Make sure we're using a new enough version of Python.
16# The flags= parameter of re.sub() is new in Python 2.7.
17if sys.version_info[:2] < (2, 7):
18 print >> sys.stderr, '\nThis script requires Python 2.7 or newer.'
19 sys.exit(1)
Jamie Gennis2da489c2012-09-19 18:06:29 -070020
Chris Craikad0b04f2015-07-21 13:44:22 -070021# pylint: disable=g-bad-import-order,g-import-not-at-top
22import imp
23import optparse
24import os
Jamie Gennis664f21b2013-06-03 16:40:54 -070025
Chris Craikad0b04f2015-07-21 13:44:22 -070026import util
Jamie Gennis664f21b2013-06-03 16:40:54 -070027
Jamie Gennis664f21b2013-06-03 16:40:54 -070028
Chris Craikad0b04f2015-07-21 13:44:22 -070029# The default agent directory.
30DEFAULT_AGENT_DIR = 'agents'
Jamie Gennis664f21b2013-06-03 16:40:54 -070031
Jamie Gennis664f21b2013-06-03 16:40:54 -070032
Chris Craikad0b04f2015-07-21 13:44:22 -070033def parse_options(argv):
34 """Parses and checks the command-line options.
Jamie Gennis664f21b2013-06-03 16:40:54 -070035
Chris Craikad0b04f2015-07-21 13:44:22 -070036 Returns:
37 A tuple containing the options structure and a list of categories to
38 be traced.
39 """
40 usage = 'Usage: %prog [options] [category1 [category2 ...]]'
41 desc = 'Example: %prog -b 32768 -t 15 gfx input view sched freq'
Jamie Gennisfe4c5942012-11-18 18:15:22 -080042 parser = optparse.OptionParser(usage=usage, description=desc)
Jamie Gennis92791472012-03-05 17:33:58 -080043 parser.add_option('-o', dest='output_file', help='write HTML to FILE',
44 default='trace.html', metavar='FILE')
45 parser.add_option('-t', '--time', dest='trace_time', type='int',
46 help='trace for N seconds', metavar='N')
Jamie Gennis98ef97d2012-03-07 16:06:53 -080047 parser.add_option('-b', '--buf-size', dest='trace_buf_size', type='int',
48 help='use a trace buffer size of N KB', metavar='N')
Jamie Gennis553ec562012-11-20 17:45:49 -080049 parser.add_option('-k', '--ktrace', dest='kfuncs', action='store',
Chris Craikad0b04f2015-07-21 13:44:22 -070050 help='specify a comma-separated list of kernel functions '
51 'to trace')
52 parser.add_option('-l', '--list-categories', dest='list_categories',
53 default=False, action='store_true',
54 help='list the available categories and exit')
Jamie Gennisb9a5fc82013-03-27 19:55:09 -070055 parser.add_option('-a', '--app', dest='app_name', default=None, type='string',
Chris Craikad0b04f2015-07-21 13:44:22 -070056 action='store',
57 help='enable application-level tracing for comma-separated '
Jamie Gennisb9a5fc82013-03-27 19:55:09 -070058 'list of app cmdlines')
Jeff Brownc6e750f2014-08-15 16:27:54 -070059 parser.add_option('--no-fix-threads', dest='fix_threads', default=True,
Chris Craikad0b04f2015-07-21 13:44:22 -070060 action='store_false',
61 help='don\'t fix missing or truncated thread names')
Adrian Roos61c9bc22015-05-06 19:06:01 -070062 parser.add_option('--no-fix-circular', dest='fix_circular', default=True,
Chris Craikad0b04f2015-07-21 13:44:22 -070063 action='store_false',
64 help='don\'t fix truncated circular traces')
65 parser.add_option('--no-compress', dest='compress_trace_data',
66 default=True, action='store_false',
67 help='Tell the device not to send the trace data in '
68 'compressed form.')
Jeff Brown595ae1e2012-05-22 14:52:13 -070069 parser.add_option('--link-assets', dest='link_assets', default=False,
Chris Craikad0b04f2015-07-21 13:44:22 -070070 action='store_true',
71 help='(deprecated)')
Glenn Kastena0cfa1d2012-10-08 15:40:30 -070072 parser.add_option('--from-file', dest='from_file', action='store',
Chris Craikad0b04f2015-07-21 13:44:22 -070073 help='read the trace from a file (compressed) rather than '
74 'running a live trace')
Jamie Gennis2da489c2012-09-19 18:06:29 -070075 parser.add_option('--asset-dir', dest='asset_dir', default='trace-viewer',
Chris Craikad0b04f2015-07-21 13:44:22 -070076 type='string', help='(deprecated)')
Keun young Parkde427be2012-08-30 15:17:13 -070077 parser.add_option('-e', '--serial', dest='device_serial', type='string',
78 help='adb device serial number')
Chris Craikad0b04f2015-07-21 13:44:22 -070079 parser.add_option('--agent-dirs', dest='agent_dirs', type='string',
80 help='the directories of additional systrace agent modules.'
81 ' The directories should be comma separated, e.g., '
82 '--agent-dirs=dir1,dir2,dir3. Directory |%s| is the default'
83 ' agent directory and will always be checked.'
84 % DEFAULT_AGENT_DIR)
Jamie Gennisfe4c5942012-11-18 18:15:22 -080085
Chris Craikad0b04f2015-07-21 13:44:22 -070086 options, categories = parser.parse_args(argv[1:])
Jamie Gennis92791472012-03-05 17:33:58 -080087
Chris Craikb122baf2015-03-05 13:58:42 -080088 if options.link_assets or options.asset_dir != 'trace-viewer':
Chris Craikad0b04f2015-07-21 13:44:22 -070089 parser.error('--link-assets and --asset-dir are deprecated.')
Chris Craikb122baf2015-03-05 13:58:42 -080090
Chris Craikad0b04f2015-07-21 13:44:22 -070091 if (options.trace_time is not None) and (options.trace_time <= 0):
92 parser.error('the trace time must be a positive number')
Jamie Gennisfe4c5942012-11-18 18:15:22 -080093
Chris Craikad0b04f2015-07-21 13:44:22 -070094 if (options.trace_buf_size is not None) and (options.trace_buf_size <= 0):
95 parser.error('the trace buffer size must be a positive number')
Jamie Gennisb9a5fc82013-03-27 19:55:09 -070096
Chris Craikad0b04f2015-07-21 13:44:22 -070097 return (options, categories)
Jamie Gennisfe4c5942012-11-18 18:15:22 -080098
Jamie Gennisb9a5fc82013-03-27 19:55:09 -070099
Chris Craikad0b04f2015-07-21 13:44:22 -0700100def write_trace_html(html_filename, script_dir, agents):
101 """Writes out a trace html file.
Jamie Gennis553ec562012-11-20 17:45:49 -0800102
Chris Craikad0b04f2015-07-21 13:44:22 -0700103 Args:
104 html_filename: The name of the file to write.
105 script_dir: The directory containing this script.
106 agents: The systrace agents.
107 """
108 html_prefix = read_asset(script_dir, 'prefix.html')
109 html_suffix = read_asset(script_dir, 'suffix.html')
110 trace_viewer_html = read_asset(script_dir, 'systrace_trace_viewer.html')
Jamie Gennisfe4c5942012-11-18 18:15:22 -0800111
Chris Craikad0b04f2015-07-21 13:44:22 -0700112 # Open the file in binary mode to prevent python from changing the
113 # line endings.
114 html_file = open(html_filename, 'wb')
115 html_file.write(html_prefix.replace('{{SYSTRACE_TRACE_VIEWER_HTML}}',
116 trace_viewer_html))
Jeff Brownc6e750f2014-08-15 16:27:54 -0700117
Chris Craikad0b04f2015-07-21 13:44:22 -0700118 html_file.write('<!-- BEGIN TRACE -->\n')
119 for a in agents:
120 html_file.write(' <script class="')
121 html_file.write(a.get_class_name())
122 html_file.write('" type="application/text">\n')
123 html_file.write(a.get_trace_data())
124 html_file.write(' </script>\n')
125 html_file.write('<!-- END TRACE -->\n')
126
127 html_file.write(html_suffix)
128 html_file.close()
129 print '\n wrote file://%s\n' % os.path.abspath(html_filename)
130
131
132def create_agents(options, categories):
133 """Create systrace agents.
134
135 This function will search systrace agent modules in agent directories and
136 create the corresponding systrace agents.
137 Args:
138 options: The command-line options.
139 categories: The trace categories to capture.
140 Returns:
141 The list of systrace agents.
142 """
143 agent_dirs = [os.path.join(os.path.dirname(__file__), DEFAULT_AGENT_DIR)]
144 if options.agent_dirs:
145 agent_dirs.extend(options.agent_dirs.split(','))
146
147 agents = []
148 for agent_dir in agent_dirs:
149 if not agent_dir:
150 continue
151 for filename in os.listdir(agent_dir):
152 (module_name, ext) = os.path.splitext(filename)
153 if ext != '.py' or module_name == '__init__':
154 continue
155 (f, pathname, data) = imp.find_module(module_name, [agent_dir])
156 try:
157 module = imp.load_module(module_name, f, pathname, data)
158 finally:
159 if f:
160 f.close()
161 if module:
162 agent = module.try_create_agent(options, categories)
163 if not agent:
164 continue
165 agents.append(agent)
166 return agents
167
168
169def main():
170 options, categories = parse_options(sys.argv)
171 agents = create_agents(options, categories)
172
173 if not agents:
174 dirs = DEFAULT_AGENT_DIR
175 if options.agent_dirs:
176 dirs += ',' + options.agent_dirs
177 print >> sys.stderr, ('No systrace agent is available in directories |%s|.'
178 % dirs)
179 sys.exit(1)
180
181 for a in agents:
182 a.start()
183
184 for a in agents:
185 a.collect_result()
186 if not a.expect_trace():
187 # Nothing more to do.
188 return
Glenn Kastena0cfa1d2012-10-08 15:40:30 -0700189
Jamie Gennis4b56a2b2012-04-28 01:06:56 -0700190 script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
Chris Craikad0b04f2015-07-21 13:44:22 -0700191 write_trace_html(options.output_file, script_dir, agents)
Jeff Brown595ae1e2012-05-22 14:52:13 -0700192
Jamie Gennis92791472012-03-05 17:33:58 -0800193
Siva Velusamy48ea0762013-07-19 11:03:37 -0700194def read_asset(src_dir, filename):
195 return open(os.path.join(src_dir, filename)).read()
196
Jeff Brown595ae1e2012-05-22 14:52:13 -0700197
Jamie Gennis92791472012-03-05 17:33:58 -0800198if __name__ == '__main__':
199 main()