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.
|
# 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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user