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.
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.
19 version
= sys
.version_info
[:2]
21 sys
.stderr
.write('This script does not support Python %d.%d. '
22 'Please use Python 2.7.\n' % version
)
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']
59 def parse_options(argv
):
60 """Parses and checks the command-line options.
63 A tuple containing the options structure and a list of categories to
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,
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 '
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 '
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
119 for module
in ALL_MODULES
:
120 option_group
= module
.add_options(parser
)
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')
145 print >> sys
.stderr
, "Unable to find adb, is it in your path?"
147 devil_dynamic_config
= {
148 'config_type': 'BaseConfig',
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.
169 if options
.target
== 'android':
170 options
.atrace_categories
= categories
171 elif options
.target
== 'linux':
172 options
.ftrace_categories
= categories
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
:
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
)
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
)
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
)
221 if __name__
== '__main__' and __package__
is None: