• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2#
3# Copyright 2014 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
7import logging
8import optparse
9import os
10import sys
11import webbrowser
12
13from profile_chrome import chrome_tracing_agent
14from profile_chrome import ddms_tracing_agent
15from profile_chrome import flags
16from profile_chrome import perf_tracing_agent
17from profile_chrome import profiler
18from profile_chrome import ui
19from systrace import util
20from systrace.tracing_agents import atrace_agent
21
22from devil.android import device_utils
23from devil.android.sdk import adb_wrapper
24
25
26_PROFILE_CHROME_AGENT_MODULES = [chrome_tracing_agent, ddms_tracing_agent,
27                                 perf_tracing_agent, atrace_agent]
28
29
30def _CreateOptionParser():
31  parser = optparse.OptionParser(description='Record about://tracing profiles '
32                                 'from Android browsers. See http://dev.'
33                                 'chromium.org/developers/how-tos/trace-event-'
34                                 'profiling-tool for detailed instructions for '
35                                 'profiling.', conflict_handler='resolve')
36
37  parser = util.get_main_options(parser)
38
39  timed_options = optparse.OptionGroup(parser, 'Timed tracing')
40  timed_options.add_option('-t', '--time', help='Profile for N seconds and '
41                          'download the resulting trace.', metavar='N',
42                           type='float', dest='trace_time')
43  parser.add_option_group(timed_options)
44
45  cont_options = optparse.OptionGroup(parser, 'Continuous tracing')
46  cont_options.add_option('--continuous', help='Profile continuously until '
47                          'stopped.', action='store_true')
48  cont_options.add_option('--ring-buffer', help='Use the trace buffer as a '
49                          'ring buffer and save its contents when stopping '
50                          'instead of appending events into one long trace.',
51                          action='store_true')
52  parser.add_option_group(cont_options)
53
54  parser.add_option_group(flags.OutputOptions(parser))
55
56  browsers = sorted(util.get_supported_browsers().keys())
57  parser.add_option('-b', '--browser', help='Select among installed browsers. '
58                    'One of ' + ', '.join(browsers) + ', "stable" is used by '
59                    'default.', type='choice', choices=browsers,
60                    default='stable')
61  parser.add_option('-v', '--verbose', help='Verbose logging.',
62                    action='store_true')
63  parser.add_option('-z', '--compress', help='Compress the resulting trace '
64                    'with gzip. ', action='store_true')
65
66  # Add options from profile_chrome agents.
67  for module in _PROFILE_CHROME_AGENT_MODULES:
68    parser.add_option_group(module.add_options(parser))
69
70  return parser
71
72
73def main():
74  parser = _CreateOptionParser()
75  options, _args = parser.parse_args()  # pylint: disable=unused-variable
76  if options.trace_cc:
77    parser.error("""--trace-cc is deprecated.
78
79For basic jank busting uses, use  --trace-frame-viewer
80For detailed study of ubercompositor, pass --trace-ubercompositor.
81
82When in doubt, just try out --trace-frame-viewer.
83""")
84
85  logging.basicConfig()
86
87  if options.verbose:
88    logging.getLogger().setLevel(logging.DEBUG)
89
90  if not options.device_serial_number:
91    devices = [a.GetDeviceSerial() for a in adb_wrapper.AdbWrapper.Devices()]
92    if len(devices) == 0:
93      raise RuntimeError('No ADB devices connected.')
94    elif len(devices) >= 2:
95      raise RuntimeError('Multiple devices connected, serial number required')
96    options.device_serial_number = devices[0]
97  device = device_utils.DeviceUtils.HealthyDevices(device_arg=
98      options.device_serial_number)[0]
99  package_info = util.get_supported_browsers()[options.browser]
100
101  options.device = device
102  options.package_info = package_info
103
104  # Include Chrome categories by default in profile_chrome.
105  if not options.chrome_categories:
106    options.chrome_categories = chrome_tracing_agent.DEFAULT_CHROME_CATEGORIES
107
108  if options.chrome_categories in ['list', 'help']:
109    ui.PrintMessage('Collecting record categories list...', eol='')
110    record_categories = []
111    disabled_by_default_categories = []
112    record_categories, disabled_by_default_categories = \
113        chrome_tracing_agent.ChromeTracingAgent.GetCategories(
114            device, package_info)
115
116    ui.PrintMessage('done')
117    ui.PrintMessage('Record Categories:')
118    ui.PrintMessage('\n'.join('\t%s' % item \
119        for item in sorted(record_categories)))
120
121    ui.PrintMessage('\nDisabled by Default Categories:')
122    ui.PrintMessage('\n'.join('\t%s' % item \
123        for item in sorted(disabled_by_default_categories)))
124
125    return 0
126
127  if options.atrace_categories in ['list', 'help']:
128    atrace_agent.list_categories(atrace_agent.get_config(options))
129    print '\n'
130    return 0
131
132  if (perf_tracing_agent.PerfProfilerAgent.IsSupported() and
133      options.perf_categories in ['list', 'help']):
134    ui.PrintMessage('\n'.join(
135        perf_tracing_agent.PerfProfilerAgent.GetCategories(device)))
136    return 0
137
138  if not options.trace_time and not options.continuous:
139    ui.PrintMessage('Time interval or continuous tracing should be specified.')
140    return 1
141
142  if (options.chrome_categories and options.atrace_categories and
143      'webview' in options.atrace_categories):
144    logging.warning('Using the "webview" category in atrace together with '
145                    'Chrome tracing results in duplicate trace events.')
146
147  if options.output_file:
148    options.output_file = os.path.expanduser(options.output_file)
149  result = profiler.CaptureProfile(
150      options,
151      options.trace_time if not options.continuous else 0,
152      _PROFILE_CHROME_AGENT_MODULES,
153      output=options.output_file,
154      compress=options.compress,
155      write_json=options.write_json)
156  if options.view:
157    if sys.platform == 'darwin':
158      os.system('/usr/bin/open %s' % os.path.abspath(result))
159    else:
160      webbrowser.open(result)
161