1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-04-20 09:40:50 +01:00

Merge pull request #62 from ep1cman/trace-cmd-target-extract

trace-cmd: Added ability to generate reports on target device
This commit is contained in:
setrofim 2015-12-02 09:58:44 +00:00
commit e5c6ef5368

View File

@ -22,7 +22,7 @@ import subprocess
from collections import defaultdict from collections import defaultdict
from wlauto import Instrument, Parameter, Executable from wlauto import Instrument, Parameter, Executable
from wlauto.exceptions import InstrumentError, ConfigError from wlauto.exceptions import InstrumentError, ConfigError, DeviceError
from wlauto.core import signal from wlauto.core import signal
from wlauto.utils.types import boolean from wlauto.utils.types import boolean
@ -133,12 +133,7 @@ class TraceCmdInstrument(Instrument):
"""), """),
Parameter('report', kind=boolean, default=True, Parameter('report', kind=boolean, default=True,
description=""" description="""
Specifies whether host-side reporting should be performed once the binary trace has been Specifies whether reporting should be performed once the binary trace has been generated.
pulled form the device.
.. note:: This requires the latest version of trace-cmd to be installed on the host (the
one in your distribution's repos may be too old).
"""), """),
Parameter('no_install', kind=boolean, default=False, Parameter('no_install', kind=boolean, default=False,
description=""" description="""
@ -146,6 +141,15 @@ class TraceCmdInstrument(Instrument):
not already a trace-cmd on the device, an error is raised. not already a trace-cmd on the device, an error is raised.
"""), """),
Parameter('report_on_target', kind=boolean, default=False,
description="""
When enabled generation of reports will be done host-side because the generated file is
very large. If trace-cmd is not available on the host device this setting and be disabled
and the report will be generated on the target device.
.. note:: This requires the latest version of trace-cmd to be installed on the host (the
one in your distribution's repos may be too old).
"""),
] ]
def __init__(self, device, **kwargs): def __init__(self, device, **kwargs):
@ -227,45 +231,35 @@ class TraceCmdInstrument(Instrument):
# The size of trace.dat will depend on how long trace-cmd was running. # The size of trace.dat will depend on how long trace-cmd was running.
# Therefore timout for the pull command must also be adjusted # Therefore timout for the pull command must also be adjusted
# accordingly. # accordingly.
pull_timeout = (self.stop_time - self.start_time) self._pull_timeout = (self.stop_time - self.start_time) # pylint: disable=attribute-defined-outside-init
self.device.pull_file(self.output_file, context.output_directory, timeout=pull_timeout) self.device.pull_file(self.output_file, context.output_directory, timeout=self._pull_timeout)
context.add_iteration_artifact('bintrace', OUTPUT_TRACE_FILE, kind='data', context.add_iteration_artifact('bintrace', OUTPUT_TRACE_FILE, kind='data',
description='trace-cmd generated ftrace dump.') description='trace-cmd generated ftrace dump.')
local_trace_file = os.path.join(context.output_directory, OUTPUT_TRACE_FILE)
local_txt_trace_file = os.path.join(context.output_directory, OUTPUT_TEXT_FILE) local_txt_trace_file = os.path.join(context.output_directory, OUTPUT_TEXT_FILE)
if self.report: if self.report:
# To get the output of trace.dat, trace-cmd must be installed # To get the output of trace.dat, trace-cmd must be installed
# This is done host-side because the generated file is very large # By default this is done host-side because the generated file is
if not os.path.isfile(local_trace_file): # very large
self.logger.warning('Not generating trace.txt, as {} does not exist.'.format(OUTPUT_TRACE_FILE)) if self.report_on_target:
try: self._generate_report_on_target(context)
command = 'trace-cmd report {} > {}'.format(local_trace_file, local_txt_trace_file) else:
self.logger.debug(command) self._generate_report_on_host(context)
process = subprocess.Popen(command, stderr=subprocess.PIPE, shell=True)
_, error = process.communicate() if os.path.isfile(local_txt_trace_file):
if process.returncode: context.add_iteration_artifact('txttrace', OUTPUT_TEXT_FILE, kind='export',
raise InstrumentError('trace-cmd returned non-zero exit code {}'.format(process.returncode)) description='trace-cmd generated ftrace dump.')
if error: self.logger.debug('Verifying traces.')
# logged at debug level, as trace-cmd always outputs some with open(local_txt_trace_file) as fh:
# errors that seem benign. for line in fh:
self.logger.debug(error) if 'EVENTS DROPPED' in line:
if os.path.isfile(local_txt_trace_file): self.logger.warning('Dropped events detected.')
context.add_iteration_artifact('txttrace', OUTPUT_TEXT_FILE, kind='export', break
description='trace-cmd generated ftrace dump.') else:
self.logger.debug('Verifying traces.') self.logger.debug('Trace verified.')
with open(local_txt_trace_file) as fh: else:
for line in fh: self.logger.warning('Could not generate trace.txt.')
if 'EVENTS DROPPED' in line:
self.logger.warning('Dropped events detected.')
break
else:
self.logger.debug('Trace verified.')
else:
self.logger.warning('Could not generate trace.txt.')
except OSError:
raise InstrumentError('Could not find trace-cmd. Please make sure it is installed and is in PATH.')
def teardown(self, context): def teardown(self, context):
self.device.delete_file(os.path.join(self.device.working_directory, OUTPUT_TRACE_FILE)) self.device.delete_file(os.path.join(self.device.working_directory, OUTPUT_TRACE_FILE))
@ -315,8 +309,37 @@ class TraceCmdInstrument(Instrument):
self.logger.warning('Failed to set trace buffer size to {}, value set was {}'.format(target_buffer_size, buffer_size)) self.logger.warning('Failed to set trace buffer size to {}, value set was {}'.format(target_buffer_size, buffer_size))
break break
def _generate_report_on_target(self, context):
try:
trace_file = self.output_file
txt_trace_file = os.path.join(self.device.working_directory, OUTPUT_TEXT_FILE)
command = 'trace-cmd report {} > {}'.format(trace_file, txt_trace_file)
self.device.execute(command)
self.device.pull_file(txt_trace_file, context.output_directory, timeout=self._pull_timeout)
except DeviceError:
raise InstrumentError('Could not generate TXT report on target.')
def _generate_report_on_host(self, context):
local_trace_file = os.path.join(context.output_directory, OUTPUT_TRACE_FILE)
local_txt_trace_file = os.path.join(context.output_directory, OUTPUT_TEXT_FILE)
command = 'trace-cmd report {} > {}'.format(local_trace_file, local_txt_trace_file)
self.logger.debug(command)
if not os.path.isfile(local_trace_file):
self.logger.warning('Not generating trace.txt, as {} does not exist.'.format(OUTPUT_TRACE_FILE))
else:
try:
process = subprocess.Popen(command, stderr=subprocess.PIPE, shell=True)
_, error = process.communicate()
if process.returncode:
raise InstrumentError('trace-cmd returned non-zero exit code {}'.format(process.returncode))
if error:
# logged at debug level, as trace-cmd always outputs some
# errors that seem benign.
self.logger.debug(error)
except OSError:
raise InstrumentError('Could not find trace-cmd. Please make sure it is installed and is in PATH.')
def _build_trace_events(events): def _build_trace_events(events):
event_string = ' '.join(['-e {}'.format(e) for e in events]) event_string = ' '.join(['-e {}'.format(e) for e in events])
return event_string return event_string