1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2024-10-06 19:01:15 +01:00
workload-automation/wa/instruments/delay.py

230 lines
10 KiB
Python
Raw Normal View History

# Copyright 2013-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.
#
2018-07-04 17:44:55 +01:00
# pylint: disable=W0613,E1101,E0203,W0201
import time
from wa import Instrument, Parameter
from wa.framework.exception import ConfigError, InstrumentError
from wa.framework.instrument import extremely_slow
class DelayInstrument(Instrument):
name = 'delay'
description = """
This instrument introduces a delay before beginning a new
spec, a new job or before the main execution of a workload.
The delay may be specified as either a fixed period or a temperature
threshold that must be reached.
Optionally, if an active cooling solution is available on the device tqgitq
speed up temperature drop between runs, it may be controlled using this
instrument.
"""
parameters = [
Parameter('temperature_file', default='/sys/devices/virtual/thermal/thermal_zone0/temp',
global_alias='thermal_temp_file',
description="""
Full path to the sysfile on the target that
contains the target's temperature.
"""),
Parameter('temperature_timeout', kind=int, default=600,
global_alias='thermal_timeout',
description="""
The timeout after which the instrument will
stop waiting even if the specified threshold temperature is
not reached. If this timeout is hit, then a warning will be
logged stating the actual temperature at which the timeout has
ended.
"""),
Parameter('temperature_poll_period', kind=int, default=5,
global_alias='thermal_sleep_time',
description="""
How long to sleep (in seconds) between polling
current target temperature.
"""),
Parameter('temperature_between_specs', kind=int, default=None,
global_alias='thermal_threshold_between_specs',
description="""
Temperature (in target-specific units) the
target must cool down to before the iteration spec will be
run.
If this is set to ``0`` then the devices initial temperature will
used as the threshold.
.. note:: This cannot be specified at the same time as
``fixed_between_specs``
"""),
Parameter('fixed_between_specs', kind=int, default=None,
global_alias='fixed_delay_between_specs',
description="""
How long to sleep (in seconds) before starting
a new workload spec.
.. note:: This cannot be specified at the same time as
``temperature_between_specs``
"""),
Parameter('temperature_between_jobs', kind=int, default=None,
global_alias='thermal_threshold_between_jobs',
aliases=['temperature_between_iterations'],
description="""
Temperature (in target-specific units) the
target must cool down to before the next job will be run.
If this is set to ``0`` then the devices initial temperature will
used as the threshold.
.. note:: This cannot be specified at the same time as
``fixed_between_jobs``
"""),
Parameter('fixed_between_jobs', kind=int, default=None,
global_alias='fixed_delay_between_jobs',
aliases=['fixed_between_iterations'],
description="""
How long to sleep (in seconds) before starting each
new job.
.. note:: This cannot be specified at the same time as
``temperature_between_jobs``
"""),
Parameter('fixed_before_start', kind=int, default=None,
global_alias='fixed_delay_before_start',
description="""
How long to sleep (in seconds) after setup for
an iteration has been performed but before running the
workload.
.. note:: This cannot be specified at the same time as
``temperature_before_start``
"""),
Parameter('temperature_before_start', kind=int, default=None,
global_alias='thermal_threshold_before_start',
description="""
Temperature (in device-specific units) the
device must cool down to just before the actual workload
execution (after setup has been performed).
.. note:: This cannot be specified at the same time as
``fixed_between_jobs``
"""),
Parameter('active_cooling', kind=bool, default=False,
description="""
This instrument supports an active cooling
solution while waiting for the device temperature to drop to
the threshold. If you wish to use this feature please ensure
the relevant module is installed on the device.
"""),
]
active_cooling_modules = ['mbed-fan', 'odroidxu3-fan']
def initialize(self, context):
if self.active_cooling:
self.cooling = self._discover_cooling_module()
if not self.cooling:
msg = 'Cooling module not found on target. Please install one of the following modules: {}'
raise InstrumentError(msg.format(self.active_cooling_modules))
if self.temperature_between_jobs == 0:
temp = self.target.read_int(self.temperature_file)
self.logger.debug('Setting temperature threshold between jobs to {}'.format(temp))
self.temperature_between_jobs = temp
if self.temperature_between_specs == 0:
temp = self.target.read_int(self.temperature_file)
msg = 'Setting temperature threshold between workload specs to {}'
self.logger.debug(msg.format(temp))
self.temperature_between_specs = temp
@extremely_slow
def start(self, context):
if self.fixed_before_start:
msg = 'Waiting for {}s before running workload...'
self.logger.info(msg.format(self.fixed_before_start))
time.sleep(self.fixed_before_start)
elif self.temperature_before_start:
self.logger.info('Waiting for temperature drop before running workload...')
self.wait_for_temperature(self.temperature_before_start)
@extremely_slow
def before_job(self, context):
if self.fixed_between_specs and context.spec_changed:
msg = 'Waiting for {}s before starting new spec...'
self.logger.info(msg.format(self.fixed_between_specs))
time.sleep(self.fixed_between_specs)
elif self.temperature_between_jobs and context.spec_changed:
self.logger.info('Waiting for temperature drop before starting new spec...')
self.wait_for_temperature(self.temperature_between_jobs)
elif self.fixed_between_jobs:
msg = 'Waiting for {}s before starting new job...'
self.logger.info(msg.format(self.fixed_between_jobs))
time.sleep(self.fixed_between_jobs)
elif self.temperature_between_jobs:
self.logger.info('Waiting for temperature drop before starting new job...')
self.wait_for_temperature(self.temperature_between_jobs)
def wait_for_temperature(self, temperature):
if self.active_cooling:
self.cooling.start()
self.do_wait_for_temperature(temperature)
self.cooling.stop()
else:
self.do_wait_for_temperature(temperature)
def do_wait_for_temperature(self, temperature):
reading = self.target.read_int(self.temperature_file)
waiting_start_time = time.time()
while reading > temperature:
self.logger.debug('target temperature: {}'.format(reading))
if time.time() - waiting_start_time > self.temperature_timeout:
self.logger.warning('Reached timeout; current temperature: {}'.format(reading))
break
time.sleep(self.temperature_poll_period)
reading = self.target.read_int(self.temperature_file)
def validate(self):
if (self.temperature_between_specs is not None and
self.fixed_between_specs is not None):
raise ConfigError('Both fixed delay and thermal threshold specified for specs.')
if (self.temperature_between_jobs is not None and
self.fixed_between_jobs is not None):
raise ConfigError('Both fixed delay and thermal threshold specified for jobs.')
if (self.temperature_before_start is not None and
self.fixed_before_start is not None):
raise ConfigError('Both fixed delay and thermal threshold specified before start.')
if not any([self.temperature_between_specs, self.fixed_between_specs,
self.temperature_between_jobs, self.fixed_between_jobs,
self.temperature_before_start, self.fixed_before_start]):
raise ConfigError('Delay instrument is enabled, but no delay is specified.')
def _discover_cooling_module(self):
cooling_module = None
for module in self.active_cooling_modules:
if self.target.has(module):
if not cooling_module:
cooling_module = getattr(self.target, module)
else:
msg = 'Multiple cooling modules found "{}" "{}".'
raise InstrumentError(msg.format(cooling_module.name, module))
return cooling_module