1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-03-25 03:59:11 +00:00
Jonathan Paynter dc64152188 configuration, types: Add support for sweeps
Sweeps are handled by one of three handlers, ``autofreq``, ``range`` and
``autoparam``. ``range`` allows the user to manually specify values for
a parameter in the agenda; ``autofreq`` allows cpu frequencies to be
swept through, and autoparam allows other parameters to be swept
through.

autoparam requries the parameter to have ``allowed_values`` specified,
and the sweep specification must supply the plugin name and parameter
name as:
``
	sweep(autoparam):
		param: <param name>
		plugin: <plugin name>
``

autofreq can be used with an empty value:
``
	sweep(autofreq):
``
to sweep through all values of ``frequency`` by default, although if
``plugin`` is specified, other parameters within cpufreq can be swept
through:
``
	sweep(autofreq):
		param: cpu0_frequency
``

For either of the above 'automatic' sweeps, a minimum and/or maximum can
be specified to limit the values generated in the sweep:
``
	sweep(autofreq):
		param: cpu0_frequency
		min: 1000000
		max: 1700000
``

``range`` sweeps support two specification syntaxes: one for manual
specification of a list, and another for a range of values. These sweeps
only accept the plugin name as a parameter:
``
	sweep(range):
		threads: [1, 3, 5, 7]
``
or
``
	sweep(range):
		threads: 1-8,2
		# start-stop[,step]
``
These both produce the same result. step is optional and defaults to 1.

Any sweep specified in a workload entry is equivalent to manually
specifying individual workload entries, each with one of the possible
values of the sweep.

Sweeps specified in sections will create the equivalent of a section
group, each section in that group with one of the sweep values. When the
group name is specified, the 'expanded' section entry will maintain that
group name, otherwise will generate its own.

If multiple sweeps are specified in one entry, then this will be
expanded to one entry for every combination of values of each sweep.
2020-09-10 18:07:16 +01:00

130 lines
3.6 KiB
Python

# Copyright 2016-2018 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
from copy import copy, deepcopy
from wa.utils import log
logger = logging.getLogger('config')
class JobSpecSource(object):
kind = ""
def __init__(self, config, parent=None):
self.config = config
self.parent = parent
self._log_self()
@property
def id(self):
return self.config['id']
def name(self):
raise NotImplementedError()
def _log_self(self):
logger.debug('Creating {} node'.format(self.kind))
with log.indentcontext():
for key, value in self.config.items():
logger.debug('"{}" to "{}"'.format(key, value))
def copy_subtree(self):
raise NotImplementedError()
class WorkloadEntry(JobSpecSource):
kind = "workload"
@property
def name(self):
if self.parent.id == "global":
return 'workload "{}"'.format(self.id)
else:
return 'workload "{}" from section "{}"'.format(self.id, self.parent.id)
def copy_subtree(self):
return WorkloadEntry(deepcopy(self.config), self.parent)
class SectionNode(JobSpecSource):
kind = "section"
@property
def name(self):
if self.id == "global":
return "globally specified configuration"
else:
return 'section "{}"'.format(self.id)
@property
def is_leaf(self):
return not bool(self.children)
def __init__(self, config, parent=None, group=None):
super(SectionNode, self).__init__(config, parent=parent)
self.workload_entries = []
self.children = []
self.group = group
def add_section(self, section, group=None):
# Each level is the same group, only need to check first
if not self.children or group == self.children[0].group:
new_node = SectionNode(section, parent=self, group=group)
self.children.append(new_node)
else:
for child in self.children:
new_node = child.add_section(section, group)
return new_node
def add_workload(self, workload_config):
self.workload_entries.append(WorkloadEntry(workload_config, self))
def descendants(self):
for child in self.children:
for n in child.descendants():
yield n
yield child
def ancestors(self):
if self.parent is not None:
yield self.parent
for ancestor in self.parent.ancestors():
yield ancestor
def leaves(self):
if self.is_leaf:
yield self
else:
for n in self.descendants():
if n.is_leaf:
yield n
def copy_subtree(self):
new_children = [child.copy_subtree() for child in self.children]
new_workloads = copy(self.workload_entries)
new_node = copy(self)
for wkl in new_workloads:
wkl.parent = new_node
for child in new_children:
child.parent = new_node
new_node.children = new_children
new_node.workload_entries = new_workloads
return new_node