1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-01-18 20:11:20 +00:00

Runtime Parameters: WIP - replace me

This commit is contained in:
Sebastian Goscik 2016-08-18 14:03:17 +01:00
parent 9046ddb15d
commit c02c6cbceb

View File

@ -13,8 +13,10 @@
# limitations under the License. # limitations under the License.
import os import os
import re
from copy import copy from copy import copy
from collections import OrderedDict, defaultdict from collections import OrderedDict, defaultdict
from devlib import TargetError
from wlauto.exceptions import ConfigError from wlauto.exceptions import ConfigError
from wlauto.utils.misc import (get_article, merge_config_values) from wlauto.utils.misc import (get_article, merge_config_values)
@ -303,10 +305,170 @@ class ConfigurationPoint(object):
__str__ = __repr__ __str__ = __repr__
class RuntimeParameter(object):
def __init__(self, name,
kind=None,
description=None,
merge=False):
self.name = re.compile(name)
if kind is not None:
if not callable(kind):
raise ValueError('Kind must be callable.')
if kind in KIND_MAP:
kind = KIND_MAP[kind]
else:
kind = str
self.kind = kind
self.description = description
self.merge = merge
def validate_kind(self, value, name):
try:
value = self.kind(value)
except (ValueError, TypeError):
typename = get_type_name(self.kind)
msg = 'Bad value "{}" for {}; must be {} {}'
article = get_article(typename)
raise ConfigError(msg.format(value, name, article, typename))
def match(self, name):
if self.name.match(name):
return True
return False
def update_value(self, name, new_value, source, dest):
self.validate_kind(new_value, name)
if name in dest:
old_value, sources = dest[name]
else:
old_value = None
sources = {}
sources[source] = new_value
if self.merge:
new_value = merge_config_values(old_value, new_value)
dest[name] = (new_value, sources)
class RuntimeParameterManager(object):
runtime_parameters = []
def __init__(self, target_manager):
self.state = {}
self.target_manager = target_manager
def get_initial_state(self):
"""
Should be used to load the starting state from the device. This state
should be updated if any changes are made to the device, and they are successful.
"""
pass
def match(self, name):
for rtp in self.runtime_parameters:
if rtp.match(name):
return True
return False
def update_value(self, name, value, source, dest):
for rtp in self.runtime_parameters:
if rtp.match(name):
rtp.update_value(name, value, source, dest)
break
else:
msg = 'Unknown runtime parameter "{}"'
raise ConfigError(msg.format(name))
def static_validation(self, params):
"""
Validate values that do not require a active device connection.
This method should also pop all runtime parameters meant for this manager
from params, even if they are not beign statically validated.
"""
pass
def dynamic_validation(self, params):
"""
Validate values that require an active device connection
"""
pass
def commit(self):
"""
All values have been validated, this will now actually set values
"""
pass
################################
### RuntimeParameterManagers ###
################################
class CpuFreqParameters(object):
runtime_parameters = {
"cores": RuntimeParameter("(.+)_cores"),
"min_frequency": RuntimeParameter("(.+)_min_frequency", kind=int),
"max_frequency": RuntimeParameter("(.+)_max_frequency", kind=int),
"frequency": RuntimeParameter("(.+)_frequency", kind=int),
"governor": RuntimeParameter("(.+)_governor"),
"governor_tunables": RuntimeParameter("(.+)_governor_tunables"),
}
def __init__(self, target):
super(CpuFreqParameters, self).__init__(target)
self.core_names = set(target.core_names)
def match(self, name):
for param in self.runtime_parameters.itervalues():
if param.match(name):
return True
return False
def update_value(self, name, value, source):
for param in self.runtime_parameters.iteritems():
core_name_match = param.name.match(name)
if not core_name_match:
continue
core_name = core_name_match.groups()[0]
if core_name not in self.core_names:
msg = '"{}" in {} is not a valid core name, must be in: {}'
raise ConfigError(msg.format(core_name, name, ", ".join(self.core_names)))
param.update_value(name, value, source)
break
else:
RuntimeError('"{}" does not belong to CpuFreqParameters'.format(name))
def _get_merged_value(self, core, param_name):
return self.runtime_parameters[param_name].merged_values["{}_{}".format(core, param_name)]
def _cross_validate(self, core):
min_freq = self._get_merged_value(core, "min_frequency")
max_frequency = self._get_merged_value(core, "max_frequency")
if max_frequency < min_freq:
msg = "{core}_max_frequency must be larger than {core}_min_frequency"
raise ConfigError(msg.format(core=core))
frequency = self._get_merged_value(core, "frequency")
if not min_freq < frequency < max_frequency:
msg = "{core}_frequency must be between {core}_min_frequency and {core}_max_frequency"
raise ConfigError(msg.format(core=core))
#TODO: more checks
def commit_to_device(self, target):
pass
# TODO: Write values to device is correct order ect
##################### #####################
### Configuration ### ### Configuration ###
##################### #####################
# pylint: disable=too-many-nested-blocks, too-many-branches # pylint: disable=too-many-nested-blocks, too-many-branches
def merge_using_priority_specificity(generic_name, specific_name, plugin_cache): def merge_using_priority_specificity(generic_name, specific_name, plugin_cache):
""" """
@ -719,6 +881,22 @@ class JobSpec(Configuration):
self.workload_parameters = workload_params self.workload_parameters = workload_params
def merge_runtime_parameters(self, plugin_cache, target_manager):
# Order global runtime parameters
runtime_parameters = OrderedDict()
global_runtime_params = plugin_cache.get_plugin_config("runtime_parameters")
for source in plugin_cache.sources:
runtime_parameters[source] = global_runtime_params[source]
# Add runtime parameters from JobSpec
for source, values in self.to_merge['runtime_parameters'].iteritems():
runtime_parameters[source] = values
# Merge
self.runtime_parameters = target_manager.merge_runtime_parameters(runtime_parameters)
def finalize(self): def finalize(self):
self.id = "-".join([source.config['id'] for source in self._sources[1:]]) # ignore first id, "global" self.id = "-".join([source.config['id'] for source in self._sources[1:]]) # ignore first id, "global"
@ -820,8 +998,11 @@ class JobGenerator(object):
# PHASE 2.2: Merge global, section and workload entry "workload_parameters" # PHASE 2.2: Merge global, section and workload entry "workload_parameters"
job_spec.merge_workload_parameters(self.plugin_cache) job_spec.merge_workload_parameters(self.plugin_cache)
target_manager.static_runtime_parameter_validation(job_spec.runtime_parameters)
# TODO: PHASE 2.3: Validate device runtime/boot paramerers # TODO: PHASE 2.3: Validate device runtime/boot paramerers
job_spec.merge_runtime_parameters(self.plugin_cache, target_manager)
target_manager.validate_runtime_parameters(job_spec.runtime_parameters)
# PHASE 2.4: Disable globally disabled instrumentation # PHASE 2.4: Disable globally disabled instrumentation
job_spec.set("instrumentation", self.disabled_instruments) job_spec.set("instrumentation", self.disabled_instruments)