mirror of
https://github.com/ARM-software/devlib.git
synced 2025-09-07 04:21:54 +01:00
exceptions: Classify transient exceptions
Exceptions such as TargetError can sometimes be raised because of a network issue, which is useful to distinguish from errors caused by a missing feature for automated testing environments. The following exceptions are introduced: * DevlibStableError: raised when a non-transient error is encountered * TargetStableError * DevlibTransientError: raised when a transient error is encountered, including timeouts. * TargetTransientError When there is an ambiguity on the type of exception to use, it can be assumed that the configuration is correct, and therefore it is a transient error, unless the function is specifically designed to probe a property of the system. In that case, ambiguity is allowed to be lifted by assuming a non-transient error, since we expect it to raise an exception when that property is not met. Such ambiguous case can appear when checking Android has booted, since we cannot know if this is a timeout/connection issue, or an actual issue with the Android build or configuration. Another case are the execute() methods, which can be expected to fail on purpose. A new parameter will_succeed=False is added, to automatically turn non transient errors into transient ones if the caller is 100% sure that the command cannot fail unless there is an environment issue that is outside of the scope controlled by the user. devlib now never raises TargetError directly, but one of TargetStableError or TargetTransientError. External code can therefore rely on all (indirect) instances TargetError to be in either category. Most existing uses of TargetError are replaced by TargetStableError.
This commit is contained in:
committed by
Marc Bonnici
parent
d6d322c8ac
commit
511d478164
@@ -18,7 +18,7 @@ import re
|
||||
from collections import namedtuple
|
||||
|
||||
from devlib.module import Module
|
||||
from devlib.exception import TargetError
|
||||
from devlib.exception import TargetStableError
|
||||
from devlib.utils.misc import list_to_ranges, isiterable
|
||||
from devlib.utils.types import boolean
|
||||
|
||||
@@ -281,7 +281,7 @@ class CGroup(object):
|
||||
self.target.execute('[ -d {0} ]'\
|
||||
.format(self.directory), as_root=True)
|
||||
return True
|
||||
except TargetError:
|
||||
except TargetStableError:
|
||||
return False
|
||||
|
||||
def get(self):
|
||||
@@ -319,7 +319,7 @@ class CGroup(object):
|
||||
# Set the attribute value
|
||||
try:
|
||||
self.target.write_value(path, attrs[idx])
|
||||
except TargetError:
|
||||
except TargetStableError:
|
||||
# Check if the error is due to a non-existing attribute
|
||||
attrs = self.get()
|
||||
if idx not in attrs:
|
||||
@@ -389,9 +389,9 @@ class CgroupsModule(Module):
|
||||
controller = Controller(ss.name, hid, hierarchy[hid])
|
||||
try:
|
||||
controller.mount(self.target, self.cgroup_root)
|
||||
except TargetError:
|
||||
except TargetStableError:
|
||||
message = 'Failed to mount "{}" controller'
|
||||
raise TargetError(message.format(controller.kind))
|
||||
raise TargetStableError(message.format(controller.kind))
|
||||
self.logger.info(' %-12s : %s', controller.kind,
|
||||
controller.mount_point)
|
||||
self.controllers[ss.name] = controller
|
||||
|
@@ -13,7 +13,7 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
from devlib.module import Module
|
||||
from devlib.exception import TargetError
|
||||
from devlib.exception import TargetStableError
|
||||
from devlib.utils.misc import memoized
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ class CpufreqModule(Module):
|
||||
Setting the governor on any core in a cluster will also set it on all
|
||||
other cores in that cluster.
|
||||
|
||||
:raises: TargetError if governor is not supported by the CPU, or if,
|
||||
:raises: TargetStableError if governor is not supported by the CPU, or if,
|
||||
for some reason, the governor could not be set.
|
||||
|
||||
"""
|
||||
@@ -90,7 +90,7 @@ class CpufreqModule(Module):
|
||||
cpu = 'cpu{}'.format(cpu)
|
||||
supported = self.list_governors(cpu)
|
||||
if governor not in supported:
|
||||
raise TargetError('Governor {} not supported for cpu {}'.format(governor, cpu))
|
||||
raise TargetStableError('Governor {} not supported for cpu {}'.format(governor, cpu))
|
||||
sysfile = '/sys/devices/system/cpu/{}/cpufreq/scaling_governor'.format(cpu)
|
||||
self.target.write_value(sysfile, governor)
|
||||
self.set_governor_tunables(cpu, governor, **kwargs)
|
||||
@@ -104,11 +104,11 @@ class CpufreqModule(Module):
|
||||
try:
|
||||
tunables_path = '/sys/devices/system/cpu/{}/cpufreq/{}'.format(cpu, governor)
|
||||
self._governor_tunables[governor] = self.target.list_directory(tunables_path)
|
||||
except TargetError: # probably an older kernel
|
||||
except TargetStableError: # probably an older kernel
|
||||
try:
|
||||
tunables_path = '/sys/devices/system/cpu/cpufreq/{}'.format(governor)
|
||||
self._governor_tunables[governor] = self.target.list_directory(tunables_path)
|
||||
except TargetError: # governor does not support tunables
|
||||
except TargetStableError: # governor does not support tunables
|
||||
self._governor_tunables[governor] = []
|
||||
return self._governor_tunables[governor]
|
||||
|
||||
@@ -122,7 +122,7 @@ class CpufreqModule(Module):
|
||||
try:
|
||||
path = '/sys/devices/system/cpu/{}/cpufreq/{}/{}'.format(cpu, governor, tunable)
|
||||
tunables[tunable] = self.target.read_value(path)
|
||||
except TargetError: # May be an older kernel
|
||||
except TargetStableError: # May be an older kernel
|
||||
path = '/sys/devices/system/cpu/cpufreq/{}/{}'.format(governor, tunable)
|
||||
tunables[tunable] = self.target.read_value(path)
|
||||
return tunables
|
||||
@@ -140,7 +140,7 @@ class CpufreqModule(Module):
|
||||
The rest should be keyword parameters mapping tunable name onto the value to
|
||||
be set for it.
|
||||
|
||||
:raises: TargetError if governor specified is not a valid governor name, or if
|
||||
:raises: TargetStableError if governor specified is not a valid governor name, or if
|
||||
a tunable specified is not valid for the governor, or if could not set
|
||||
tunable.
|
||||
|
||||
@@ -155,7 +155,7 @@ class CpufreqModule(Module):
|
||||
path = '/sys/devices/system/cpu/{}/cpufreq/{}/{}'.format(cpu, governor, tunable)
|
||||
try:
|
||||
self.target.write_value(path, value)
|
||||
except TargetError:
|
||||
except TargetStableError:
|
||||
if self.target.file_exists(path):
|
||||
# File exists but we did something wrong
|
||||
raise
|
||||
@@ -165,7 +165,7 @@ class CpufreqModule(Module):
|
||||
else:
|
||||
message = 'Unexpected tunable {} for governor {} on {}.\n'.format(tunable, governor, cpu)
|
||||
message += 'Available tunables are: {}'.format(valid_tunables)
|
||||
raise TargetError(message)
|
||||
raise TargetStableError(message)
|
||||
|
||||
@memoized
|
||||
def list_frequencies(self, cpu):
|
||||
@@ -177,14 +177,14 @@ class CpufreqModule(Module):
|
||||
cmd = 'cat /sys/devices/system/cpu/{}/cpufreq/scaling_available_frequencies'.format(cpu)
|
||||
output = self.target.execute(cmd)
|
||||
available_frequencies = list(map(int, output.strip().split())) # pylint: disable=E1103
|
||||
except TargetError:
|
||||
except TargetStableError:
|
||||
# On some devices scaling_frequencies is not generated.
|
||||
# http://adrynalyne-teachtofish.blogspot.co.uk/2011/11/how-to-enable-scalingavailablefrequenci.html
|
||||
# Fall back to parsing stats/time_in_state
|
||||
path = '/sys/devices/system/cpu/{}/cpufreq/stats/time_in_state'.format(cpu)
|
||||
try:
|
||||
out_iter = iter(self.target.read_value(path).split())
|
||||
except TargetError:
|
||||
except TargetStableError:
|
||||
if not self.target.file_exists(path):
|
||||
# Probably intel_pstate. Can't get available freqs.
|
||||
return []
|
||||
@@ -219,7 +219,7 @@ class CpufreqModule(Module):
|
||||
try to read the minimum frequency and the following exception will be
|
||||
raised ::
|
||||
|
||||
:raises: TargetError if for some reason the frequency could not be read.
|
||||
:raises: TargetStableError if for some reason the frequency could not be read.
|
||||
|
||||
"""
|
||||
if isinstance(cpu, int):
|
||||
@@ -239,7 +239,7 @@ class CpufreqModule(Module):
|
||||
|
||||
on the device.
|
||||
|
||||
:raises: TargetError if the frequency is not supported by the CPU, or if, for
|
||||
:raises: TargetStableError if the frequency is not supported by the CPU, or if, for
|
||||
some reason, frequency could not be set.
|
||||
:raises: ValueError if ``frequency`` is not an integer.
|
||||
|
||||
@@ -250,7 +250,7 @@ class CpufreqModule(Module):
|
||||
try:
|
||||
value = int(frequency)
|
||||
if exact and available_frequencies and value not in available_frequencies:
|
||||
raise TargetError('Can\'t set {} frequency to {}\nmust be in {}'.format(cpu,
|
||||
raise TargetStableError('Can\'t set {} frequency to {}\nmust be in {}'.format(cpu,
|
||||
value,
|
||||
available_frequencies))
|
||||
sysfile = '/sys/devices/system/cpu/{}/cpufreq/scaling_min_freq'.format(cpu)
|
||||
@@ -266,7 +266,7 @@ class CpufreqModule(Module):
|
||||
try to read the current frequency and the following exception will be
|
||||
raised ::
|
||||
|
||||
:raises: TargetError if for some reason the frequency could not be read.
|
||||
:raises: TargetStableError if for some reason the frequency could not be read.
|
||||
|
||||
"""
|
||||
if isinstance(cpu, int):
|
||||
@@ -288,7 +288,7 @@ class CpufreqModule(Module):
|
||||
|
||||
on the device (if it exists).
|
||||
|
||||
:raises: TargetError if the frequency is not supported by the CPU, or if, for
|
||||
:raises: TargetStableError if the frequency is not supported by the CPU, or if, for
|
||||
some reason, frequency could not be set.
|
||||
:raises: ValueError if ``frequency`` is not an integer.
|
||||
|
||||
@@ -300,11 +300,11 @@ class CpufreqModule(Module):
|
||||
if exact:
|
||||
available_frequencies = self.list_frequencies(cpu)
|
||||
if available_frequencies and value not in available_frequencies:
|
||||
raise TargetError('Can\'t set {} frequency to {}\nmust be in {}'.format(cpu,
|
||||
raise TargetStableError('Can\'t set {} frequency to {}\nmust be in {}'.format(cpu,
|
||||
value,
|
||||
available_frequencies))
|
||||
if self.get_governor(cpu) != 'userspace':
|
||||
raise TargetError('Can\'t set {} frequency; governor must be "userspace"'.format(cpu))
|
||||
raise TargetStableError('Can\'t set {} frequency; governor must be "userspace"'.format(cpu))
|
||||
sysfile = '/sys/devices/system/cpu/{}/cpufreq/scaling_setspeed'.format(cpu)
|
||||
self.target.write_value(sysfile, value, verify=False)
|
||||
except ValueError:
|
||||
@@ -318,7 +318,7 @@ class CpufreqModule(Module):
|
||||
try to read the maximum frequency and the following exception will be
|
||||
raised ::
|
||||
|
||||
:raises: TargetError if for some reason the frequency could not be read.
|
||||
:raises: TargetStableError if for some reason the frequency could not be read.
|
||||
"""
|
||||
if isinstance(cpu, int):
|
||||
cpu = 'cpu{}'.format(cpu)
|
||||
@@ -337,7 +337,7 @@ class CpufreqModule(Module):
|
||||
|
||||
on the device.
|
||||
|
||||
:raises: TargetError if the frequency is not supported by the CPU, or if, for
|
||||
:raises: TargetStableError if the frequency is not supported by the CPU, or if, for
|
||||
some reason, frequency could not be set.
|
||||
:raises: ValueError if ``frequency`` is not an integer.
|
||||
|
||||
@@ -348,7 +348,7 @@ class CpufreqModule(Module):
|
||||
try:
|
||||
value = int(frequency)
|
||||
if exact and available_frequencies and value not in available_frequencies:
|
||||
raise TargetError('Can\'t set {} frequency to {}\nmust be in {}'.format(cpu,
|
||||
raise TargetStableError('Can\'t set {} frequency to {}\nmust be in {}'.format(cpu,
|
||||
value,
|
||||
available_frequencies))
|
||||
sysfile = '/sys/devices/system/cpu/{}/cpufreq/scaling_max_freq'.format(cpu)
|
||||
@@ -409,13 +409,13 @@ class CpufreqModule(Module):
|
||||
return self.target._execute_util(
|
||||
'cpufreq_set_all_governors {}'.format(governor),
|
||||
as_root=True)
|
||||
except TargetError as e:
|
||||
except TargetStableError as e:
|
||||
if ("echo: I/O error" in str(e) or
|
||||
"write error: Invalid argument" in str(e)):
|
||||
|
||||
cpus_unsupported = [c for c in self.target.list_online_cpus()
|
||||
if governor not in self.list_governors(c)]
|
||||
raise TargetError("Governor {} unsupported for CPUs {}".format(
|
||||
raise TargetStableError("Governor {} unsupported for CPUs {}".format(
|
||||
governor, cpus_unsupported))
|
||||
else:
|
||||
raise
|
||||
|
@@ -13,7 +13,7 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
from devlib.module import Module
|
||||
from devlib.exception import TargetError
|
||||
from devlib.exception import TargetStableError
|
||||
from devlib.utils.misc import memoized
|
||||
|
||||
class DevfreqModule(Module):
|
||||
@@ -64,13 +64,13 @@ class DevfreqModule(Module):
|
||||
Additional keyword arguments can be used to specify governor tunables for
|
||||
governors that support them.
|
||||
|
||||
:raises: TargetError if governor is not supported by the device, or if,
|
||||
:raises: TargetStableError if governor is not supported by the device, or if,
|
||||
for some reason, the governor could not be set.
|
||||
|
||||
"""
|
||||
supported = self.list_governors(device)
|
||||
if governor not in supported:
|
||||
raise TargetError('Governor {} not supported for device {}'.format(governor, device))
|
||||
raise TargetStableError('Governor {} not supported for device {}'.format(governor, device))
|
||||
sysfile = '/sys/class/devfreq/{}/governor'.format(device)
|
||||
self.target.write_value(sysfile, governor)
|
||||
|
||||
@@ -94,7 +94,7 @@ class DevfreqModule(Module):
|
||||
will try to read the minimum frequency and the following exception will
|
||||
be raised ::
|
||||
|
||||
:raises: TargetError if for some reason the frequency could not be read.
|
||||
:raises: TargetStableError if for some reason the frequency could not be read.
|
||||
|
||||
"""
|
||||
sysfile = '/sys/class/devfreq/{}/min_freq'.format(device)
|
||||
@@ -112,7 +112,7 @@ class DevfreqModule(Module):
|
||||
|
||||
on the device.
|
||||
|
||||
:raises: TargetError if the frequency is not supported by the device, or if, for
|
||||
:raises: TargetStableError if the frequency is not supported by the device, or if, for
|
||||
some reason, frequency could not be set.
|
||||
:raises: ValueError if ``frequency`` is not an integer.
|
||||
|
||||
@@ -121,7 +121,7 @@ class DevfreqModule(Module):
|
||||
try:
|
||||
value = int(frequency)
|
||||
if exact and available_frequencies and value not in available_frequencies:
|
||||
raise TargetError('Can\'t set {} frequency to {}\nmust be in {}'.format(device,
|
||||
raise TargetStableError('Can\'t set {} frequency to {}\nmust be in {}'.format(device,
|
||||
value,
|
||||
available_frequencies))
|
||||
sysfile = '/sys/class/devfreq/{}/min_freq'.format(device)
|
||||
@@ -137,7 +137,7 @@ class DevfreqModule(Module):
|
||||
will try to read the current frequency and the following exception will
|
||||
be raised ::
|
||||
|
||||
:raises: TargetError if for some reason the frequency could not be read.
|
||||
:raises: TargetStableError if for some reason the frequency could not be read.
|
||||
|
||||
"""
|
||||
sysfile = '/sys/class/devfreq/{}/cur_freq'.format(device)
|
||||
@@ -151,7 +151,7 @@ class DevfreqModule(Module):
|
||||
try to read the maximum frequency and the following exception will be
|
||||
raised ::
|
||||
|
||||
:raises: TargetError if for some reason the frequency could not be read.
|
||||
:raises: TargetStableError if for some reason the frequency could not be read.
|
||||
"""
|
||||
sysfile = '/sys/class/devfreq/{}/max_freq'.format(device)
|
||||
return self.target.read_int(sysfile)
|
||||
@@ -168,7 +168,7 @@ class DevfreqModule(Module):
|
||||
|
||||
on the device.
|
||||
|
||||
:raises: TargetError if the frequency is not supported by the device, or
|
||||
:raises: TargetStableError if the frequency is not supported by the device, or
|
||||
if, for some reason, frequency could not be set.
|
||||
:raises: ValueError if ``frequency`` is not an integer.
|
||||
|
||||
@@ -180,7 +180,7 @@ class DevfreqModule(Module):
|
||||
raise ValueError('Frequency must be an integer; got: "{}"'.format(frequency))
|
||||
|
||||
if exact and value not in available_frequencies:
|
||||
raise TargetError('Can\'t set {} frequency to {}\nmust be in {}'.format(device,
|
||||
raise TargetStableError('Can\'t set {} frequency to {}\nmust be in {}'.format(device,
|
||||
value,
|
||||
available_frequencies))
|
||||
sysfile = '/sys/class/devfreq/{}/max_freq'.format(device)
|
||||
@@ -202,13 +202,13 @@ class DevfreqModule(Module):
|
||||
try:
|
||||
return self.target._execute_util( # pylint: disable=protected-access
|
||||
'devfreq_set_all_governors {}'.format(governor), as_root=True)
|
||||
except TargetError as e:
|
||||
except TargetStableError as e:
|
||||
if ("echo: I/O error" in str(e) or
|
||||
"write error: Invalid argument" in str(e)):
|
||||
|
||||
devs_unsupported = [d for d in self.target.list_devices()
|
||||
if governor not in self.list_governors(d)]
|
||||
raise TargetError("Governor {} unsupported for devices {}".format(
|
||||
raise TargetStableError("Governor {} unsupported for devices {}".format(
|
||||
governor, devs_unsupported))
|
||||
else:
|
||||
raise
|
||||
|
@@ -17,7 +17,7 @@ import sys
|
||||
import os.path
|
||||
from collections import defaultdict
|
||||
|
||||
from devlib.exception import TargetError, HostError
|
||||
from devlib.exception import TargetStableError, HostError
|
||||
from devlib.module import Module
|
||||
from devlib.platform.gem5 import Gem5SimulationPlatform
|
||||
from devlib.utils.gem5 import iter_statistics_dump, GEM5STATS_ROI_NUMBER
|
||||
@@ -87,13 +87,13 @@ class Gem5StatsModule(Module):
|
||||
if label not in self.rois:
|
||||
raise KeyError('Incorrect ROI label: {}'.format(label))
|
||||
if not self.rois[label].start():
|
||||
raise TargetError('ROI {} was already running'.format(label))
|
||||
raise TargetStableError('ROI {} was already running'.format(label))
|
||||
|
||||
def roi_end(self, label):
|
||||
if label not in self.rois:
|
||||
raise KeyError('Incorrect ROI label: {}'.format(label))
|
||||
if not self.rois[label].stop():
|
||||
raise TargetError('ROI {} was not running'.format(label))
|
||||
raise TargetStableError('ROI {} was not running'.format(label))
|
||||
|
||||
def start_periodic_dump(self, delay_ns=0, period_ns=10000000):
|
||||
# Default period is 10ms because it's roughly what's needed to have
|
||||
|
@@ -29,7 +29,7 @@
|
||||
|
||||
import re
|
||||
from devlib.module import Module
|
||||
from devlib.exception import TargetError
|
||||
from devlib.exception import TargetStableError
|
||||
from devlib.utils.misc import memoized
|
||||
|
||||
class GpufreqModule(Module):
|
||||
@@ -56,7 +56,7 @@ class GpufreqModule(Module):
|
||||
|
||||
def set_governor(self, governor):
|
||||
if governor not in self.governors:
|
||||
raise TargetError('Governor {} not supported for gpu'.format(governor))
|
||||
raise TargetStableError('Governor {} not supported for gpu'.format(governor))
|
||||
self.target.write_value("/sys/kernel/gpu/gpu_governor", governor)
|
||||
|
||||
def get_frequencies(self):
|
||||
@@ -73,7 +73,7 @@ class GpufreqModule(Module):
|
||||
try to read the current frequency and the following exception will be
|
||||
raised ::
|
||||
|
||||
:raises: TargetError if for some reason the frequency could not be read.
|
||||
:raises: TargetStableError if for some reason the frequency could not be read.
|
||||
|
||||
"""
|
||||
return int(self.target.read_value("/sys/kernel/gpu/gpu_clock"))
|
||||
|
@@ -15,7 +15,7 @@
|
||||
import re
|
||||
from collections import defaultdict
|
||||
|
||||
from devlib import TargetError
|
||||
from devlib import TargetStableError
|
||||
from devlib.module import Module
|
||||
from devlib.utils.types import integer
|
||||
|
||||
@@ -118,7 +118,7 @@ class HwmonModule(Module):
|
||||
def probe(target):
|
||||
try:
|
||||
target.list_directory(HWMON_ROOT, as_root=target.is_rooted)
|
||||
except TargetError:
|
||||
except TargetStableError:
|
||||
# Doesn't exist or no permissions
|
||||
return False
|
||||
return True
|
||||
|
@@ -20,7 +20,7 @@ import shutil
|
||||
from subprocess import CalledProcessError
|
||||
|
||||
from devlib.module import HardRestModule, BootModule, FlashModule
|
||||
from devlib.exception import TargetError, HostError
|
||||
from devlib.exception import TargetError, TargetStableError, HostError
|
||||
from devlib.utils.serial_port import open_serial_connection, pulse_dtr, write_characters
|
||||
from devlib.utils.uefi import UefiMenu, UefiConfig
|
||||
from devlib.utils.uboot import UbootMenu
|
||||
@@ -89,7 +89,7 @@ class VexpressReboottxtHardReset(HardRestModule):
|
||||
try:
|
||||
if self.target.is_connected:
|
||||
self.target.execute('sync')
|
||||
except TargetError:
|
||||
except (TargetError, CalledProcessError):
|
||||
pass
|
||||
|
||||
if not os.path.exists(self.path):
|
||||
@@ -225,7 +225,7 @@ class VexpressUefiShellBoot(VexpressBootModule):
|
||||
try:
|
||||
menu.select(self.uefi_entry)
|
||||
except LookupError:
|
||||
raise TargetError('Did not see "{}" UEFI entry.'.format(self.uefi_entry))
|
||||
raise TargetStableError('Did not see "{}" UEFI entry.'.format(self.uefi_entry))
|
||||
tty.expect(self.efi_shell_prompt, timeout=self.timeout)
|
||||
if self.bootargs:
|
||||
tty.sendline('') # stop default boot
|
||||
@@ -344,7 +344,7 @@ class VersatileExpressFlashModule(FlashModule):
|
||||
os.system('sync')
|
||||
except (IOError, OSError) as e:
|
||||
msg = 'Could not deploy images to {}; got: {}'
|
||||
raise TargetError(msg.format(self.vemsd_mount, e))
|
||||
raise TargetStableError(msg.format(self.vemsd_mount, e))
|
||||
self.target.boot()
|
||||
self.target.connect(timeout=30)
|
||||
|
||||
@@ -390,4 +390,4 @@ def wait_for_vemsd(vemsd_mount, tty, mcc_prompt=DEFAULT_MCC_PROMPT, short_delay=
|
||||
time.sleep(short_delay * 3)
|
||||
if os.path.exists(path):
|
||||
return
|
||||
raise TargetError('Could not mount {}'.format(vemsd_mount))
|
||||
raise TargetStableError('Could not mount {}'.format(vemsd_mount))
|
||||
|
Reference in New Issue
Block a user