1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-04-20 09:40:50 +01:00

Implementing dynamic device modules

Dynamic modules may be loaded automatically on device initialization if
the device supports them. Dynamic modules implent probe() method to
determine whether they are supported by a particular deviced.

devcpufreq and cpuidle have been converted into dynamic modules
This commit is contained in:
Sergei Trofimov 2015-06-18 09:42:40 +01:00
parent 73d85c2b4e
commit d9f45db71e
5 changed files with 80 additions and 23 deletions

View File

@ -107,6 +107,11 @@ class BaseLinuxDevice(Device): # pylint: disable=abstract-method
value_name='tunables'), value_name='tunables'),
] ]
dynamic_modules = [
'devcpufreq',
'cpuidle',
]
@property @property
def abi(self): def abi(self):
if not self._abi: if not self._abi:

View File

@ -35,6 +35,7 @@ from collections import OrderedDict
from contextlib import contextmanager from contextlib import contextmanager
from wlauto.core.extension import Extension, ExtensionMeta, AttributeCollection, Parameter from wlauto.core.extension import Extension, ExtensionMeta, AttributeCollection, Parameter
from wlauto.core.extension_loader import ExtensionLoader
from wlauto.exceptions import DeviceError, ConfigError from wlauto.exceptions import DeviceError, ConfigError
from wlauto.utils.types import list_of_integers, list_of, caseless_string from wlauto.utils.types import list_of_integers, list_of, caseless_string
@ -93,10 +94,34 @@ class CoreParameter(RuntimeParameter):
return params return params
class DynamicModuleSpec(dict):
@property
def name(self):
return self.keys()[0]
def __init__(self, *args, **kwargs):
dict.__init__(self)
if args:
if len(args) > 1:
raise ValueError(args)
value = args[0]
else:
value = kwargs
if isinstance(value, basestring):
self[value] = {}
elif isinstance(value, dict) and len(value) == 1:
for k, v in value.iteritems():
self[k] = v
else:
raise ValueError(value)
class DeviceMeta(ExtensionMeta): class DeviceMeta(ExtensionMeta):
to_propagate = ExtensionMeta.to_propagate + [ to_propagate = ExtensionMeta.to_propagate + [
('runtime_parameters', RuntimeParameter, AttributeCollection), ('runtime_parameters', RuntimeParameter, AttributeCollection),
('dynamic_modules', DynamicModuleSpec, AttributeCollection),
] ]
@ -157,6 +182,9 @@ class Device(Extension):
] ]
runtime_parameters = [] runtime_parameters = []
# dynamic modules are loaded or not based on whether the device supports
# them (established at runtime by module probling the device).
dynamic_modules = []
# These must be overwritten by subclasses. # These must be overwritten by subclasses.
name = None name = None
@ -197,7 +225,17 @@ class Device(Extension):
been connecte). been connecte).
""" """
pass loader = ExtensionLoader()
for module_spec in self.dynamic_modules:
module = self._load_module(loader, module_spec)
if not hasattr(module, 'probe'):
message = 'Module {} does not have "probe" attribute; cannot be loaded dynamically'
raise ValueError(message.format(module.name))
if module.probe(self):
self.logger.debug('Installing module "{}"'.format(module.name))
self._install_module(module)
else:
self.logger.debug('Module "{}" is not supported by the device'.format(module.name))
def reset(self): def reset(self):
""" """

View File

@ -598,28 +598,8 @@ class Extension(object):
for module_spec in modules: for module_spec in modules:
if not module_spec: if not module_spec:
continue continue
if isinstance(module_spec, basestring): module = self._load_module(loader, module_spec)
name = module_spec self._install_module(module)
params = {}
elif isinstance(module_spec, dict):
if len(module_spec) != 1:
message = 'Invalid module spec: {}; dict must have exctly one key -- the module name.'
raise ValueError(message.format(module_spec))
name, params = module_spec.items()[0]
else:
message = 'Invalid module spec: {}; must be a string or a one-key dict.'
raise ValueError(message.format(module_spec))
if not isinstance(params, dict):
message = 'Invalid module spec: {}; dict value must also be a dict.'
raise ValueError(message.format(module_spec))
module = loader.get_module(name, owner=self, **params)
module.initialize(None)
for capability in module.capabilities:
if capability not in self.capabilities:
self.capabilities.append(capability)
self._modules.append(module)
def has(self, capability): def has(self, capability):
"""Check if this extension has the specified capability. The alternative method ``can`` is """Check if this extension has the specified capability. The alternative method ``can`` is
@ -629,6 +609,33 @@ class Extension(object):
can = has can = has
def _load_module(self, loader, module_spec):
if isinstance(module_spec, basestring):
name = module_spec
params = {}
elif isinstance(module_spec, dict):
if len(module_spec) != 1:
message = 'Invalid module spec: {}; dict must have exctly one key -- the module name.'
raise ValueError(message.format(module_spec))
name, params = module_spec.items()[0]
else:
message = 'Invalid module spec: {}; must be a string or a one-key dict.'
raise ValueError(message.format(module_spec))
if not isinstance(params, dict):
message = 'Invalid module spec: {}; dict value must also be a dict.'
raise ValueError(message.format(module_spec))
module = loader.get_module(name, owner=self, **params)
module.initialize(None)
return module
def _install_module(self, module):
for capability in module.capabilities:
if capability not in self.capabilities:
self.capabilities.append(capability)
self._modules.append(module)
def __check_from_loader(self): def __check_from_loader(self):
""" """
There are a few things that need to happen in order to get a valide extension instance. There are a few things that need to happen in order to get a valide extension instance.

View File

@ -28,6 +28,10 @@ class CpufreqModule(Module):
""" """
capabilities = ['cpufreq'] capabilities = ['cpufreq']
def probe(self, device): # pylint: disable=no-self-use
path = '/sys/devices/system/cpu/cpufreq'
return device.file_exists(path)
def initialize(self, context): def initialize(self, context):
# pylint: disable=W0201 # pylint: disable=W0201
CpufreqModule._available_governors = {} CpufreqModule._available_governors = {}

View File

@ -86,6 +86,9 @@ class Cpuidle(Module):
root_path = '/sys/devices/system/cpu/cpuidle' root_path = '/sys/devices/system/cpu/cpuidle'
def probe(self, device):
return device.file_exists(self.root_path)
def initialize(self, context): def initialize(self, context):
self.device = self.root_owner self.device = self.root_owner
signal.connect(self._on_device_init, signal.RUN_INIT, priority=1) signal.connect(self._on_device_init, signal.RUN_INIT, priority=1)