| Index: systrace/systrace/run_systrace.py
|
| diff --git a/systrace/systrace/systrace.py b/systrace/systrace/run_systrace.py
|
| similarity index 54%
|
| rename from systrace/systrace/systrace.py
|
| rename to systrace/systrace/run_systrace.py
|
| index 738164b69be6ad792a458a3daacea85fda29decb..62e1ed0b43a3a6116b34bb7838df72953d1546a1 100755
|
| --- a/systrace/systrace/systrace.py
|
| +++ b/systrace/systrace/run_systrace.py
|
| @@ -1,6 +1,6 @@
|
| #!/usr/bin/env python
|
|
|
| -# Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| +# Copyright (c) 2016 The Chromium Authors. All rights reserved.
|
| # Use of this source code is governed by a BSD-style license that can be
|
| # found in the LICENSE file.
|
|
|
| @@ -10,7 +10,25 @@ This is a tool for capturing a trace that includes data from both userland and
|
| the kernel. It creates an HTML file for visualizing the trace.
|
| """
|
|
|
| +import optparse
|
| +import os
|
| import sys
|
| +import time
|
| +
|
| +_SYSTRACE_DIR = os.path.abspath(
|
| + os.path.join(os.path.dirname(__file__), os.path.pardir))
|
| +_CATAPULT_DIR = os.path.join(
|
| + os.path.dirname(os.path.abspath(__file__)), os.path.pardir, os.path.pardir)
|
| +_DEVIL_DIR = os.path.join(_CATAPULT_DIR, 'devil')
|
| +if _DEVIL_DIR not in sys.path:
|
| + sys.path.insert(0, _DEVIL_DIR)
|
| +if _SYSTRACE_DIR not in sys.path:
|
| + sys.path.insert(0, _SYSTRACE_DIR)
|
| +
|
| +from devil.utils import cmd_helper
|
| +from systrace import systrace_tracing_controller
|
| +from systrace.tracing_agents import atrace_agent
|
| +from systrace.tracing_agents import ftrace_agent
|
|
|
| # Make sure we're using a new enough version of Python.
|
| # The flags= parameter of re.sub() is new in Python 2.7. And Systrace does not
|
| @@ -21,14 +39,6 @@ if version != (2, 7):
|
| 'Please use Python 2.7.\n' % version)
|
| sys.exit(1)
|
|
|
| -import imp
|
| -import optparse
|
| -import os
|
| -
|
| -
|
| -# The default agent directory.
|
| -DEFAULT_AGENT_DIR = 'agents'
|
| -
|
|
|
| def parse_options(argv):
|
| """Parses and checks the command-line options.
|
| @@ -40,9 +50,9 @@ def parse_options(argv):
|
| usage = 'Usage: %prog [options] [category1 [category2 ...]]'
|
| desc = 'Example: %prog -b 32768 -t 15 gfx input view sched freq'
|
| parser = optparse.OptionParser(usage=usage, description=desc)
|
| - parser.add_option('-o', dest='output_file', help='write HTML to FILE',
|
| - default='trace.html', metavar='FILE')
|
| - parser.add_option('-t', '--time', dest='trace_time', type='int',
|
| + parser.add_option('-o', dest='output_file', help='write HTML/JSON to FILE',
|
| + default=None, metavar='FILE')
|
| + parser.add_option('-t', '--time', dest='trace_time', default=0, type='int',
|
| help='trace for N seconds', metavar='N')
|
| parser.add_option('-b', '--buf-size', dest='trace_buf_size', type='int',
|
| help='use a trace buffer size of N KB', metavar='N')
|
| @@ -50,8 +60,10 @@ def parse_options(argv):
|
| help='specify a comma-separated list of kernel functions '
|
| 'to trace')
|
| parser.add_option('-l', '--list-categories', dest='list_categories',
|
| + default=False, action='store_true')
|
| + parser.add_option('-j', '--json', dest='write_json',
|
| default=False, action='store_true',
|
| - help='list the available categories and exit')
|
| + help='write a JSON file')
|
| parser.add_option('-a', '--app', dest='app_name', default=None, type='string',
|
| action='store',
|
| help='enable application-level tracing for comma-separated '
|
| @@ -89,136 +101,82 @@ def parse_options(argv):
|
| ' The directories should be comma separated, e.g., '
|
| '--agent-dirs=dir1,dir2,dir3. Directory |%s| is the default'
|
| ' agent directory and will always be checked.'
|
| - % DEFAULT_AGENT_DIR)
|
| + % systrace_tracing_controller.DEFAULT_AGENT_DIR)
|
| parser.add_option('--target', dest='target', default='android', type='string',
|
| help='chose tracing target (android or linux)')
|
| + parser.add_option('--timeout', dest='timeout', type='int',
|
| + help='timeout for start and stop tracing (seconds)')
|
| + parser.add_option('--collection-timeout', dest='collection_timeout',
|
| + type='int', help='timeout for data collection (seconds)')
|
|
|
| options, categories = parser.parse_args(argv[1:])
|
|
|
| + if options.output_file is None:
|
| + options.output_file = 'trace.json' if options.write_json else 'trace.html'
|
| +
|
| if options.link_assets or options.asset_dir != 'trace-viewer':
|
| parser.error('--link-assets and --asset-dir are deprecated.')
|
|
|
| - if (options.trace_time is not None) and (options.trace_time <= 0):
|
| - parser.error('the trace time must be a positive number')
|
| + if options.trace_time < 0:
|
| + parser.error('the trace time must be a non-negative number')
|
|
|
| if (options.trace_buf_size is not None) and (options.trace_buf_size <= 0):
|
| parser.error('the trace buffer size must be a positive number')
|
|
|
| return (options, categories)
|
|
|
| +def get_device_serials():
|
| + """Get the serial numbers of devices connected via adb.
|
|
|
| -def write_trace_html(html_filename, script_dir, agents):
|
| - """Writes out a trace html file.
|
| -
|
| - Args:
|
| - html_filename: The name of the file to write.
|
| - script_dir: The directory containing this script.
|
| - agents: The systrace agents.
|
| + Only gets serial numbers of "active" devices (e.g. does not get serial
|
| + numbers of devices which have not been authorized.)
|
| """
|
| - systrace_dir = os.path.abspath(os.path.dirname(__file__))
|
| - html_prefix = read_asset(systrace_dir, 'prefix.html')
|
| - html_suffix = read_asset(systrace_dir, 'suffix.html')
|
| - trace_viewer_html = read_asset(script_dir, 'systrace_trace_viewer.html')
|
| -
|
| - # Open the file in binary mode to prevent python from changing the
|
| - # line endings.
|
| - html_file = open(html_filename, 'wb')
|
| - html_file.write(html_prefix.replace('{{SYSTRACE_TRACE_VIEWER_HTML}}',
|
| - trace_viewer_html))
|
| -
|
| - html_file.write('<!-- BEGIN TRACE -->\n')
|
| - for a in agents:
|
| - html_file.write(' <script class="')
|
| - html_file.write(a.get_class_name())
|
| - html_file.write('" type="application/text">\n')
|
| - html_file.write(a.get_trace_data())
|
| - html_file.write(' </script>\n')
|
| - html_file.write('<!-- END TRACE -->\n')
|
| -
|
| - html_file.write(html_suffix)
|
| - html_file.close()
|
| - print '\n wrote file://%s\n' % os.path.abspath(html_filename)
|
| -
|
| -
|
| -def create_agents(options, categories):
|
| - """Create systrace agents.
|
| -
|
| - This function will search systrace agent modules in agent directories and
|
| - create the corresponding systrace agents.
|
| - Args:
|
| - options: The command-line options.
|
| - categories: The trace categories to capture.
|
| - Returns:
|
| - The list of systrace agents.
|
| - """
|
| - agent_dirs = [os.path.join(os.path.dirname(__file__), DEFAULT_AGENT_DIR)]
|
| - if options.agent_dirs:
|
| - agent_dirs.extend(options.agent_dirs.split(','))
|
| -
|
| - agents = []
|
| - for agent_dir in agent_dirs:
|
| - if not agent_dir:
|
| - continue
|
| - for filename in os.listdir(agent_dir):
|
| - (module_name, ext) = os.path.splitext(filename)
|
| - if (ext != '.py' or module_name == '__init__'
|
| - or module_name.endswith('_unittest')):
|
| - continue
|
| - (f, pathname, data) = imp.find_module(module_name, [agent_dir])
|
| - try:
|
| - module = imp.load_module(module_name, f, pathname, data)
|
| - finally:
|
| - if f:
|
| - f.close()
|
| - if module:
|
| - agent = module.try_create_agent(options, categories)
|
| - if not agent:
|
| - continue
|
| - agents.append(agent)
|
| - return agents
|
| -
|
| + cmdout = cmd_helper.GetCmdOutput(['adb', 'devices'])
|
| + lines = [x.split() for x in cmdout.splitlines()[1:-1]]
|
| + return [x[0] for x in lines if x[1] == 'device']
|
|
|
| def main():
|
| + # Parse the command line options.
|
| options, categories = parse_options(sys.argv)
|
| - agents = create_agents(options, categories)
|
| -
|
| - if not agents:
|
| - dirs = DEFAULT_AGENT_DIR
|
| - if options.agent_dirs:
|
| - dirs += ',' + options.agent_dirs
|
| - sys.stderr.write('No systrace agent is available in directories |%s|.\n' %
|
| - dirs)
|
| - sys.exit(1)
|
| -
|
| - try:
|
| - from . import update_systrace_trace_viewer
|
| - except ImportError:
|
| - pass
|
| - else:
|
| - update_systrace_trace_viewer.update()
|
| -
|
| - for a in agents:
|
| - a.start()
|
| -
|
| - for a in agents:
|
| - a.collect_result()
|
| - if not a.expect_trace():
|
| - # Nothing more to do.
|
| - return
|
|
|
| - script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
|
| - write_trace_html(options.output_file, script_dir, agents)
|
| -
|
| -
|
| -def read_asset(src_dir, filename):
|
| - return open(os.path.join(src_dir, filename)).read()
|
| + # Get the serial number of the connected ADB device if necessary.
|
| + if options.target == 'android' and not options.device_serial:
|
| + devices = get_device_serials()
|
| + if len(devices) == 0:
|
| + raise RuntimeError('No ADB devices connected.')
|
| + elif len(devices) >= 2:
|
| + raise RuntimeError('Multiple devices connected, serial number required')
|
| + options.device_serial = devices[0]
|
| +
|
| + # If list_categories is selected, just print the list of categories.
|
| + # In this case, use of the tracing controller is not necessary.
|
| + if options.list_categories:
|
| + if options.target == 'android':
|
| + atrace_agent.list_categories(options)
|
| + elif options.target == 'linux':
|
| + ftrace_agent.list_categories(options)
|
| + return
|
| +
|
| + # Set up the tracing controller and start tracing.
|
| + script_dir = os.path.dirname(os.path.abspath(__file__))
|
| + controller = systrace_tracing_controller.SystraceTracingController(
|
| + script_dir, options, categories)
|
| + controller.StartTracing()
|
| +
|
| + # Wait for the given number of seconds or until the user presses enter.
|
| + if options.from_file is not None:
|
| + print 'Reading results from file.'
|
| + elif options.trace_time == 0:
|
| + raw_input('Starting tracing (stop with enter)')
|
| + else:
|
| + print 'Starting tracing (%d seconds)' % options.trace_time
|
| + time.sleep(options.trace_time)
|
|
|
| + # Stop tracing and collect the output.
|
| + print 'Tracing completed. Collecting output...'
|
| + controller.StopTracing()
|
| + print 'Outputting Systrace results...'
|
| + controller.OutputSystraceResults(write_json=options.write_json)
|
|
|
| if __name__ == '__main__' and __package__ is None:
|
| - # Add current package to search path.
|
| - _SYSTRACE_DIR = os.path.abspath(
|
| - os.path.join(os.path.dirname(__file__), os.path.pardir))
|
| - sys.path.insert(0, _SYSTRACE_DIR)
|
| - __package__ = "systrace" # pylint: disable=redefined-builtin
|
| -
|
| main()
|
|
|