Home | History | Annotate | Download | only in profile_chrome
      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 
      7 import logging
      8 import optparse
      9 import os
     10 import sys
     11 import webbrowser
     12 
     13 from profile_chrome import chrome_tracing_agent
     14 from profile_chrome import ddms_tracing_agent
     15 from profile_chrome import flags
     16 from profile_chrome import perf_tracing_agent
     17 from profile_chrome import profiler
     18 from profile_chrome import ui
     19 from systrace import util
     20 from systrace.tracing_agents import atrace_agent
     21 
     22 from devil.android import device_utils
     23 from 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 
     30 def _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 
     73 def 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 
     79 For basic jank busting uses, use  --trace-frame-viewer
     80 For detailed study of ubercompositor, pass --trace-ubercompositor.
     81 
     82 When 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