From a697c47c498628d2a265c385fe69429b4bd5a2a5 Mon Sep 17 00:00:00 2001 From: Sebastian Goscik Date: Tue, 1 Dec 2015 11:16:05 +0000 Subject: [PATCH] trace-cmd: Added ability to generate reports on target device --- wlauto/instrumentation/trace_cmd/__init__.py | 103 ++++++++++++------- 1 file changed, 63 insertions(+), 40 deletions(-) diff --git a/wlauto/instrumentation/trace_cmd/__init__.py b/wlauto/instrumentation/trace_cmd/__init__.py index 7fca4579..d417bd00 100644 --- a/wlauto/instrumentation/trace_cmd/__init__.py +++ b/wlauto/instrumentation/trace_cmd/__init__.py @@ -22,7 +22,7 @@ import subprocess from collections import defaultdict 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.utils.types import boolean @@ -133,12 +133,7 @@ class TraceCmdInstrument(Instrument): """), Parameter('report', kind=boolean, default=True, description=""" - Specifies whether host-side reporting should be performed once the binary trace has been - 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). - + Specifies whether reporting should be performed once the binary trace has been generated. """), Parameter('no_install', kind=boolean, default=False, description=""" @@ -146,6 +141,15 @@ class TraceCmdInstrument(Instrument): 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): @@ -227,45 +231,35 @@ class TraceCmdInstrument(Instrument): # The size of trace.dat will depend on how long trace-cmd was running. # Therefore timout for the pull command must also be adjusted # accordingly. - pull_timeout = (self.stop_time - self.start_time) - self.device.pull_file(self.output_file, context.output_directory, timeout=pull_timeout) + 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=self._pull_timeout) context.add_iteration_artifact('bintrace', OUTPUT_TRACE_FILE, kind='data', 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) if self.report: # To get the output of trace.dat, trace-cmd must be installed - # This is done host-side because the generated file is very large - if not os.path.isfile(local_trace_file): - self.logger.warning('Not generating trace.txt, as {} does not exist.'.format(OUTPUT_TRACE_FILE)) - try: - command = 'trace-cmd report {} > {}'.format(local_trace_file, local_txt_trace_file) - self.logger.debug(command) - 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) - if os.path.isfile(local_txt_trace_file): - context.add_iteration_artifact('txttrace', OUTPUT_TEXT_FILE, kind='export', - description='trace-cmd generated ftrace dump.') - self.logger.debug('Verifying traces.') - with open(local_txt_trace_file) as fh: - for line in fh: - 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.') + # By default this is done host-side because the generated file is + # very large + if self.report_on_target: + self._generate_report_on_target(context) + else: + self._generate_report_on_host(context) + + if os.path.isfile(local_txt_trace_file): + context.add_iteration_artifact('txttrace', OUTPUT_TEXT_FILE, kind='export', + description='trace-cmd generated ftrace dump.') + self.logger.debug('Verifying traces.') + with open(local_txt_trace_file) as fh: + for line in fh: + 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.') def teardown(self, context): 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)) 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): event_string = ' '.join(['-e {}'.format(e) for e in events]) return event_string -