| Index: systrace/systrace/systrace_tracing_controller.py
|
| diff --git a/systrace/systrace/systrace_tracing_controller.py b/systrace/systrace/systrace_tracing_controller.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..15ca56e4688523696d41925d52b9e952e1c9e987
|
| --- /dev/null
|
| +++ b/systrace/systrace/systrace_tracing_controller.py
|
| @@ -0,0 +1,195 @@
|
| +#!/usr/bin/env python
|
| +
|
| +# 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.
|
| +
|
| +'''Implementation of tracing controller for systrace. This class creates the
|
| +necessary tracing agents for systrace, runs them, and outputs the results
|
| +as an HTML file.'''
|
| +
|
| +import imp
|
| +import json
|
| +import os
|
| +
|
| +from systrace import tracing_controller
|
| +
|
| +# The default agent directory.
|
| +DEFAULT_AGENT_DIR = 'tracing_agents'
|
| +
|
| +# TODO(alexandermont): Current version of trace viewer does not support
|
| +# the controller tracing agent output. Thus we use this variable to
|
| +# suppress this tracing agent's output. This should be removed once
|
| +# trace viewer is working again.
|
| +OUTPUT_CONTROLLER_TRACE_ = False
|
| +
|
| +
|
| +class SystraceTracingController(tracing_controller.TracingController):
|
| + def __init__(self, script_dir, options, categories):
|
| + """Set up the SystraceTracingController.
|
| +
|
| + Args:
|
| + script_dir: Directory containing the trace viewer script
|
| + (systrace_trace_viewer.html)
|
| + options: List of command line options.
|
| + categories: List of trace categories to capture.
|
| + """
|
| + # Parse command line arguments and create agents
|
| + self._script_dir = script_dir
|
| + self._out_filename = options.output_file
|
| + agents = CreateAgents(options, categories)
|
| +
|
| + # Error if no agents are available
|
| + if not agents:
|
| + dirs = DEFAULT_AGENT_DIR
|
| + if options.agent_dirs:
|
| + dirs += ',' + options.agent_dirs
|
| + raise RuntimeError('No systrace agent is available'
|
| + 'in directories |%s|.\n' % dirs)
|
| +
|
| + # Update trace viewer if necessary
|
| + try:
|
| + from systrace import update_systrace_trace_viewer
|
| + except ImportError:
|
| + pass
|
| + else:
|
| + update_systrace_trace_viewer.update(dest=script_dir)
|
| +
|
| + super(SystraceTracingController, self).__init__(options,
|
| + categories,
|
| + agents)
|
| +
|
| + def SupportsExplicitClockSync(self):
|
| + return False
|
| +
|
| + def RecordClockSyncMarker(self, sync_id, callback):
|
| + raise NotImplementedError
|
| +
|
| + def OutputSystraceResults(self, write_json=False):
|
| + """Output the results of systrace to a file.
|
| +
|
| + If output is necessary, then write the results of systrace to either (a)
|
| + a standalone HTML file, or (b) a json file which can be read by the
|
| + trace viewer.
|
| +
|
| + Args:
|
| + write_json: Whether to output to a json file (if false, use HTML file)
|
| + """
|
| + print 'Tracing complete, writing results'
|
| + if write_json:
|
| + self._WriteTraceJSON(self._all_results)
|
| + else:
|
| + self._WriteTraceHTML(self._all_results)
|
| +
|
| + def _WriteTraceJSON(self, results):
|
| + """Write the results of systrace as a JSON file.
|
| +
|
| + Args:
|
| + results: Results to write.
|
| + """
|
| + print 'Writing trace JSON'
|
| + results['controllerTraceDataKey'] = 'traceEvents'
|
| + if not OUTPUT_CONTROLLER_TRACE_:
|
| + results['traceEvents'] = []
|
| + with open(self._out_filename, 'w') as json_file:
|
| + json.dump(results, json_file)
|
| + print '\n wrote file://%s\n' % os.path.abspath(self._out_filename)
|
| +
|
| + def _WriteTraceHTML(self, results):
|
| + """Write the results of systrace to an HTML file.
|
| +
|
| + Args:
|
| + results: Results to write.
|
| + """
|
| + def _read_asset(src_dir, filename):
|
| + return open(os.path.join(src_dir, filename)).read()
|
| +
|
| + # Get the trace viewer code and the prefix and suffix for the HTML.
|
| + print 'Writing trace HTML'
|
| + 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(self._script_dir,
|
| + 'systrace_trace_viewer.html')
|
| +
|
| + # Open the file in binary mode to prevent python from changing the
|
| + # line endings, then write the prefix.
|
| + html_file = open(self._out_filename, 'wb')
|
| + html_file.write(html_prefix.replace('{{SYSTRACE_TRACE_VIEWER_HTML}}',
|
| + trace_viewer_html))
|
| +
|
| + # Write the trace data itself. There is a separate section of the form
|
| + # <script class="trace-data" type="application/text"> ... </script>
|
| + # for each tracing agent (including the controller tracing agent).
|
| + html_file.write('<!-- BEGIN TRACE -->\n')
|
| + for (name, data) in results.iteritems():
|
| + if name == 'traceEvents' and not OUTPUT_CONTROLLER_TRACE_:
|
| + continue
|
| + html_file.write(' <script class="')
|
| + html_file.write('trace-data')
|
| + html_file.write('" type="application/text">\n')
|
| + html_file.write(convert(data))
|
| + html_file.write(' </script>\n')
|
| + html_file.write('<!-- END TRACE -->\n')
|
| +
|
| + # Write the suffix and finish.
|
| + html_file.write(html_suffix)
|
| + html_file.close()
|
| + print '\n wrote file://%s\n' % os.path.abspath(self._out_filename)
|
| +
|
| +def convert(data):
|
| + """Convert a data element to the format to be output into HTML.
|
| +
|
| + If the data element is a dictionary or list, JSON-encode it.
|
| + If the data element is a string, leave it unchanged.
|
| +
|
| + Args:
|
| + data: Data to convert.
|
| +
|
| + Returns:
|
| + String to be output into the HTML file.
|
| + """
|
| + if isinstance(data, dict) or isinstance(data, list):
|
| + return json.dumps(data)
|
| + elif isinstance(data, str):
|
| + return data
|
| + else:
|
| + raise ValueError('Invalid data format for HTML output')
|
| +
|
| +def CreateAgents(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
|
|
|