mirror of
https://github.com/ARM-software/workload-automation.git
synced 2025-10-29 22:24:51 +00:00
New target description + moving target stuff under "framework"
Changing the way target descriptions work from a static mapping to something that is dynamically generated and is extensible via plugins. Also moving core target implementation stuff under "framework".
This commit is contained in:
0
wa/framework/target/__init__.py
Normal file
0
wa/framework/target/__init__.py
Normal file
20
wa/framework/target/config.py
Normal file
20
wa/framework/target/config.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from copy import copy
|
||||
|
||||
#Not going to be used for now.
|
||||
|
||||
class TargetConfig(dict):
|
||||
"""
|
||||
Represents a configuration for a target.
|
||||
|
||||
"""
|
||||
def __init__(self, config=None):
|
||||
if isinstance(config, TargetConfig):
|
||||
self.__dict__ = copy(config.__dict__)
|
||||
elif hasattr(config, 'iteritems'):
|
||||
for k, v in config.iteritems:
|
||||
self.set(k, v)
|
||||
elif config:
|
||||
raise ValueError(config)
|
||||
|
||||
def set(self, name, value):
|
||||
setattr(self, name, value)
|
||||
252
wa/framework/target/descriptor.py
Normal file
252
wa/framework/target/descriptor.py
Normal file
@@ -0,0 +1,252 @@
|
||||
from collections import OrderedDict
|
||||
from copy import copy
|
||||
|
||||
from devlib import (LinuxTarget, AndroidTarget, LocalLinuxTarget,
|
||||
Platform, Juno, TC2, Gem5SimulationPlatform)
|
||||
|
||||
from wa.framework import pluginloader
|
||||
from wa.framework.exception import PluginLoaderError
|
||||
from wa.framework.plugin import Plugin, Parameter
|
||||
from wa.utils.types import list_of_strings, list_of_ints
|
||||
|
||||
|
||||
def get_target_descriptions(loader=pluginloader):
|
||||
targets = {}
|
||||
for cls in loader.list_target_descriptors():
|
||||
descriptor = cls()
|
||||
for desc in descriptor.get_descriptions():
|
||||
if desc.name in targets:
|
||||
msg = 'Duplicate target "{}" returned by {} and {}'
|
||||
prev_dtor = targets[desc.name].source
|
||||
raise PluginLoaderError(msg.format(dsc.name, prev_dtor.name,
|
||||
descriptor.name))
|
||||
targets[desc.name] = desc
|
||||
return targets.values()
|
||||
|
||||
|
||||
class TargetDescription(object):
|
||||
|
||||
def __init__(self, name, source, description=None, target=None, platform=None,
|
||||
conn=None, target_params=None, platform_params=None,
|
||||
conn_params=None):
|
||||
self.name = name
|
||||
self.source = source
|
||||
self.description = description
|
||||
self.target = target
|
||||
self.platform = platform
|
||||
self.connection = conn
|
||||
self._set('target_params', target_params)
|
||||
self._set('platform_params', platform_params)
|
||||
self._set('conn_params', conn_params)
|
||||
|
||||
def _set(self, attr, vals):
|
||||
if vals is None:
|
||||
vals = {}
|
||||
elif isiterable(vals):
|
||||
if not hasattr(vals, 'iteritems'):
|
||||
vals = {v.name: v for v in vals}
|
||||
else:
|
||||
msg = '{} must be iterable; got "{}"'
|
||||
raise ValueError(msg.format(attr, vals))
|
||||
setattr(self, attr, vals)
|
||||
|
||||
|
||||
class TargetDescriptor(Plugin):
|
||||
|
||||
kind = 'target_descriptor'
|
||||
|
||||
def get_descriptions(self):
|
||||
return []
|
||||
|
||||
|
||||
COMMON_TARGET_PARAMS = [
|
||||
Parameter('working_directory', kind=str,
|
||||
description='''
|
||||
On-target working directory that will be used by WA. This
|
||||
directory must be writable by the user WA logs in as without
|
||||
the need for privilege elevation.
|
||||
'''),
|
||||
Parameter('executables_directory', kind=str,
|
||||
description='''
|
||||
On-target directory where WA will install its executable
|
||||
binaries. This location must allow execution. This location does
|
||||
*not* need to be writable by unprivileged users or rooted devices
|
||||
(WA will install with elevated privileges as necessary).
|
||||
'''),
|
||||
Parameter('modules', kind=list_of_strings,
|
||||
description='''
|
||||
A list of additional modules to be installed for the target.
|
||||
|
||||
``devlib`` implements functionality for particular subsystems as
|
||||
modules. A number of "default" modules (e.g. for cpufreq
|
||||
subsystem) are loaded automatically, unless explicitly disabled.
|
||||
If additional modules need to be loaded, they may be specified
|
||||
using this parameter.
|
||||
|
||||
Please see ``devlab`` documentation for information on the available
|
||||
modules.
|
||||
'''),
|
||||
]
|
||||
|
||||
COMMON_PLATFORM_PARAMS = [
|
||||
Parameter('core_names', kind=list_of_strings,
|
||||
description='''
|
||||
List of names of CPU cores in the order that they appear to the
|
||||
kernel. If not specified, it will be inferred from the platform.
|
||||
'''),
|
||||
Parameter('core_clusters', kind=list_of_ints,
|
||||
description='''
|
||||
Cluster mapping corresponding to the cores in ``core_names``.
|
||||
Cluster indexing starts at ``0``. If not specified, this will be
|
||||
inferred from ``core_names`` -- consecutive cores with the same
|
||||
name will be assumed to share a cluster.
|
||||
'''),
|
||||
Parameter('big_core', kind=str,
|
||||
description='''
|
||||
The name of the big cores in a big.LITTLE system. If not
|
||||
specified, this will be inferred, either from the name (if one of
|
||||
the names in ``core_names`` matches known big cores), or by
|
||||
assuming that the last cluster is big.
|
||||
'''),
|
||||
Parameter('model', kind=str,
|
||||
description='''
|
||||
Hardware model of the platform. If not specified, an attempt will
|
||||
be made to read it from target.
|
||||
'''),
|
||||
Parameter('modules', kind=list_of_strings,
|
||||
description='''
|
||||
An additional list of modules to be loaded into the target.
|
||||
'''),
|
||||
]
|
||||
|
||||
VEXPRESS_PLATFORM_PARAMS = [
|
||||
Parameter('serial_port', kind=str,
|
||||
description='''
|
||||
The serial device/port on the host for the initial connection to
|
||||
the target (used for early boot, flashing, etc).
|
||||
'''),
|
||||
Parameter('baudrate', kind=int,
|
||||
description='''
|
||||
Baud rate for the serial connection.
|
||||
'''),
|
||||
Parameter('vemsd_mount', kind=str,
|
||||
description='''
|
||||
VExpress MicroSD card mount location. This is a MicroSD card in
|
||||
the VExpress device that is mounted on the host via USB. The card
|
||||
contains configuration files for the platform and firmware and
|
||||
kernel images to be flashed.
|
||||
'''),
|
||||
Parameter('bootloader', kind=str,
|
||||
allowed_values=['uefi', 'uefi-shell', 'u-boot', 'bootmon'],
|
||||
description='''
|
||||
Selects the bootloader mechanism used by the board. Depending on
|
||||
firmware version, a number of possible boot mechanisms may be use.
|
||||
|
||||
Please see ``devlib`` documentation for descriptions.
|
||||
'''),
|
||||
Parameter('hard_reset_method', kind=str,
|
||||
allowed_values=['dtr', 'reboottxt'],
|
||||
description='''
|
||||
There are a couple of ways to reset VersatileExpress board if the
|
||||
software running on the board becomes unresponsive. Both require
|
||||
configuration to be enabled (please see ``devlib`` documentation).
|
||||
|
||||
``dtr``: toggle the DTR line on the serial connection
|
||||
``reboottxt``: create ``reboot.txt`` in the root of the VEMSD mount.
|
||||
|
||||
'''),
|
||||
]
|
||||
|
||||
GEM5_PLATFORM_PARAMS = [
|
||||
Parameter('host_output_dir', kind=str, mandatory=True,
|
||||
description='''
|
||||
Path on the host where gem5 output (e.g. stats file) will be placed.
|
||||
'''),
|
||||
Parameter('gem5_bin', kind=str, mandatory=True,
|
||||
description='''
|
||||
Path to the gem5 binary
|
||||
'''),
|
||||
Parameter('gem5_args', kind=str, mandatory=True,
|
||||
description='''
|
||||
Arguments to be passed to the gem5 binary
|
||||
'''),
|
||||
Parameter('gem5_virtio', kind=str, mandatory=True,
|
||||
description='''
|
||||
VirtIO device setup arguments to be passed to gem5. VirtIO is used
|
||||
to transfer files between the simulation and the host.
|
||||
'''),
|
||||
]
|
||||
|
||||
# name --> (target_class, params_list, defaults)
|
||||
TARGETS = {
|
||||
'linux': (LinuxTarget, COMMON_TARGET_PARAMS, None),
|
||||
'android': (AndroidTarget, COMMON_TARGET_PARAMS +
|
||||
[Parameter('package_data_directory', kind=str, default='/data/data',
|
||||
description='''
|
||||
Directory containing Android data
|
||||
'''),
|
||||
], None),
|
||||
'local': (LocalLinuxTarget, COMMON_TARGET_PARAMS, None),
|
||||
}
|
||||
|
||||
# name --> (platform_class, params_list, defaults)
|
||||
PLATFORMS = {
|
||||
'generic': (Platform, COMMON_PLATFORM_PARAMS, None),
|
||||
'juno': (Juno, COMMON_PLATFORM_PARAMS + VEXPRESS_PLATFORM_PARAMS,
|
||||
{
|
||||
'vemsd_mount': '/media/JUNO',
|
||||
'baudrate': 115200,
|
||||
'bootloader': 'u-boot',
|
||||
'hard_reset_method': 'dtr',
|
||||
}),
|
||||
'tc2': (TC2, COMMON_PLATFORM_PARAMS + VEXPRESS_PLATFORM_PARAMS,
|
||||
{
|
||||
'vemsd_mount': '/media/VEMSD',
|
||||
'baudrate': 38400,
|
||||
'bootloader': 'bootmon',
|
||||
'hard_reset_method': 'reboottxt',
|
||||
}),
|
||||
'gem5': (Gem5SimulationPlatform, GEM5_PLATFORM_PARAMS, None),
|
||||
}
|
||||
|
||||
|
||||
class DefaultTargetDescriptor(TargetDescriptor):
|
||||
|
||||
name = 'devlib_targets'
|
||||
|
||||
description = """
|
||||
The default target descriptor that provides descriptions in the form
|
||||
<platform>_<target>.
|
||||
|
||||
These map directly onto ``Target``\ s and ``Platform``\ s supplied by ``devlib``.
|
||||
|
||||
"""
|
||||
|
||||
def get_descriptions(self):
|
||||
result = []
|
||||
for target_name, target_tuple in TARGETS.iteritems():
|
||||
target, target_params = self._get_item(target_tuple)
|
||||
for platform_name, platform_tuple in PLATFORMS.iteritems():
|
||||
platform, platform_params = self._get_item(platform_tuple)
|
||||
|
||||
name = '{}_{}'.format(platform_name, target_name)
|
||||
td = TargetDescription(name, self)
|
||||
td.target = target
|
||||
td.platform = platform
|
||||
td.target_params = target_params
|
||||
td.platform_params = platform_params
|
||||
result.append(td)
|
||||
return result
|
||||
|
||||
def _get_item(self, item_tuple):
|
||||
cls, params, defaults = item_tuple
|
||||
if not defaults:
|
||||
return cls, params
|
||||
|
||||
param_map = OrderedDict((p.name, copy(p)) for p in params)
|
||||
for name, value in defaults.iteritems():
|
||||
if name not in param_map:
|
||||
raise ValueError('Unexpected default "{}"'.format(name))
|
||||
param_map[name].default = value
|
||||
return cls, param_map.values()
|
||||
|
||||
78
wa/framework/target/info.py
Normal file
78
wa/framework/target/info.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from devlib import AndroidTarget
|
||||
from devlib.exception import TargetError
|
||||
from devlib.target import KernelConfig, KernelVersion, Cpuinfo
|
||||
|
||||
|
||||
class TargetInfo(object):
|
||||
|
||||
@staticmethod
|
||||
def from_pod(pod):
|
||||
instance = TargetInfo()
|
||||
instance.target = pod['target']
|
||||
instance.abi = pod['abi']
|
||||
instance.cpuinfo = Cpuinfo(pod['cpuinfo'])
|
||||
instance.os = pod['os']
|
||||
instance.os_version = pod['os_version']
|
||||
instance.abi = pod['abi']
|
||||
instance.is_rooted = pod['is_rooted']
|
||||
instance.kernel_version = KernelVersion(pod['kernel_release'],
|
||||
pod['kernel_version'])
|
||||
instance.kernel_config = KernelConfig(pod['kernel_config'])
|
||||
|
||||
if pod["target"] == "AndroidTarget":
|
||||
instance.screen_resolution = pod['screen_resolution']
|
||||
instance.prop = pod['prop']
|
||||
instance.prop = pod['android_id']
|
||||
|
||||
return instance
|
||||
|
||||
def __init__(self, target=None):
|
||||
if target:
|
||||
self.target = target.__class__.__name__
|
||||
self.cpuinfo = target.cpuinfo
|
||||
self.os = target.os
|
||||
self.os_version = target.os_version
|
||||
self.abi = target.abi
|
||||
self.is_rooted = target.is_rooted
|
||||
self.kernel_version = target.kernel_version
|
||||
self.kernel_config = target.config
|
||||
|
||||
if isinstance(target, AndroidTarget):
|
||||
self.screen_resolution = target.screen_resolution
|
||||
self.prop = target.getprop()
|
||||
self.android_id = target.android_id
|
||||
|
||||
else:
|
||||
self.target = None
|
||||
self.cpuinfo = None
|
||||
self.os = None
|
||||
self.os_version = None
|
||||
self.abi = None
|
||||
self.is_rooted = None
|
||||
self.kernel_version = None
|
||||
self.kernel_config = None
|
||||
|
||||
if isinstance(target, AndroidTarget):
|
||||
self.screen_resolution = None
|
||||
self.prop = None
|
||||
self.android_id = None
|
||||
|
||||
def to_pod(self):
|
||||
pod = {}
|
||||
pod['target'] = self.target
|
||||
pod['abi'] = self.abi
|
||||
pod['cpuinfo'] = self.cpuinfo.sections
|
||||
pod['os'] = self.os
|
||||
pod['os_version'] = self.os_version
|
||||
pod['abi'] = self.abi
|
||||
pod['is_rooted'] = self.is_rooted
|
||||
pod['kernel_release'] = self.kernel_version.release
|
||||
pod['kernel_version'] = self.kernel_version.version
|
||||
pod['kernel_config'] = dict(self.kernel_config.iteritems())
|
||||
|
||||
if self.target == "AndroidTarget":
|
||||
pod['screen_resolution'] = self.screen_resolution
|
||||
pod['prop'] = self.prop
|
||||
pod['android_id'] = self.android_id
|
||||
|
||||
return pod
|
||||
383
wa/framework/target/manager.py
Normal file
383
wa/framework/target/manager.py
Normal file
@@ -0,0 +1,383 @@
|
||||
import logging
|
||||
import tempfile
|
||||
import threading
|
||||
import os
|
||||
import time
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
from wa.framework import signal
|
||||
from wa.framework.exception import WorkerThreadError, ConfigError
|
||||
from wa.framework.plugin import Parameter
|
||||
from wa.framework.target.info import TargetInfo
|
||||
from wa.framework.target.runtime_config import (SysfileValuesRuntimeConfig,
|
||||
HotplugRuntimeConfig,
|
||||
CpufreqRuntimeConfig,
|
||||
CpuidleRuntimeConfig)
|
||||
from wa.utils.misc import isiterable
|
||||
from wa.utils.serializer import json
|
||||
|
||||
|
||||
from devlib import LocalLinuxTarget, LinuxTarget, AndroidTarget
|
||||
from devlib.utils.types import identifier
|
||||
# from wa.target.manager import AndroidTargetManager, LinuxTargetManager
|
||||
|
||||
|
||||
class TargetManager(object):
|
||||
|
||||
name = 'target-manager'
|
||||
|
||||
description = """
|
||||
Instanciated the required target and performs configuration and validation
|
||||
of the device.
|
||||
|
||||
"""
|
||||
|
||||
parameters = [
|
||||
Parameter('disconnect', kind=bool, default=False,
|
||||
description="""
|
||||
Specifies whether the target should be disconnected from
|
||||
at the end of the run.
|
||||
"""),
|
||||
]
|
||||
|
||||
DEVICE_MAPPING = {'test' : {'platform_name':'generic',
|
||||
'target_name': 'android'},
|
||||
'other': {'platform_name':'test',
|
||||
'target_name': 'linux'},
|
||||
}
|
||||
|
||||
runtime_config_cls = [
|
||||
# order matters
|
||||
SysfileValuesRuntimeConfig,
|
||||
HotplugRuntimeConfig,
|
||||
CpufreqRuntimeConfig,
|
||||
CpuidleRuntimeConfig,
|
||||
]
|
||||
|
||||
def __init__(self, name, parameters):
|
||||
self.name = name
|
||||
self.target = None
|
||||
self.assistant = None
|
||||
self.target_name = None
|
||||
self.platform_name = None
|
||||
self.parameters = parameters
|
||||
self.disconnect = parameters.get('disconnect')
|
||||
self.info = TargetInfo()
|
||||
|
||||
# Determine platform and target based on passed name
|
||||
self._parse_name()
|
||||
# Create target
|
||||
self._get_target()
|
||||
# Create an assistant to perform target specific configuration
|
||||
self._get_assistant()
|
||||
|
||||
### HERE FOR TESTING, WILL BE CALLED EXTERNALLY ###
|
||||
# Connect to device and retrieve details.
|
||||
# self.initialize()
|
||||
# self.add_parameters()
|
||||
# self.validate_parameters()
|
||||
# self.set_parameters()
|
||||
|
||||
def initialize(self):
|
||||
self.runtime_configs = [cls(self.target) for cls in self.runtime_config_cls]
|
||||
# if self.parameters:
|
||||
# self.logger.info('Connecting to the device')
|
||||
with signal.wrap('TARGET_CONNECT'):
|
||||
self.target.connect()
|
||||
# self.info.load(self.target)
|
||||
# info_file = os.path.join(self.context.info_directory, 'target.json')
|
||||
# with open(info_file, 'w') as wfh:
|
||||
# json.dump(self.info.to_pod(), wfh)
|
||||
|
||||
def finalize(self):
|
||||
# self.logger.info('Disconnecting from the device')
|
||||
if self.disconnect:
|
||||
with signal.wrap('TARGET_DISCONNECT'):
|
||||
self.target.disconnect()
|
||||
|
||||
def add_parameters(self, parameters=None):
|
||||
if parameters:
|
||||
self.parameters = parameters
|
||||
if not self.parameters:
|
||||
raise ConfigError('No Configuration Provided')
|
||||
|
||||
for name in self.parameters.keys():
|
||||
for cfg in self.runtime_configs:
|
||||
# if name in cfg.supported_parameters:
|
||||
if any(parameter in name for parameter in cfg.supported_parameters):
|
||||
cfg.add(name, self.parameters.pop(name))
|
||||
|
||||
def validate_parameters(self):
|
||||
for cfg in self.runtime_configs:
|
||||
cfg.validate()
|
||||
|
||||
def set_parameters(self):
|
||||
for cfg in self.runtime_configs:
|
||||
cfg.set()
|
||||
|
||||
def clear_parameters(self):
|
||||
for cfg in self.runtime_configs:
|
||||
cfg.clear()
|
||||
|
||||
def _parse_name(self):
|
||||
# Try and get platform and target
|
||||
self.name = identifier(self.name.replace('-', '_'))
|
||||
if '_' in self.name:
|
||||
self.platform_name, self.target_name = self.name.split('_', 1)
|
||||
elif self.name in self.DEVICE_MAPPING:
|
||||
self.platform_name = self.DEVICE_MAPPING[self.name]['platform_name']
|
||||
self.target_name = self.DEVICE_MAPPING[self.name]['target_name']
|
||||
else:
|
||||
raise ConfigError('Unknown Device Specified {}'.format(self.name))
|
||||
|
||||
def _get_target(self):
|
||||
# Create a corresponding target and target-assistant
|
||||
if self.target_name == 'android':
|
||||
self.target = AndroidTarget()
|
||||
elif self.target_name == 'linux':
|
||||
self.target = LinuxTarget() # pylint: disable=redefined-variable-type
|
||||
elif self.target_name == 'localLinux':
|
||||
self.target = LocalLinuxTarget()
|
||||
else:
|
||||
raise ConfigError('Unknown Target Specified {}'.format(self.target_name))
|
||||
|
||||
def _get_assistant(self):
|
||||
# Create a corresponding target and target-assistant to help with platformy stuff?
|
||||
if self.target_name == 'android':
|
||||
self.assistant = AndroidAssistant(self.target)
|
||||
elif self.target_name in ['linux', 'localLinux']:
|
||||
self.assistant = LinuxAssistant(self.target) # pylint: disable=redefined-variable-type
|
||||
else:
|
||||
raise ConfigError('Unknown Target Specified {}'.format(self.target_name))
|
||||
|
||||
# def validate_runtime_parameters(self, parameters):
|
||||
# for name, value in parameters.iteritems():
|
||||
# self.add_parameter(name, value)
|
||||
# self.validate_parameters()
|
||||
|
||||
# def set_runtime_parameters(self, parameters):
|
||||
# # self.clear()
|
||||
# for name, value in parameters.iteritems():
|
||||
# self.add_parameter(name, value)
|
||||
# self.set_parameters()
|
||||
|
||||
|
||||
class LinuxAssistant(object):
|
||||
|
||||
name = 'linux-assistant'
|
||||
|
||||
description = """
|
||||
Performs configuration, instrumentation, etc. during runs on Linux targets.
|
||||
"""
|
||||
|
||||
def __init__(self, target, **kwargs):
|
||||
self.target = target
|
||||
# parameters = [
|
||||
|
||||
# Parameter('disconnect', kind=bool, default=False,
|
||||
# description="""
|
||||
# Specifies whether the target should be disconnected from
|
||||
# at the end of the run.
|
||||
# """),
|
||||
# ]
|
||||
|
||||
# runtime_config_cls = [
|
||||
# # order matters
|
||||
# SysfileValuesRuntimeConfig,
|
||||
# HotplugRuntimeConfig,
|
||||
# CpufreqRuntimeConfig,
|
||||
# CpuidleRuntimeConfig,
|
||||
# ]
|
||||
|
||||
# def __init__(self, target, context, **kwargs):
|
||||
# # super(LinuxTargetManager, self).__init__(target, context, **kwargs)
|
||||
# self.target = target
|
||||
# self.context = context
|
||||
# self.info = TargetInfo()
|
||||
# self.runtime_configs = [cls(target) for cls in self.runtime_config_cls]
|
||||
|
||||
# def __init__(self):
|
||||
# # super(LinuxTargetManager, self).__init__(target, context, **kwargs)
|
||||
# self.target = target
|
||||
# self.info = TargetInfo()
|
||||
# self.parameters = parameters
|
||||
|
||||
# self.info = TargetInfo()
|
||||
# self.runtime_configs = [cls(target) for cls in self.runtime_config_cls]
|
||||
|
||||
# def initialize(self):
|
||||
# # self.runtime_configs = [cls(self.target) for cls in self.runtime_config_cls]
|
||||
# # if self.parameters:
|
||||
# self.logger.info('Connecting to the device')
|
||||
# with signal.wrap('TARGET_CONNECT'):
|
||||
# self.target.connect()
|
||||
# self.info.load(self.target)
|
||||
# # info_file = os.path.join(self.context.info_directory, 'target.json')
|
||||
# # with open(info_file, 'w') as wfh:
|
||||
# # json.dump(self.info.to_pod(), wfh)
|
||||
|
||||
# def finalize(self, runner):
|
||||
# self.logger.info('Disconnecting from the device')
|
||||
# if self.disconnect:
|
||||
# with signal.wrap('TARGET_DISCONNECT'):
|
||||
# self.target.disconnect()
|
||||
|
||||
# def _add_parameters(self):
|
||||
# for name, value in self.parameters.iteritems():
|
||||
# self.add_parameter(name, value)
|
||||
|
||||
# def validate_runtime_parameters(self, parameters):
|
||||
# self.clear()
|
||||
# for name, value in parameters.iteritems():
|
||||
# self.add_parameter(name, value)
|
||||
# self.validate_parameters()
|
||||
|
||||
# def set_runtime_parameters(self, parameters):
|
||||
# self.clear()
|
||||
# for name, value in parameters.iteritems():
|
||||
# self.add_parameter(name, value)
|
||||
# self.set_parameters()
|
||||
|
||||
# def clear_parameters(self):
|
||||
# for cfg in self.runtime_configs:
|
||||
# cfg.clear()
|
||||
|
||||
# def add_parameter(self, name, value):
|
||||
# for cfg in self.runtime_configs:
|
||||
# if name in cfg.supported_parameters:
|
||||
# cfg.add(name, value)
|
||||
# return
|
||||
# raise ConfigError('Unexpected runtime parameter "{}".'.format(name))
|
||||
|
||||
# def validate_parameters(self):
|
||||
# for cfg in self.runtime_configs:
|
||||
# cfg.validate()
|
||||
|
||||
# def set_parameters(self):
|
||||
# for cfg in self.runtime_configs:
|
||||
# cfg.set()
|
||||
|
||||
|
||||
class AndroidAssistant(LinuxAssistant):
|
||||
|
||||
name = 'android-assistant'
|
||||
description = """
|
||||
Extends ``LinuxTargetManager`` with Android-specific operations.
|
||||
"""
|
||||
|
||||
parameters = [
|
||||
Parameter('logcat_poll_period', kind=int,
|
||||
description="""
|
||||
If specified, logcat will cached in a temporary file on the
|
||||
host every ``logcat_poll_period`` seconds. This is useful for
|
||||
longer job executions, where on-device logcat buffer may not be
|
||||
big enough to capture output for the entire execution.
|
||||
"""),
|
||||
]
|
||||
|
||||
def __init__(self, target, **kwargs):
|
||||
super(AndroidAssistant, self).__init__(target)
|
||||
self.logcat_poll_period = kwargs.get('logcat_poll_period', None)
|
||||
if self.logcat_poll_period:
|
||||
self.logcat_poller = LogcatPoller(target, self.logcat_poll_period)
|
||||
else:
|
||||
self.logcat_poller = None
|
||||
|
||||
# def __init__(self, target, context, **kwargs):
|
||||
# super(AndroidAssistant, self).__init__(target, context, **kwargs)
|
||||
# self.logcat_poll_period = kwargs.get('logcat_poll_period', None)
|
||||
# if self.logcat_poll_period:
|
||||
# self.logcat_poller = LogcatPoller(target, self.logcat_poll_period)
|
||||
# else:
|
||||
# self.logcat_poller = None
|
||||
|
||||
# def next_job(self, job):
|
||||
# super(AndroidAssistant, self).next_job(job)
|
||||
# if self.logcat_poller:
|
||||
# self.logcat_poller.start()
|
||||
|
||||
# def job_done(self, job):
|
||||
# super(AndroidAssistant, self).job_done(job)
|
||||
# if self.logcat_poller:
|
||||
# self.logcat_poller.stop()
|
||||
# outfile = os.path.join(self.context.output_directory, 'logcat.log')
|
||||
# self.logger.debug('Dumping logcat to {}'.format(outfile))
|
||||
# self.dump_logcat(outfile)
|
||||
# self.clear()
|
||||
|
||||
def dump_logcat(self, outfile):
|
||||
if self.logcat_poller:
|
||||
self.logcat_poller.write_log(outfile)
|
||||
else:
|
||||
self.target.dump_logcat(outfile)
|
||||
|
||||
def clear_logcat(self):
|
||||
if self.logcat_poller:
|
||||
self.logcat_poller.clear_buffer()
|
||||
|
||||
|
||||
class LogcatPoller(threading.Thread):
|
||||
|
||||
def __init__(self, target, period=60, timeout=30):
|
||||
super(LogcatPoller, self).__init__()
|
||||
self.target = target
|
||||
self.logger = logging.getLogger('logcat')
|
||||
self.period = period
|
||||
self.timeout = timeout
|
||||
self.stop_signal = threading.Event()
|
||||
self.lock = threading.Lock()
|
||||
self.buffer_file = tempfile.mktemp()
|
||||
self.last_poll = 0
|
||||
self.daemon = True
|
||||
self.exc = None
|
||||
|
||||
def start(self):
|
||||
self.logger.debug('starting polling')
|
||||
try:
|
||||
while True:
|
||||
if self.stop_signal.is_set():
|
||||
break
|
||||
with self.lock:
|
||||
current_time = time.time()
|
||||
if (current_time - self.last_poll) >= self.period:
|
||||
self.poll()
|
||||
time.sleep(0.5)
|
||||
except Exception: # pylint: disable=W0703
|
||||
self.exc = WorkerThreadError(self.name, sys.exc_info())
|
||||
self.logger.debug('polling stopped')
|
||||
|
||||
def stop(self):
|
||||
self.logger.debug('Stopping logcat polling')
|
||||
self.stop_signal.set()
|
||||
self.join(self.timeout)
|
||||
if self.is_alive():
|
||||
self.logger.error('Could not join logcat poller thread.')
|
||||
if self.exc:
|
||||
raise self.exc # pylint: disable=E0702
|
||||
|
||||
def clear_buffer(self):
|
||||
self.logger.debug('clearing logcat buffer')
|
||||
with self.lock:
|
||||
self.target.clear_logcat()
|
||||
with open(self.buffer_file, 'w') as _: # NOQA
|
||||
pass
|
||||
|
||||
def write_log(self, outfile):
|
||||
with self.lock:
|
||||
self.poll()
|
||||
if os.path.isfile(self.buffer_file):
|
||||
shutil.copy(self.buffer_file, outfile)
|
||||
else: # there was no logcat trace at this time
|
||||
with open(outfile, 'w') as _: # NOQA
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
self.logger.debug('closing poller')
|
||||
if os.path.isfile(self.buffer_file):
|
||||
os.remove(self.buffer_file)
|
||||
|
||||
def poll(self):
|
||||
self.last_poll = time.time()
|
||||
self.target.dump_logcat(self.buffer_file, append=True, timeout=self.timeout)
|
||||
self.target.clear_logcat()
|
||||
454
wa/framework/target/runtime_config.py
Normal file
454
wa/framework/target/runtime_config.py
Normal file
@@ -0,0 +1,454 @@
|
||||
from collections import defaultdict, OrderedDict
|
||||
|
||||
from wa.framework.plugin import Plugin
|
||||
from wa.framework.exception import ConfigError
|
||||
|
||||
from devlib.exception import TargetError
|
||||
from devlib.utils.misc import unique
|
||||
from devlib.utils.types import integer
|
||||
|
||||
|
||||
class RuntimeConfig(Plugin):
|
||||
|
||||
kind = 'runtime-config'
|
||||
|
||||
parameters = [
|
||||
]
|
||||
|
||||
# class RuntimeConfig(object):
|
||||
|
||||
@property
|
||||
def supported_parameters(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def core_names(self):
|
||||
return unique(self.target.core_names)
|
||||
|
||||
def __init__(self, target):
|
||||
super(RuntimeConfig, self).__init__()
|
||||
self.target = target
|
||||
|
||||
def initialize(self, context):
|
||||
pass
|
||||
|
||||
def add(self, name, value):
|
||||
raise NotImplementedError()
|
||||
|
||||
def validate(self):
|
||||
return True
|
||||
|
||||
def set(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def clear(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class HotplugRuntimeConfig(RuntimeConfig):
|
||||
##### NOTE: Currently if initialized with cores hotplugged, this will fail when trying to hotplug back in
|
||||
@property
|
||||
def supported_parameters(self):
|
||||
params = ['cores']
|
||||
return params
|
||||
|
||||
def __init__(self, target):
|
||||
super(HotplugRuntimeConfig, self).__init__(target)
|
||||
self.num_cores = defaultdict(dict)
|
||||
|
||||
def add(self, name, value):
|
||||
if not self.target.has('hotplug'):
|
||||
raise TargetError('Target does not support hotplug.')
|
||||
core, _ = split_parameter_name(name, self.supported_parameters)
|
||||
|
||||
# cpus = cpusFromPrefix(core, self.target)
|
||||
# core = name.split('_')[0]
|
||||
value = integer(value)
|
||||
if core not in self.core_names:
|
||||
raise ValueError(name)
|
||||
max_cores = self.core_count(core)
|
||||
if value > max_cores:
|
||||
message = 'Cannot set number of {}\'s to {}; max is {}'
|
||||
raise ValueError(message.format(core, value, max_cores))
|
||||
self.num_cores[core] = value
|
||||
if all(v == 0 for v in self.num_cores.values()):
|
||||
raise ValueError('Cannot set number of all cores to 0')
|
||||
|
||||
def set(self):
|
||||
for c, n in reversed(sorted(self.num_cores.iteritems(),
|
||||
key=lambda x: x[1])):
|
||||
self.set_num_online_cpus(c, n)
|
||||
|
||||
def clear(self):
|
||||
self.num_cores = defaultdict(dict)
|
||||
|
||||
def set_num_online_cpus(self, core, number):
|
||||
indexes = [i for i, c in enumerate(self.target.core_names) if c == core]
|
||||
self.target.hotplug.online(*indexes[:number])
|
||||
self.target.hotplug.offline(*indexes[number:])
|
||||
|
||||
def core_count(self, core):
|
||||
return sum(1 for c in self.target.core_names if c == core)
|
||||
|
||||
|
||||
class SysfileValuesRuntimeConfig(RuntimeConfig):
|
||||
|
||||
@property
|
||||
def supported_parameters(self):
|
||||
return ['sysfile_values']
|
||||
|
||||
def __init__(self, target):
|
||||
super(SysfileValuesRuntimeConfig, self).__init__(target)
|
||||
self.sysfile_values = OrderedDict()
|
||||
|
||||
def add(self, name, value):
|
||||
for f, v in value.iteritems():
|
||||
if f.endswith('+'):
|
||||
f = f[:-1]
|
||||
elif f.endswith('+!'):
|
||||
f = f[:-2] + '!'
|
||||
else:
|
||||
if f.endswith('!'):
|
||||
self._check_exists(f[:-1])
|
||||
else:
|
||||
self._check_exists(f)
|
||||
self.sysfile_values[f] = v
|
||||
|
||||
def set(self):
|
||||
for f, v in self.sysfile_values.iteritems():
|
||||
verify = True
|
||||
if f.endswith('!'):
|
||||
verify = False
|
||||
f = f[:-1]
|
||||
self.target.write_value(f, v, verify=verify)
|
||||
|
||||
def clear(self):
|
||||
self.sysfile_values = OrderedDict()
|
||||
|
||||
def _check_exists(self, path):
|
||||
if not self.target.file_exists(path):
|
||||
raise ConfigError('Sysfile "{}" does not exist.'.format(path))
|
||||
|
||||
|
||||
class CpufreqRuntimeConfig(RuntimeConfig):
|
||||
|
||||
@property
|
||||
def supported_parameters(self):
|
||||
params = ['frequency']
|
||||
params.extend(['max_frequency'])
|
||||
params.extend(['min_frequency'])
|
||||
params.extend(['governor'])
|
||||
params.extend(['governor_tunables'])
|
||||
|
||||
return params
|
||||
|
||||
def __init__(self, target):
|
||||
super(CpufreqRuntimeConfig, self).__init__(target)
|
||||
self.config = defaultdict(dict)
|
||||
self.supports_userspace = None
|
||||
self.supported_freqs = {}
|
||||
self.supported_govenors = {}
|
||||
self.min_supported_freq = {}
|
||||
self.max_supported_freq = {}
|
||||
|
||||
for cpu in self.target.list_online_cpus():
|
||||
self.supported_freqs[cpu] = self.target.cpufreq.list_frequencies(cpu) or []
|
||||
self.supported_govenors[cpu] = self.target.cpufreq.list_governors(cpu) or []
|
||||
|
||||
def add(self, name, value):
|
||||
if not self.target.has('cpufreq'):
|
||||
raise TargetError('Target does not support cpufreq.')
|
||||
|
||||
prefix, parameter = split_parameter_name(name, self.supported_parameters)
|
||||
# Get list of valid cpus for a given prefix.
|
||||
cpus = uniqueDomainCpusFromPrefix(prefix, self.target)
|
||||
|
||||
for cpu in cpus:
|
||||
# if cpu not in self.target.list_online_cpus():
|
||||
# message = 'Unexpected core name "{}"; must be in {}'
|
||||
# raise ConfigError(message.format(core, self.core_names))
|
||||
# try:
|
||||
# cpu = self.target.list_online_cpus(core)[0]
|
||||
# except IndexError:
|
||||
# message = 'Cannot retrieve frequencies for {} as no CPUs are online.'
|
||||
# raise TargetError(message.format(core))
|
||||
if parameter.endswith('frequency'):
|
||||
try:
|
||||
value = integer(value)
|
||||
except ValueError:
|
||||
if value.upper() == 'MAX':
|
||||
value = self.supported_freqs[cpu][-1]
|
||||
elif value.upper() == 'MIN':
|
||||
value = self.supported_freqs[cpu][0]
|
||||
else:
|
||||
msg = 'Invalid value {} specified for {}'
|
||||
raise ConfigError(msg.format(value, parameter))
|
||||
self.config[cpu][parameter] = value
|
||||
|
||||
def set(self):
|
||||
for cpu in self.config:
|
||||
config = self.config[cpu]
|
||||
if config.get('governor'):
|
||||
self.configure_governor(cpu,
|
||||
config.get('governor'),
|
||||
config.get('governor_tunables'))
|
||||
self.configure_frequency(cpu,
|
||||
config.get('frequency'),
|
||||
config.get('min_frequency'),
|
||||
config.get('max_frequency'))
|
||||
|
||||
def clear(self):
|
||||
self.config = defaultdict(dict)
|
||||
|
||||
def validate(self):
|
||||
for cpu in self.config:
|
||||
if cpu not in self.target.list_online_cpus():
|
||||
message = 'Cannot configure frequencies for {} as no CPUs are online.'
|
||||
raise TargetError(message.format(cpu))
|
||||
|
||||
config = self.config[cpu]
|
||||
minf = config.get('min_frequency')
|
||||
maxf = config.get('max_frequency')
|
||||
freq = config.get('frequency')
|
||||
governor = config.get('governor')
|
||||
governor_tunables = config.get('governor_tunables')
|
||||
|
||||
if maxf and minf > maxf:
|
||||
message = '{}: min_frequency ({}) cannot be greater than max_frequency ({})'
|
||||
raise ConfigError(message.format(cpu, minf, maxf))
|
||||
if maxf and freq > maxf:
|
||||
message = '{}: cpu frequency ({}) cannot be greater than max_frequency ({})'
|
||||
raise ConfigError(message.format(cpu, freq, maxf))
|
||||
if freq and minf > freq:
|
||||
message = '{}: min_frequency ({}) cannot be greater than cpu frequency ({})'
|
||||
raise ConfigError(message.format(cpu, minf, freq))
|
||||
|
||||
# Check that either userspace governor is available or min and max do not differ to frequency
|
||||
if 'userspace' not in self.supported_govenors[cpu]:
|
||||
self.supports_userspace = False
|
||||
if minf and minf != freq:
|
||||
message = '{}: "userspace" governor not available, min frequency ({}) cannot be different to frequency {}'
|
||||
raise ConfigError(message.format(cpu, minf, freq))
|
||||
if maxf and maxf != freq:
|
||||
message = '{}: "userspace" governor not available, max frequency ({}) cannot be different to frequency {}'
|
||||
raise ConfigError(message.format(cpu, maxf, freq))
|
||||
else:
|
||||
self.supports_userspace = True
|
||||
|
||||
# Check that specified values are available on the cpu
|
||||
if minf and not minf in self.supported_freqs[cpu]:
|
||||
msg = '{}: Minimum frequency {}Hz not available. Must be in {}'.format(cpu, minf, self.supported_freqs[cpu])
|
||||
raise TargetError(msg)
|
||||
if maxf and not maxf in self.supported_freqs[cpu]:
|
||||
msg = '{}: Maximum frequency {}Hz not available. Must be in {}'.format(cpu, maxf, self.supported_freqs[cpu])
|
||||
raise TargetError(msg)
|
||||
if freq and not freq in self.supported_freqs[cpu]:
|
||||
msg = '{}: Frequency {}Hz not available. Must be in {}'.format(cpu, freq, self.supported_freqs[cpu])
|
||||
raise TargetError(msg)
|
||||
if governor and governor not in self.supported_govenors[cpu]:
|
||||
raise TargetError('{}: {} governor not available'.format(cpu, governor))
|
||||
if governor_tunables and not governor:
|
||||
raise TargetError('{}: {} governor tunables cannot be provided without a governor'.format(cpu, governor))
|
||||
|
||||
def configure_frequency(self, cpu, freq=None, min_freq=None, max_freq=None):
|
||||
if cpu not in self.target.list_online_cpus():
|
||||
message = 'Cannot configure frequencies for {} as no CPUs are online.'
|
||||
raise TargetError(message.format(cpu))
|
||||
|
||||
|
||||
current_min_freq = self.target.cpufreq.get_min_frequency(cpu)
|
||||
current_freq = self.target.cpufreq.get_frequency(cpu)
|
||||
current_max_freq = self.target.cpufreq.get_max_frequency(cpu)
|
||||
|
||||
if freq:
|
||||
# If 'userspace' governor is not available 'spoof' functionality
|
||||
if not self.supports_userspace:
|
||||
min_freq = max_freq = freq
|
||||
# else: # Find better alternative for this.
|
||||
# Set min/max frequency if required
|
||||
# if not min_freq:
|
||||
# min_freq = self.target.cpufreq.get_min_frequency(cpu)
|
||||
# if not max_freq:
|
||||
# max_freq = self.target.cpufreq.get_max_frequency(cpu)
|
||||
|
||||
if freq < current_freq:
|
||||
self.target.cpufreq.set_min_frequency(cpu, min_freq)
|
||||
if self.supports_userspace:
|
||||
self.target.cpufreq.set_frequency(cpu, freq)
|
||||
self.target.cpufreq.set_max_frequency(cpu, max_freq)
|
||||
else:
|
||||
self.target.cpufreq.set_max_frequency(cpu, max_freq)
|
||||
if self.supports_userspace:
|
||||
self.target.cpufreq.set_frequency(cpu, freq)
|
||||
self.target.cpufreq.set_min_frequency(cpu, min_freq)
|
||||
return
|
||||
|
||||
if max_freq:
|
||||
if max_freq < current_min_freq:
|
||||
if min_freq:
|
||||
self.target.cpufreq.set_min_frequency(cpu, min_freq)
|
||||
self.target.cpufreq.set_max_frequency(cpu, max_freq)
|
||||
min_freq_set = True
|
||||
else:
|
||||
message = '{}: Cannot set max_frequency ({}) below current min frequency ({}).'
|
||||
raise TargetError(message.format(cpu, max_freq, current_min_freq))
|
||||
else:
|
||||
self.target.cpufreq.set_max_frequency(cpu, max_freq)
|
||||
if min_freq and not min_freq_set:
|
||||
current_max_freq = max_freq or current_max_freq
|
||||
if min_freq > current_max_freq:
|
||||
message = '{}: Cannot set min_frequency ({}) below current max frequency ({}).'
|
||||
raise TargetError(message.format(cpu, max_freq, current_min_freq))
|
||||
self.target.cpufreq.set_min_frequency(cpu, min_freq)
|
||||
|
||||
|
||||
def configure_governor(self, cpu, governor, governor_tunables=None):
|
||||
if cpu not in self.target.list_online_cpus():
|
||||
message = 'Cannot configure governor for {} as no CPUs are online.'
|
||||
raise TargetError(message.format(cpu))
|
||||
|
||||
# for cpu in self.target.list_online_cpus(cpu): #All cpus or only online?
|
||||
if governor not in self.supported_govenors[cpu]:
|
||||
raise TargetError('{}: {} governor not available'.format(cpu, governor))
|
||||
if governor_tunables:
|
||||
self.target.cpufreq.set_governor(cpu, governor, **governor_tunables)
|
||||
else:
|
||||
self.target.cpufreq.set_governor(cpu, governor)
|
||||
|
||||
|
||||
|
||||
class CpuidleRuntimeConfig(RuntimeConfig):
|
||||
|
||||
@property
|
||||
def supported_parameters(self):
|
||||
params = ['idle_states']
|
||||
return params
|
||||
|
||||
def __init__(self, target):
|
||||
super(CpuidleRuntimeConfig, self).__init__(target)
|
||||
self.config = defaultdict(dict)
|
||||
self.aliases = ['ENABLE_ALL', 'DISABLE_ALL']
|
||||
self.available_states = {}
|
||||
|
||||
for cpu in self.target.list_online_cpus():
|
||||
self.available_states[cpu] = self.target.cpuidle.get_states(cpu) or []
|
||||
|
||||
def add(self, name, values):
|
||||
if not self.target.has('cpufreq'):
|
||||
raise TargetError('Target does not support cpufreq.')
|
||||
|
||||
prefix, _ = split_parameter_name(name, self.supported_parameters)
|
||||
cpus = uniqueDomainCpusFromPrefix(prefix, self.target)
|
||||
|
||||
for cpu in cpus:
|
||||
if values in self.aliases:
|
||||
self.config[cpu] = [values]
|
||||
else:
|
||||
self.config[cpu] = values
|
||||
|
||||
def validate(self):
|
||||
for cpu in self.config:
|
||||
if cpu not in self.target.list_online_cpus():
|
||||
message = 'Cannot configure idle states for {} as no CPUs are online.'
|
||||
raise TargetError(message.format(cpu))
|
||||
for state in self.config[cpu]:
|
||||
state = state[1:] if state.startswith('~') else state
|
||||
# self.available_states.extend(self.aliases)
|
||||
if state not in self.available_states[cpu] + self.aliases:
|
||||
message = 'Unexpected idle state "{}"; must be in {}'
|
||||
raise ConfigError(message.format(state, self.available_states))
|
||||
|
||||
def clear(self):
|
||||
self.config = defaultdict(dict)
|
||||
|
||||
def set(self):
|
||||
for cpu in self.config:
|
||||
for state in self.config[cpu]:
|
||||
self.configure_idle_state(state, cpu)
|
||||
|
||||
def configure_idle_state(self, state, cpu=None):
|
||||
if cpu is not None:
|
||||
if cpu not in self.target.list_online_cpus():
|
||||
message = 'Cannot configure idle state for {} as no CPUs are online {}.'
|
||||
raise TargetError(message.format(self.target.core_names[cpu], self.target.list_online_cpus()))
|
||||
else:
|
||||
cpu = 0
|
||||
|
||||
# Check for aliases
|
||||
if state == 'ENABLE_ALL':
|
||||
self.target.cpuidle.enable_all(cpu)
|
||||
elif state == 'DISABLE_ALL':
|
||||
self.target.cpuidle.disable_all(cpu)
|
||||
elif state.startswith('~'):
|
||||
self.target.cpuidle.disable(state[1:], cpu)
|
||||
else:
|
||||
self.target.cpuidle.enable(state, cpu)
|
||||
|
||||
# TO BE MOVED TO UTILS FILE
|
||||
|
||||
import re
|
||||
# Function to return the cpu prefix without the trailing underscore if
|
||||
# present from a given list of parameters, and its matching parameter
|
||||
def split_parameter_name(name, params):
|
||||
for param in sorted(params, key=len)[::-1]: # Try matching longest parameter first
|
||||
if len(name.split(param)) > 1:
|
||||
prefix, _ = name.split(param)
|
||||
return prefix[:-1], param
|
||||
message = 'Cannot split {}, must in the form [core_]parameter'
|
||||
raise ConfigError(message.format(name))
|
||||
|
||||
def cpusFromPrefix(prefix, target):
|
||||
|
||||
# Deal with big little substitution
|
||||
if prefix.lower() == 'big':
|
||||
prefix = target.big_core
|
||||
if not prefix:
|
||||
raise ConfigError('big core name could not be retrieved')
|
||||
elif prefix.lower() == 'little':
|
||||
prefix = target.little_core
|
||||
if not prefix:
|
||||
raise ConfigError('little core name could not be retrieved')
|
||||
|
||||
cpu_list = target.list_online_cpus() + target.list_offline_cpus()
|
||||
|
||||
# Apply to all cpus
|
||||
if not prefix:
|
||||
cpus = cpu_list
|
||||
|
||||
# Return all cores with specified name
|
||||
elif prefix in target.core_names:
|
||||
cpus = target.core_cpus(prefix)
|
||||
|
||||
# Check if core number has been supplied.
|
||||
else:
|
||||
# core_no = prefix[4]
|
||||
core_no = re.match('cpu([0-9]+)', prefix, re.IGNORECASE)
|
||||
if core_no:
|
||||
cpus = [int(core_no.group(1))]
|
||||
if cpus[0] not in cpu_list:
|
||||
message = 'CPU{} is not available, must be in {}'
|
||||
raise ConfigError(message.format(cpus[0], cpu_list))
|
||||
|
||||
else:
|
||||
message = 'Unexpected core name "{}"'
|
||||
raise ConfigError(message.format(prefix))
|
||||
# Should this be applied for everything or just all cpus?
|
||||
# Make sure not to include any cpus within the same frequency domain
|
||||
# for cpu in cpus:
|
||||
# if cpu not in cpus: # Already removed
|
||||
# continue
|
||||
# cpus = [c for c in cpus if (c is cpu) or
|
||||
# (c not in target.cpufreq.get_domain_cpus(cpu))]
|
||||
# print 'Final results ' + str(cpus)
|
||||
# return cpus
|
||||
return cpus
|
||||
|
||||
# Function to only return cpus list on different frequency domains.
|
||||
def uniqueDomainCpusFromPrefix(prefix, target):
|
||||
cpus = cpusFromPrefix(prefix, target)
|
||||
for cpu in cpus:
|
||||
if cpu not in cpus: # Already removed
|
||||
continue
|
||||
cpus = [c for c in cpus if (c is cpu) or
|
||||
(c not in target.cpufreq.get_domain_cpus(cpu))]
|
||||
return cpus
|
||||
Reference in New Issue
Block a user