1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-02-21 12:28:44 +00:00

cpustate: now generates a timeline csv as well as stats

This commit is contained in:
Sergei Trofimov 2015-06-16 11:04:25 +01:00
parent 4d3feeba64
commit a85e45c6b0
2 changed files with 70 additions and 12 deletions

View File

@ -95,6 +95,11 @@ class CpuStatesProcessor(ResultProcessor):
By default proportional values will be reported as percentages, if this By default proportional values will be reported as percentages, if this
flag is enabled, they will be reported as ratios instead. flag is enabled, they will be reported as ratios instead.
"""), """),
Parameter('create_timeline', kind=bool, default=True,
description="""
Create a CSV with the timeline of core power states over the course of the run
as well as the usual stats reports.
"""),
] ]
@ -128,7 +133,11 @@ class CpuStatesProcessor(ResultProcessor):
self.logger.debug('Text trace does not appear to have been generated; skipping this iteration.') self.logger.debug('Text trace does not appear to have been generated; skipping this iteration.')
return return
self.logger.debug('Generating power state reports from trace...') self.logger.debug('Generating power state reports from trace...')
parallel_report, powerstate_report = report_power_stats( if self.create_timeline:
timeline_csv_file = os.path.join(context.output_directory, 'power_states.csv')
else:
timeline_csv_file = None
parallel_report, powerstate_report = report_power_stats( # pylint: disable=unbalanced-tuple-unpacking
trace_file=trace.path, trace_file=trace.path,
idle_state_names=self.idle_state_names, idle_state_names=self.idle_state_names,
core_names=self.core_names, core_names=self.core_names,
@ -137,6 +146,7 @@ class CpuStatesProcessor(ResultProcessor):
first_cluster_state=self.first_cluster_state, first_cluster_state=self.first_cluster_state,
first_system_state=self.first_system_state, first_system_state=self.first_system_state,
use_ratios=self.use_ratios, use_ratios=self.use_ratios,
timeline_csv_file=timeline_csv_file,
) )
if parallel_report is None: if parallel_report is None:
self.logger.warning('No power state reports generated; are power ' self.logger.warning('No power state reports generated; are power '

View File

@ -285,6 +285,40 @@ def gather_core_states(system_state_stream, freq_dependent_idle_states=None): #
yield (system_state.timestamp, core_states) yield (system_state.timestamp, core_states)
class PowerStateTimeline(object):
def __init__(self, filepath, core_names, idle_state_names):
self.filepath = filepath
self.idle_state_names = idle_state_names
self._wfh = open(filepath, 'w')
self.writer = csv.writer(self._wfh)
if core_names:
headers = ['ts'] + ['{} CPU{}'.format(c, i)
for i, c in enumerate(core_names)]
self.writer.writerow(headers)
def update(self, timestamp, core_states): # NOQA
row = [timestamp]
for idle_state, frequency in core_states:
if frequency is None:
if idle_state is None or idle_state == -1:
row.append(None)
else:
row.append(self.idle_state_names[idle_state])
else: # frequency is not None
if idle_state == -1:
row.append(frequency)
elif idle_state is None:
row.append(None)
else:
row.append('{} ({})'.format(self.idle_state_names[idle_state],
frequency))
self.writer.writerow(row)
def report(self):
self._wfh.close()
class ParallelStats(object): class ParallelStats(object):
def __init__(self, core_clusters, use_ratios=False): def __init__(self, core_clusters, use_ratios=False):
@ -498,15 +532,21 @@ def build_idle_domains(core_clusters, # NOQA
def report_power_stats(trace_file, idle_state_names, core_names, core_clusters, def report_power_stats(trace_file, idle_state_names, core_names, core_clusters,
num_idle_states, first_cluster_state=sys.maxint, num_idle_states, first_cluster_state=sys.maxint,
first_system_state=sys.maxint, use_ratios=False): first_system_state=sys.maxint, use_ratios=False,
timeline_csv_file=None):
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
trace = TraceCmdTrace() trace = TraceCmdTrace()
ps_processor = PowerStateProcessor(core_clusters, ps_processor = PowerStateProcessor(core_clusters,
num_idle_states=num_idle_states, num_idle_states=num_idle_states,
first_cluster_state=first_cluster_state, first_cluster_state=first_cluster_state,
first_system_state=first_system_state) first_system_state=first_system_state)
parallel_stats = ParallelStats(core_clusters, use_ratios) reporters = [
power_state_stats = PowerStateStats(core_names, idle_state_names, use_ratios) ParallelStats(core_clusters, use_ratios),
PowerStateStats(core_names, idle_state_names, use_ratios)
]
if timeline_csv_file:
reporters.append(PowerStateTimeline(timeline_csv_file,
core_names, idle_state_names))
event_stream = trace.parse(trace_file, names=['cpu_idle', 'cpu_frequency']) event_stream = trace.parse(trace_file, names=['cpu_idle', 'cpu_frequency'])
transition_stream = stream_cpu_power_transitions(event_stream) transition_stream = stream_cpu_power_transitions(event_stream)
@ -514,18 +554,20 @@ def report_power_stats(trace_file, idle_state_names, core_names, core_clusters,
core_state_stream = gather_core_states(power_state_stream) core_state_stream = gather_core_states(power_state_stream)
for timestamp, states in core_state_stream: for timestamp, states in core_state_stream:
parallel_stats.update(timestamp, states) for reporter in reporters:
power_state_stats.update(timestamp, states) reporter.update(timestamp, states)
parallel_report = parallel_stats.report() reports = []
ps_report = power_state_stats.report() for reporter in reporters:
report = reporter.report()
return (parallel_report, ps_report) if report:
reports.append(report)
return reports
def main(): def main():
# pylint: disable=unbalanced-tuple-unpacking
args = parse_arguments() args = parse_arguments()
parallel_report, powerstate_report = report_power_stats( parallel_report, powerstate_report = report_power_stats(
trace_file=args.infile, trace_file=args.infile,
idle_state_names=args.idle_state_names, idle_state_names=args.idle_state_names,
@ -535,6 +577,7 @@ def main():
first_cluster_state=args.first_cluster_state, first_cluster_state=args.first_cluster_state,
first_system_state=args.first_system_state, first_system_state=args.first_system_state,
use_ratios=args.ratios, use_ratios=args.ratios,
timeline_csv_file=args.timeline_file,
) )
parallel_report.write(os.path.join(args.output_directory, 'parallel.csv')) parallel_report.write(os.path.join(args.output_directory, 'parallel.csv'))
powerstate_report.write(os.path.join(args.output_directory, 'cpustate.csv')) powerstate_report.write(os.path.join(args.output_directory, 'cpustate.csv'))
@ -576,7 +619,7 @@ def parse_arguments(): # NOQA
core names on the assumption that all cores with the same name are on the core names on the assumption that all cores with the same name are on the
same cluster. same cluster.
''') ''')
parser.add_argument('-i', '--idle-state-names', type=SplitListAction, parser.add_argument('-i', '--idle-state-names', action=SplitListAction,
help=''' help='''
Comma-separated list of idle state names. The number of names must match Comma-separated list of idle state names. The number of names must match
--num-idle-states if that was explicitly specified. --num-idle-states if that was explicitly specified.
@ -599,6 +642,11 @@ def parse_arguments(): # NOQA
By default proportional values will be reported as percentages, if this By default proportional values will be reported as percentages, if this
flag is enabled, they will be reported as ratios instead. flag is enabled, they will be reported as ratios instead.
''') ''')
parser.add_argument('-t', '--timeline-file', metavar='FILE',
help='''
A timeline of core power states will be written to the specified file in
CSV format.
''')
args = parser.parse_args() args = parser.parse_args()