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:
parent
9046ddb15d
commit
c02c6cbceb
@ -13,8 +13,10 @@
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import re
|
||||
from copy import copy
|
||||
from collections import OrderedDict, defaultdict
|
||||
from devlib import TargetError
|
||||
|
||||
from wlauto.exceptions import ConfigError
|
||||
from wlauto.utils.misc import (get_article, merge_config_values)
|
||||
@ -303,10 +305,170 @@ class ConfigurationPoint(object):
|
||||
__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 ###
|
||||
#####################
|
||||
|
||||
|
||||
# pylint: disable=too-many-nested-blocks, too-many-branches
|
||||
def merge_using_priority_specificity(generic_name, specific_name, plugin_cache):
|
||||
"""
|
||||
@ -719,6 +881,22 @@ class JobSpec(Configuration):
|
||||
|
||||
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):
|
||||
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"
|
||||
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
|
||||
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
|
||||
job_spec.set("instrumentation", self.disabled_instruments)
|
||||
|
Loading…
x
Reference in New Issue
Block a user