Move to Android N-MR1 SDK.
[android_tools.git] / sdk / platform-tools / systrace / catapult / systrace / systrace / run_systrace.py
blob815daa7a86af2a7c79541dbdc28864362471b6b8
1 #!/usr/bin/env python
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.
7 """Android system-wide tracing utility.
9 This is a tool for capturing a trace that includes data from both userland and
10 the kernel. It creates an HTML file for visualizing the trace.
11 """
13 # Make sure we're using a new enough version of Python.
14 # The flags= parameter of re.sub() is new in Python 2.7. And Systrace does not
15 # support Python 3 yet.
17 import sys
19 version = sys.version_info[:2]
20 if version != (2, 7):
21 sys.stderr.write('This script does not support Python %d.%d. '
22 'Please use Python 2.7.\n' % version)
23 sys.exit(1)
26 import optparse
27 import os
28 import time
29 from distutils.spawn import find_executable
31 _SYSTRACE_DIR = os.path.abspath(
32 os.path.join(os.path.dirname(__file__), os.path.pardir))
33 _CATAPULT_DIR = os.path.join(
34 os.path.dirname(os.path.abspath(__file__)), os.path.pardir, os.path.pardir)
35 _DEVIL_DIR = os.path.join(_CATAPULT_DIR, 'devil')
36 if _DEVIL_DIR not in sys.path:
37 sys.path.insert(0, _DEVIL_DIR)
38 if _SYSTRACE_DIR not in sys.path:
39 sys.path.insert(0, _SYSTRACE_DIR)
41 from devil import devil_env
42 from devil.android.sdk import adb_wrapper
43 from systrace import systrace_runner
44 from systrace.tracing_agents import atrace_agent
45 from systrace.tracing_agents import atrace_from_file_agent
46 from systrace.tracing_agents import battor_trace_agent
47 from systrace.tracing_agents import ftrace_agent
49 ALL_MODULES = [atrace_agent, atrace_from_file_agent,
50 battor_trace_agent, ftrace_agent]
53 def _get_default_serial():
54 if 'ANDROID_SERIAL' in os.environ:
55 return os.environ['ANDROID_SERIAL']
56 return None
59 def parse_options(argv):
60 """Parses and checks the command-line options.
62 Returns:
63 A tuple containing the options structure and a list of categories to
64 be traced.
65 """
66 usage = 'Usage: %prog [options] [category1 [category2 ...]]'
67 desc = 'Example: %prog -b 32768 -t 15 gfx input view sched freq'
68 parser = optparse.OptionParser(usage=usage, description=desc)
69 parser.add_option('-o', dest='output_file', help='write trace output to FILE',
70 default=None, metavar='FILE')
71 parser.add_option('-t', '--time', dest='trace_time', type='int',
72 help='trace for N seconds', metavar='N')
73 parser.add_option('-l', '--list-categories', dest='list_categories',
74 default=False, action='store_true',
75 help='list the available categories and exit')
76 parser.add_option('-j', '--json', dest='write_json',
77 default=False, action='store_true',
78 help='write a JSON file')
79 parser.add_option('--link-assets', dest='link_assets', default=False,
80 action='store_true',
81 help='(deprecated)')
82 parser.add_option('--from-file', dest='from_file', action='store',
83 help='read the trace from a file (compressed) rather than'
84 'running a live trace')
85 parser.add_option('--asset-dir', dest='asset_dir', default='trace-viewer',
86 type='string', help='(deprecated)')
87 parser.add_option('-e', '--serial', dest='device_serial_number',
88 default=_get_default_serial(),
89 type='string', help='adb device serial number')
90 parser.add_option('--target', dest='target', default='android', type='string',
91 help='chose tracing target (android or linux)')
92 parser.add_option('--timeout', dest='timeout', type='int',
93 help='timeout for start and stop tracing (seconds)')
94 parser.add_option('--collection-timeout', dest='collection_timeout',
95 type='int', help='timeout for data collection (seconds)')
97 atrace_ftrace_options = optparse.OptionGroup(parser,
98 'Atrace and Ftrace options')
99 atrace_ftrace_options.add_option('-b', '--buf-size', dest='trace_buf_size',
100 type='int', help='use a trace buffer size '
101 ' of N KB', metavar='N')
102 atrace_ftrace_options.add_option('--no-fix-threads', dest='fix_threads',
103 default=True, action='store_false',
104 help='don\'t fix missing or truncated '
105 'thread names')
106 atrace_ftrace_options.add_option('--no-fix-tgids', dest='fix_tgids',
107 default=True, action='store_false',
108 help='Do not run extra commands to restore'
109 ' missing thread to thread group id '
110 'mappings.')
111 atrace_ftrace_options.add_option('--no-fix-circular', dest='fix_circular',
112 default=True, action='store_false',
113 help='don\'t fix truncated circular traces')
114 parser.add_option_group(atrace_ftrace_options)
116 # Add the other agent parsing options to the parser. For Systrace on the
117 # command line, all agents are added. For Android, only the compatible agents
118 # will be added.
119 for module in ALL_MODULES:
120 option_group = module.add_options(parser)
121 if option_group:
122 parser.add_option_group(option_group)
124 options, categories = parser.parse_args(argv[1:])
126 if options.output_file is None:
127 options.output_file = 'trace.json' if options.write_json else 'trace.html'
129 if options.link_assets or options.asset_dir != 'trace-viewer':
130 parser.error('--link-assets and --asset-dir are deprecated.')
132 if options.trace_time and options.trace_time < 0:
133 parser.error('the trace time must be a non-negative number')
135 if (options.trace_buf_size is not None) and (options.trace_buf_size <= 0):
136 parser.error('the trace buffer size must be a positive number')
138 return (options, categories)
141 def initialize_devil():
142 """Initialize devil to use adb from $PATH"""
143 adb_path = find_executable('adb')
144 if adb_path is None:
145 print >> sys.stderr, "Unable to find adb, is it in your path?"
146 sys.exit(1)
147 devil_dynamic_config = {
148 'config_type': 'BaseConfig',
149 'dependencies': {
150 'adb': {
151 'file_info': {
152 devil_env.GetPlatform(): {
153 'local_paths': [os.path.abspath(adb_path)]
159 devil_env.config.Initialize(configs=[devil_dynamic_config])
162 def main_impl(arguments):
163 # Parse the command line options.
164 options, categories = parse_options(arguments)
166 # Override --atrace-categories and --ftrace-categories flags if command-line
167 # categories are provided.
168 if categories:
169 if options.target == 'android':
170 options.atrace_categories = categories
171 elif options.target == 'linux':
172 options.ftrace_categories = categories
173 else:
174 raise RuntimeError('Categories are only valid for atrace/ftrace. Target '
175 'platform must be either Android or Linux.')
177 if options.target == 'android' and not options.from_file:
178 initialize_devil()
179 if not options.device_serial_number:
180 devices = [a.GetDeviceSerial() for a in adb_wrapper.AdbWrapper.Devices()]
181 if len(devices) == 0:
182 raise RuntimeError('No ADB devices connected.')
183 elif len(devices) >= 2:
184 raise RuntimeError('Multiple devices connected, serial number required')
185 options.device_serial_number = devices[0]
187 # If list_categories is selected, just print the list of categories.
188 # In this case, use of the tracing controller is not necessary.
189 if options.list_categories:
190 if options.target == 'android':
191 atrace_agent.list_categories(options)
192 elif options.target == 'linux':
193 ftrace_agent.list_categories(options)
194 return
196 # Set up the systrace runner and start tracing.
197 controller = systrace_runner.SystraceRunner(
198 os.path.dirname(os.path.abspath(__file__)), options)
199 controller.StartTracing()
201 # Wait for the given number of seconds or until the user presses enter.
202 # pylint: disable=superfluous-parens
203 # (need the parens so no syntax error if trying to load with Python 3)
204 if options.from_file is not None:
205 print('Reading results from file.')
206 elif options.trace_time:
207 print('Starting tracing (%d seconds)' % options.trace_time)
208 time.sleep(options.trace_time)
209 else:
210 raw_input('Starting tracing (stop with enter)')
212 # Stop tracing and collect the output.
213 print('Tracing completed. Collecting output...')
214 controller.StopTracing()
215 print('Outputting Systrace results...')
216 controller.OutputSystraceResults(write_json=options.write_json)
218 def main():
219 main_impl(sys.argv)
221 if __name__ == '__main__' and __package__ is None:
222 main()