mirror of
https://github.com/ARM-software/workload-automation.git
synced 2025-02-21 20:38:57 +00:00
Merge pull request #96 from setrofim/master
Fixes to cpufreq module and elimination of unknown state in cpustate result processor.
This commit is contained in:
commit
85edc3084b
@ -237,6 +237,8 @@ class CpufreqModule(Module):
|
|||||||
:raises: DeviceError if for some reason the frequency could not be read.
|
:raises: DeviceError if for some reason the frequency could not be read.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
if isinstance(cpu, int):
|
||||||
|
cpu = 'cpu{}'.format(cpu)
|
||||||
sysfile = '/sys/devices/system/cpu/{}/cpufreq/scaling_cur_freq'.format(cpu)
|
sysfile = '/sys/devices/system/cpu/{}/cpufreq/scaling_cur_freq'.format(cpu)
|
||||||
return self.device.get_sysfile_value(sysfile)
|
return self.device.get_sysfile_value(sysfile)
|
||||||
|
|
||||||
@ -393,7 +395,7 @@ class CpufreqModule(Module):
|
|||||||
|
|
||||||
def get_cluster_cur_frequency(self, cluster):
|
def get_cluster_cur_frequency(self, cluster):
|
||||||
cpu = self.get_cluster_active_cpu(cluster)
|
cpu = self.get_cluster_active_cpu(cluster)
|
||||||
return self.get_cpu_cur_frequency(cpu)
|
return self.get_cpu_frequency(cpu)
|
||||||
|
|
||||||
def set_cluster_cur_frequency(self, cluster, freq):
|
def set_cluster_cur_frequency(self, cluster, freq):
|
||||||
cpu = self.get_cluster_active_cpu(cluster)
|
cpu = self.get_cluster_active_cpu(cluster)
|
||||||
@ -434,7 +436,7 @@ class CpufreqModule(Module):
|
|||||||
self.set_cluster_min_frequency(cluster, freq)
|
self.set_cluster_min_frequency(cluster, freq)
|
||||||
|
|
||||||
def get_core_cur_frequency(self, core):
|
def get_core_cur_frequency(self, core):
|
||||||
return self.get_cpu_cur_frequency(self.get_core_online_cpu(core))
|
return self.get_cpu_frequency(self.get_core_online_cpu(core))
|
||||||
|
|
||||||
def set_core_cur_frequency(self, core, freq):
|
def set_core_cur_frequency(self, core, freq):
|
||||||
for cluster in self.get_core_clusters(core):
|
for cluster in self.get_core_clusters(core):
|
||||||
|
@ -18,9 +18,11 @@ import csv
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from wlauto import ResultProcessor, Parameter
|
from wlauto import ResultProcessor, Parameter
|
||||||
|
from wlauto.core import signal
|
||||||
from wlauto.exceptions import ConfigError
|
from wlauto.exceptions import ConfigError
|
||||||
from wlauto.instrumentation import instrument_is_installed
|
from wlauto.instrumentation import instrument_is_installed
|
||||||
from wlauto.utils.power import report_power_stats
|
from wlauto.utils.power import report_power_stats
|
||||||
|
from wlauto.utils.misc import unique
|
||||||
|
|
||||||
|
|
||||||
class CpuStatesProcessor(ResultProcessor):
|
class CpuStatesProcessor(ResultProcessor):
|
||||||
@ -115,8 +117,10 @@ class CpuStatesProcessor(ResultProcessor):
|
|||||||
def initialize(self, context):
|
def initialize(self, context):
|
||||||
# pylint: disable=attribute-defined-outside-init
|
# pylint: disable=attribute-defined-outside-init
|
||||||
device = context.device
|
device = context.device
|
||||||
if not device.has('cpuidle'):
|
for modname in ['cpuidle', 'cpufreq']:
|
||||||
raise ConfigError('Device does not appear to have cpuidle capability; is the right module installed?')
|
if not device.has(modname):
|
||||||
|
message = 'Device does not appear to have {} capability; is the right module installed?'
|
||||||
|
raise ConfigError(message.format(modname))
|
||||||
if not device.core_names:
|
if not device.core_names:
|
||||||
message = '{} requires"core_names" and "core_clusters" to be specified for the device.'
|
message = '{} requires"core_names" and "core_clusters" to be specified for the device.'
|
||||||
raise ConfigError(message.format(self.name))
|
raise ConfigError(message.format(self.name))
|
||||||
@ -126,6 +130,30 @@ class CpuStatesProcessor(ResultProcessor):
|
|||||||
self.idle_state_names = [idle_states[i] for i in sorted(idle_states.keys())]
|
self.idle_state_names = [idle_states[i] for i in sorted(idle_states.keys())]
|
||||||
self.num_idle_states = len(self.idle_state_names)
|
self.num_idle_states = len(self.idle_state_names)
|
||||||
self.iteration_reports = OrderedDict()
|
self.iteration_reports = OrderedDict()
|
||||||
|
# priority -19: just higher than the slow_start of instrumentation
|
||||||
|
signal.connect(self.set_initial_state, signal.BEFORE_WORKLOAD_EXECUTION, priority=-19)
|
||||||
|
|
||||||
|
def set_initial_state(self, context):
|
||||||
|
# TODO: this does not play well with hotplug but leaving as-is, as this will be changed with
|
||||||
|
# the devilib port anyway.
|
||||||
|
# Write initial frequencies into the trace.
|
||||||
|
# NOTE: this assumes per-cluster DVFS, that is valid for devices that
|
||||||
|
# currently exist. This will need to be updated for per-CPU DFS.
|
||||||
|
self.logger.debug('Writing initial frequencies into trace...')
|
||||||
|
device = context.device
|
||||||
|
cluster_freqs = {}
|
||||||
|
for c in unique(device.core_clusters):
|
||||||
|
cluster_freqs[c] = device.get_cluster_cur_frequency(c)
|
||||||
|
for i, c in enumerate(device.core_clusters):
|
||||||
|
entry = 'CPU {} FREQUENCY: {} kHZ'.format(i, cluster_freqs[c])
|
||||||
|
device.set_sysfile_value('/sys/kernel/debug/tracing/trace_marker',
|
||||||
|
entry, verify=False)
|
||||||
|
|
||||||
|
# Nudge each cpu to force idle state transitions in the trace
|
||||||
|
self.logger.debug('Nudging all cores awake...')
|
||||||
|
for i in xrange(len(device.core_names)):
|
||||||
|
command = device.busybox + ' taskset 0x{:x} {}'
|
||||||
|
device.execute(command.format(1 << i, 'ls'))
|
||||||
|
|
||||||
def process_iteration_result(self, result, context):
|
def process_iteration_result(self, result, context):
|
||||||
trace = context.get_artifact('txttrace')
|
trace = context.get_artifact('txttrace')
|
||||||
|
@ -17,18 +17,21 @@ from __future__ import division
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import csv
|
import csv
|
||||||
|
import re
|
||||||
import logging
|
import logging
|
||||||
from ctypes import c_int32
|
from ctypes import c_int32
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from wlauto.utils.trace_cmd import TraceCmdTrace
|
from wlauto.utils.trace_cmd import TraceCmdTrace, TRACE_MARKER_START, TRACE_MARKER_STOP
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('power')
|
logger = logging.getLogger('power')
|
||||||
|
|
||||||
UNKNOWN_FREQUENCY = -1
|
UNKNOWN_FREQUENCY = -1
|
||||||
|
|
||||||
|
INIT_CPU_FREQ_REGEX = re.compile(r'CPU (?P<cpu>\d+) FREQUENCY: (?P<freq>\d+) kHZ')
|
||||||
|
|
||||||
|
|
||||||
class CorePowerTransitionEvent(object):
|
class CorePowerTransitionEvent(object):
|
||||||
|
|
||||||
@ -66,6 +69,18 @@ class CorePowerDroppedEvents(object):
|
|||||||
__repr__ = __str__
|
__repr__ = __str__
|
||||||
|
|
||||||
|
|
||||||
|
class TraceMarkerEvent(object):
|
||||||
|
|
||||||
|
kind = 'marker'
|
||||||
|
__slots__ = ['name']
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'MARKER: {}'.format(self.name)
|
||||||
|
|
||||||
|
|
||||||
class CpuPowerState(object):
|
class CpuPowerState(object):
|
||||||
|
|
||||||
__slots__ = ['frequency', 'idle_state']
|
__slots__ = ['frequency', 'idle_state']
|
||||||
@ -136,9 +151,12 @@ class PowerStateProcessor(object):
|
|||||||
self.power_state.timestamp = value
|
self.power_state.timestamp = value
|
||||||
|
|
||||||
def __init__(self, core_clusters, num_idle_states,
|
def __init__(self, core_clusters, num_idle_states,
|
||||||
first_cluster_state=sys.maxint, first_system_state=sys.maxint):
|
first_cluster_state=sys.maxint, first_system_state=sys.maxint,
|
||||||
|
wait_for_start_marker=False):
|
||||||
self.power_state = SystemPowerState(len(core_clusters))
|
self.power_state = SystemPowerState(len(core_clusters))
|
||||||
self.requested_states = defaultdict(lambda: -1) # cpu_id -> requeseted state
|
self.requested_states = defaultdict(lambda: -1) # cpu_id -> requeseted state
|
||||||
|
self.wait_for_start_marker = wait_for_start_marker
|
||||||
|
self._saw_start_marker = False
|
||||||
|
|
||||||
idle_state_domains = build_idle_domains(core_clusters,
|
idle_state_domains = build_idle_domains(core_clusters,
|
||||||
num_states=num_idle_states,
|
num_states=num_idle_states,
|
||||||
@ -155,7 +173,9 @@ class PowerStateProcessor(object):
|
|||||||
|
|
||||||
def process(self, event_stream):
|
def process(self, event_stream):
|
||||||
for event in event_stream:
|
for event in event_stream:
|
||||||
yield self.update_power_state(event)
|
next_state = self.update_power_state(event)
|
||||||
|
if self._saw_start_marker or not self.wait_for_start_marker:
|
||||||
|
yield next_state
|
||||||
|
|
||||||
def update_power_state(self, event):
|
def update_power_state(self, event):
|
||||||
"""
|
"""
|
||||||
@ -167,6 +187,11 @@ class PowerStateProcessor(object):
|
|||||||
self._process_transition(event)
|
self._process_transition(event)
|
||||||
elif event.kind == 'dropped_events':
|
elif event.kind == 'dropped_events':
|
||||||
self._process_dropped_events(event)
|
self._process_dropped_events(event)
|
||||||
|
elif event.kind == 'marker':
|
||||||
|
if event.name == 'START':
|
||||||
|
self._saw_start_marker = True
|
||||||
|
elif event.name == 'STOP':
|
||||||
|
self._saw_start_marker = False
|
||||||
else:
|
else:
|
||||||
raise ValueError('Unexpected event type: {}'.format(event.kind))
|
raise ValueError('Unexpected event type: {}'.format(event.kind))
|
||||||
return self.power_state.copy()
|
return self.power_state.copy()
|
||||||
@ -269,6 +294,17 @@ def stream_cpu_power_transitions(events):
|
|||||||
yield CorePowerTransitionEvent(event.timestamp, event.cpu_id, frequency=event.state)
|
yield CorePowerTransitionEvent(event.timestamp, event.cpu_id, frequency=event.state)
|
||||||
elif event.name == 'DROPPED EVENTS DETECTED':
|
elif event.name == 'DROPPED EVENTS DETECTED':
|
||||||
yield CorePowerDroppedEvents(event.cpu_id)
|
yield CorePowerDroppedEvents(event.cpu_id)
|
||||||
|
elif event.name == 'print':
|
||||||
|
if TRACE_MARKER_START in event.text:
|
||||||
|
yield TraceMarkerEvent('START')
|
||||||
|
elif TRACE_MARKER_STOP in event.text:
|
||||||
|
yield TraceMarkerEvent('STOP')
|
||||||
|
else:
|
||||||
|
match = INIT_CPU_FREQ_REGEX.search(event.text)
|
||||||
|
if match:
|
||||||
|
yield CorePowerTransitionEvent(event.timestamp,
|
||||||
|
int(match.group('cpu')),
|
||||||
|
frequency=int(match.group('freq')))
|
||||||
|
|
||||||
|
|
||||||
def gather_core_states(system_state_stream, freq_dependent_idle_states=None): # NOQA
|
def gather_core_states(system_state_stream, freq_dependent_idle_states=None): # NOQA
|
||||||
@ -541,13 +577,14 @@ 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, filter_trace=True):
|
timeline_csv_file=None, filter_trace=False):
|
||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
trace = TraceCmdTrace(filter_markers=filter_trace)
|
trace = TraceCmdTrace(filter_markers=filter_trace)
|
||||||
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,
|
||||||
|
wait_for_start_marker=not filter_trace)
|
||||||
reporters = [
|
reporters = [
|
||||||
ParallelStats(core_clusters, use_ratios),
|
ParallelStats(core_clusters, use_ratios),
|
||||||
PowerStateStats(core_names, idle_state_names, use_ratios)
|
PowerStateStats(core_names, idle_state_names, use_ratios)
|
||||||
@ -556,7 +593,7 @@ def report_power_stats(trace_file, idle_state_names, core_names, core_clusters,
|
|||||||
reporters.append(PowerStateTimeline(timeline_csv_file,
|
reporters.append(PowerStateTimeline(timeline_csv_file,
|
||||||
core_names, idle_state_names))
|
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', 'print'])
|
||||||
transition_stream = stream_cpu_power_transitions(event_stream)
|
transition_stream = stream_cpu_power_transitions(event_stream)
|
||||||
power_state_stream = ps_processor.process(transition_stream)
|
power_state_stream = ps_processor.process(transition_stream)
|
||||||
core_state_stream = gather_core_states(power_state_stream)
|
core_state_stream = gather_core_states(power_state_stream)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user