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