-
Notifications
You must be signed in to change notification settings - Fork 122
Add support for "perf record" and "perf report" to WA #971
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,3 +1,4 @@ | ||||||
|
|
||||||
| # Copyright 2013-2015 ARM Limited | ||||||
| # | ||||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|
|
@@ -22,6 +23,7 @@ | |||||
|
|
||||||
| from wa import Instrument, Parameter | ||||||
| from wa.utils.types import list_or_string, list_of_strs | ||||||
| from wa.utils.types import numeric | ||||||
|
|
||||||
| PERF_COUNT_REGEX = re.compile(r'^(CPU\d+)?\s*(\d+)\s*(.*?)\s*(\[\s*\d+\.\d+%\s*\])?\s*$') | ||||||
|
|
||||||
|
|
@@ -77,6 +79,19 @@ class PerfInstrument(Instrument): | |||||
| description="""Provides labels for pref output. If specified, the number of | ||||||
| labels must match the number of ``optionstring``\ s. | ||||||
| """), | ||||||
| Parameter('mode', kind=str, default='stat', allowed_values=['stat', 'record'], | ||||||
| global_alias='mode', | ||||||
| description=""" | ||||||
| Choose between 'perf stat' and 'perf record'. If 'perf record' is selected | ||||||
| 'perf report' will also be run. 'report_optionstring' can be used to generate | ||||||
| custom report from the trace. | ||||||
| """), | ||||||
| Parameter('report_optionstring', kind=list_or_string, default='', | ||||||
| global_alias='report_perf_options', | ||||||
| description=""" | ||||||
| Specifies options to be used for the 'perf report' command used | ||||||
| with 'mode=record'. | ||||||
| """), | ||||||
| Parameter('force_install', kind=bool, default=False, | ||||||
| description=""" | ||||||
| always install perf binary even if perf is already present on the device. | ||||||
|
|
@@ -92,6 +107,8 @@ def initialize(self, context): | |||||
| self.events, | ||||||
| self.optionstring, | ||||||
| self.labels, | ||||||
| self.mode, | ||||||
| self.report_optionstring, | ||||||
| self.force_install) | ||||||
|
|
||||||
| def setup(self, context): | ||||||
|
|
@@ -104,12 +121,21 @@ def stop(self, context): | |||||
| self.collector.stop() | ||||||
|
|
||||||
| def update_output(self, context): | ||||||
| self.logger.info('Extracting reports from target...') | ||||||
| outdir = os.path.join(context.output_directory, 'perf') | ||||||
| self.collector.get_trace(outdir) | ||||||
|
|
||||||
| # Extract data for 'perf stat' | ||||||
| if self.mode == 'stat': | ||||||
| self._update_output_stat(context, outdir) | ||||||
| # Extract data for 'perf record' | ||||||
| elif self.mode == 'record': | ||||||
| self._update_output_record(context, outdir) | ||||||
|
|
||||||
| def _update_output_stat(self, context, outdir): | ||||||
| self.logger.info('Processing perf stat reports.') | ||||||
|
|
||||||
| for host_file in os.listdir(outdir): | ||||||
| label = host_file.split('.out')[0] | ||||||
| label = os.path.splitext(host_file)[0] | ||||||
| host_file_path = os.path.join(outdir, host_file) | ||||||
| context.add_artifact(label, host_file_path, 'raw') | ||||||
| with open(host_file_path) as fh: | ||||||
|
|
@@ -134,5 +160,27 @@ def update_output(self, context): | |||||
| metric = '{}_{}'.format(label, match.group(3)) | ||||||
| context.add_metric(metric, count, classifiers=classifiers) | ||||||
|
|
||||||
| def _update_output_record(self, context, outdir): | ||||||
| self.logger.info('Processing "perf report" reports.') | ||||||
|
|
||||||
| for host_file in os.listdir(outdir): | ||||||
| label, ext = os.path.splitext(host_file) | ||||||
| host_file_path = os.path.join(outdir, host_file) | ||||||
| context.add_artifact(label, host_file_path, 'raw') | ||||||
| if ext == '.rpt': | ||||||
| with open(host_file_path) as fh: | ||||||
| for line in fh: | ||||||
| words = line.split() | ||||||
| if len(words) >= 1: | ||||||
| if words[0] == '#' and len(words) == 6: | ||||||
| if words[4] == 'event': | ||||||
| event_type = words[5] | ||||||
| event_type = event_type.strip("'") | ||||||
| if words[0] != '#' and '%' in words[0] and len(words) == 5: | ||||||
| metric = 'perf/{}/{}/{}'.format(event_type, words[1], words[2].strip("[]")) | ||||||
| count = numeric(words[0].strip('%')) | ||||||
| context.add_metric(metric, count, '%', | ||||||
| classifiers={'Perf Event': event_type, 'Command': words[1], 'Shared Object' : words[2]}) | ||||||
|
|
||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
You could use a dictionary of functions (method-local dictionary of instance methods, class-attribute dictionary of class methods, ... your call), accessed with (I know that |
||||||
| def teardown(self, context): | ||||||
| self.collector.reset() | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is currently attempting to process every file in the perf directory, since we are now pulling the raw trace data to this directory this fails trying to parse binary data. Should this be updated to only process
.rptfiles?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, changed in latest version.