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