1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2024-10-06 19:01:15 +01:00
workload-automation/wlauto/instrumentation/systrace/__init__.py
Sebastian Goscik b3a9512f44 Added systrace instrument
Added an instrument to uses systrace.py from the android SDK.
 Generates a fancy HTML report (only works in Google chrome).
2015-11-27 09:53:59 +00:00

155 lines
7.2 KiB
Python

# Copyright 2013-2015 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# pylint: disable=W0613,attribute-defined-outside-init
import os
import subprocess
import shutil
from wlauto import Instrument, Parameter
from wlauto.utils.types import list_of_strings, boolean
from wlauto.utils.misc import check_output
from wlauto.exceptions import ConfigError, InstrumentError
class systrace(Instrument):
name = 'systrace'
description = """
This instrument uses systrace.py from the android SDK to dump atrace
output.
Note: This is unlikely to work on devices that have an android build built
before 15-May-2015. Before this date there was a bug with running
atrace asynchronously.
From developer.android.com:
The Systrace tool helps analyze the performance of your application by
capturing and displaying execution times of your applications processes
and other Android system processes. The tool combines data from the
Android kernel such as the CPU scheduler, disk activity, and application
threads to generate an HTML report that shows an overall picture of an
Android device's system processes for a given period of time.
"""
parameters = [
Parameter('buffer_size', kind=int, default=1024,
description="""
Use a trace buffer size of N kilobytes. This option lets you
limit the total size of the data collected during a trace.
"""),
Parameter('use_circular_buffer', kind=boolean, default=False,
description="""
When true trace data will be put into a circular buffer such
that when it overflows it will start overwriting the beginning
of the buffer.
"""),
Parameter('kernel_functions', kind=list_of_strings,
description="""
Specify the names of kernel functions to trace.
"""),
Parameter('categories', kind=list_of_strings,
default=["freq", "sched"],
description="""
A list of the categories you wish to trace.
"""),
Parameter('app_names', kind=list_of_strings,
description="""
Enable tracing for applications, specified as a
comma-separated list of package names. The apps must contain
tracing instrumentation calls from the Trace class. For more
information, see
http://developer.android.com/tools/debugging/systrace.html#app-trace
"""),
Parameter("ignore_signals", kind=boolean, default=False,
description="""
This will cause atrace to ignore ``SIGHUP``, ``SIGINT``,
``SIGQUIT`` and ``SIGTERM``.
"""),
Parameter("compress_trace", kind=boolean, default=True,
description="""
Compresses atrace output. This *greatly* decreases the time
it takes to pull results from a device but the resulting txt
file is not human readable.
""")
]
def initialize(self, context):
cmd_options = {}
if context.device.get_sdk_version() >= 23:
# Set up command line options
if self.app_names:
cmd_options["-a"] = ",".join(self.app_names)
if self.buffer_size:
cmd_options["-b"] = self.buffer_size
if self.use_circular_buffer:
cmd_options["-c"] = None
if self.kernel_functions:
cmd_options["-k"] = ",".join(self.kernel_functions)
if self.ignore_signals:
cmd_options["-n"] = None
# Generate commands
opt_string = ''.join(['{} {} '.format(name, value or "")
for name, value in cmd_options.iteritems()])
self.start_cmd = "atrace --async_start {} {}".format(opt_string,
" ".join(self.categories))
self.output_file = os.path.join(self.device.working_directory, "atrace.txt")
self.stop_cmd = "atrace --async_stop {} > {}".format("-z" if self.compress_trace else "",
self.output_file)
# Check if provided categories are available on the device
available_categories = [cat.strip().split(" - ")[0] for cat in
context.device.execute("atrace --list_categories").splitlines()]
for category in self.categories:
if category not in available_categories:
raise ConfigError("Unknown category '{}'; Must be one of: {}"
.format(category, available_categories))
else:
raise InstrumentError("Only android devices with an API level >= 23 can use systrace properly")
def setup(self, context):
self.device.execute("atrace --async_dump")
def start(self, context):
result = self.device.execute(self.start_cmd)
if "error" in result:
raise InstrumentError(result)
def stop(self, context):
self.p = self.device.execute(self.stop_cmd, background=True)
def update_result(self, context): # pylint: disable=r0201
self.logger.debug("Waiting for atrace to finish dumping data")
self.p.wait()
context.device.pull_file(self.output_file, context.output_directory)
cmd = "python {} --from-file={} -o {}"
cmd = cmd.format(os.path.join(os.environ['ANDROID_HOME'],
"platform-tools/systrace/systrace.py"),
os.path.join(context.output_directory, "atrace.txt"),
os.path.join(context.output_directory, "systrace.html"))
self.logger.debug(cmd)
_, error = check_output(cmd.split(" "), timeout=10)
if error:
raise InstrumentError(error)
context.add_iteration_artifact('atrace.txt',
path=os.path.join(context.output_directory,
"atace.txt"),
kind='data',
description='atrace dump.')
context.add_iteration_artifact('systrace.html',
path=os.path.join(context.output_directory,
"systrace.html"),
kind='data',
description='Systrace HTML report.')