From: Ondrej Lichtner <olichtne(a)redhat.com>
For now throwing an exception when trying to read/write coalescing
settings to a device that doesn't support them is still the best option.
However, there's a need to easily distinguish and ignore this error in
operations that try to access all properties of a Device class instance,
e.g. enable_readonly_cache. In such cases the tester probably doesn't
care that coalescing isn't supported and has no option to skip it for
the cache generation operation leading to the recipe failing with an
exception.
Handling device capabilities dynamically is a larger feature that might
be hard to implement for now so instead a special
DeviceFeatureNotSupported exception class is added that can be safely
ignored when performing these "bulk"/"iterative" operations.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
---
lnst/Common/DeviceError.py | 3 +++
lnst/Devices/Device.py | 11 +++++++----
lnst/Devices/RemoteDevice.py | 8 +++++++-
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/lnst/Common/DeviceError.py b/lnst/Common/DeviceError.py
index c89541e..dc17205 100644
--- a/lnst/Common/DeviceError.py
+++ b/lnst/Common/DeviceError.py
@@ -32,3 +32,6 @@ class DeviceReadOnly(DeviceError):
class DeviceConfigValueError(DeviceConfigError):
pass
+
+class DeviceFeatureNotSupported(DeviceError):
+ pass
diff --git a/lnst/Devices/Device.py b/lnst/Devices/Device.py
index 3984776..e69a297 100644
--- a/lnst/Devices/Device.py
+++ b/lnst/Devices/Device.py
@@ -23,6 +23,7 @@
from lnst.Common.ExecCmd import exec_cmd
from lnst.Common.DeviceError import DeviceError, DeviceDeleted, DeviceDisabled
from lnst.Common.DeviceError import DeviceConfigError, DeviceConfigValueError
+from lnst.Common.DeviceError import DeviceFeatureNotSupported
from lnst.Common.IpAddress import ipaddress
from lnst.Common.HWAddress import hwaddress
@@ -624,8 +625,9 @@ def _read_adaptive_coalescing(self):
try:
res = re.search(regex, res).groups()
except AttributeError:
- raise DeviceError("No values for coalescence of %s." %
- self.name)
+ raise DeviceFeatureNotSupported(
+ "No values for coalescence of %s." % self.name
+ )
return list(res)
def _write_adaptive_coalescing(self, rx_val, tx_val):
@@ -635,8 +637,9 @@ def _write_adaptive_coalescing(self, rx_val, tx_val):
exec_cmd("ethtool -C %s adaptive-rx %s adaptive-tx %s" %
(self.name, rx_val, tx_val))
except:
- raise DeviceConfigError("Not allowed to modify coalescence "
- "settings for %s." % self.name)
+ raise DeviceFeatureNotSupported(
+ "Not allowed to modify coalescence settings for %s." %
self.name
+ )
def restore_coalescing(self):
rx_val = self._cleanup_data["adaptive_rx_coalescing"]
diff --git a/lnst/Devices/RemoteDevice.py b/lnst/Devices/RemoteDevice.py
index 17bc52b..55912ea 100644
--- a/lnst/Devices/RemoteDevice.py
+++ b/lnst/Devices/RemoteDevice.py
@@ -11,9 +11,11 @@
olichtne(a)redhat.com (Ondrej Lichtner)
"""
+import logging
from copy import deepcopy
from lnst.Devices.Device import Device
from lnst.Common.DeviceError import DeviceDeleted, DeviceReadOnly
+from lnst.Common.DeviceError import DeviceFeatureNotSupported
def remotedev_decorator(cls):
def func(*args, **kwargs):
@@ -150,7 +152,11 @@ def __iter__(self):
attr = getattr(self._dev_cls, x)
if not callable(attr):
- yield (x, getattr(self, x))
+ try:
+ yield (x, getattr(self, x))
+ except DeviceFeatureNotSupported as e:
+ logging.debug(str(e))
+ continue
def _match_update_data(self, data):
return False
--
2.23.0
Show replies by date
From: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
---
lnst/Devices/RemoteDevice.py | 3 ---
1 file changed, 3 deletions(-)
diff --git a/lnst/Devices/RemoteDevice.py b/lnst/Devices/RemoteDevice.py
index 55912ea..652e193 100644
--- a/lnst/Devices/RemoteDevice.py
+++ b/lnst/Devices/RemoteDevice.py
@@ -90,9 +90,6 @@ def __id_set(self, value):
_id = property(__id_get, __id_set)
- def _get_dev_cls(self):
- return self._dev_cls
-
@property
def host(self):
return self._machine._initns
--
2.23.0
From: Ondrej Lichtner <olichtne(a)redhat.com>
For pretty printing the object in automated logs.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
---
lnst/Common/HWAddress.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lnst/Common/HWAddress.py b/lnst/Common/HWAddress.py
index b35550d..0271285 100644
--- a/lnst/Common/HWAddress.py
+++ b/lnst/Common/HWAddress.py
@@ -53,6 +53,9 @@ def _parse_addr(self, addr):
res.append(val)
return res
+ def __repr__(self):
+ return "{}({})".format(self.__class__.__name__, str(self))
+
def hwaddress(addr):
"""Factory method to create a _HWAddress object"""
if isinstance(addr, HWAddress):
--
2.23.0
From: Ondrej Lichtner <olichtne(a)redhat.com>
Instread of throwing an exception we should simply return a float
infinity value so that it propagates all the way to the user.
Same exception could also be raised by the BaseFlowMeasurement "report"
methods while calculating the percentage of the standard deviation out
of the average value.
A helper method was utilized to calculate the percentage for all of the
measured values.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
---
.../Perf/Measurements/BaseFlowMeasurement.py | 11 +++++++++--
lnst/RecipeCommon/Perf/Results.py | 5 ++++-
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/lnst/RecipeCommon/Perf/Measurements/BaseFlowMeasurement.py
b/lnst/RecipeCommon/Perf/Measurements/BaseFlowMeasurement.py
index 14f0661..9890ed2 100644
--- a/lnst/RecipeCommon/Perf/Measurements/BaseFlowMeasurement.py
+++ b/lnst/RecipeCommon/Perf/Measurements/BaseFlowMeasurement.py
@@ -198,7 +198,7 @@ def _report_flow_results(cls, recipe, flow_results):
desc.append("Generator measured throughput: {tput:.2f}
+-{deviation:.2f}({percentage:.2f}%) {unit} per second."
.format(tput=generator.average,
deviation=generator.std_deviation,
- percentage=(generator.std_deviation/generator.average) * 100,
+ percentage=cls._deviation_percentage(generator),
unit=generator.unit))
desc.append("Generator process CPU data: {cpu:.2f} +-{cpu_deviation:.2f}
{cpu_unit} per second."
.format(cpu=generator_cpu.average,
@@ -207,7 +207,7 @@ def _report_flow_results(cls, recipe, flow_results):
desc.append("Receiver measured throughput: {tput:.2f}
+-{deviation:.2f}({percentage:.2}%) {unit} per second."
.format(tput=receiver.average,
deviation=receiver.std_deviation,
- percentage=(receiver.std_deviation/receiver.average) * 100,
+ percentage=cls._deviation_percentage(receiver),
unit=receiver.unit))
desc.append("Receiver process CPU data: {cpu:.2f} +-{cpu_deviation:.2f}
{cpu_unit} per second."
.format(cpu=receiver_cpu.average,
@@ -238,3 +238,10 @@ def _aggregate_flows(self, old_flow, new_flow):
new_result.add_results(old_flow)
new_result.add_results(new_flow)
return new_result
+
+ @classmethod
+ def _deviation_percentage(cls, result):
+ try:
+ return (result.std_deviation/result.average) * 100
+ except ZeroDivisionError:
+ return float('inf') if result.std_deviation >= 0 else
float("-inf")
diff --git a/lnst/RecipeCommon/Perf/Results.py b/lnst/RecipeCommon/Perf/Results.py
index 1b44cde..4519fb8 100644
--- a/lnst/RecipeCommon/Perf/Results.py
+++ b/lnst/RecipeCommon/Perf/Results.py
@@ -4,7 +4,10 @@
class PerfStatMixin(object):
@property
def average(self):
- return float(self.value) / self.duration
+ try:
+ return float(self.value) / self.duration
+ except ZeroDivisionError:
+ return float('inf') if self.value >= 0 else float('-inf')
@property
def std_deviation(self):
--
2.23.0
Tue, Oct 01, 2019 at 10:47:01AM CEST, olichtne(a)redhat.com wrote:
From: Ondrej Lichtner <olichtne(a)redhat.com>
For now throwing an exception when trying to read/write coalescing
settings to a device that doesn't support them is still the best option.
However, there's a need to easily distinguish and ignore this error in
operations that try to access all properties of a Device class instance,
e.g. enable_readonly_cache. In such cases the tester probably doesn't
care that coalescing isn't supported and has no option to skip it for
the cache generation operation leading to the recipe failing with an
exception.
Handling device capabilities dynamically is a larger feature that might
be hard to implement for now so instead a special
DeviceFeatureNotSupported exception class is added that can be safely
ignored when performing these "bulk"/"iterative" operations.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Ack to series.
Acked-by: Jan Tluka <jtluka(a)redhat.com>
On Tue, Oct 01, 2019 at 12:08:14PM +0200, Jan Tluka wrote:
Tue, Oct 01, 2019 at 10:47:01AM CEST, olichtne(a)redhat.com wrote:
>From: Ondrej Lichtner <olichtne(a)redhat.com>
>
>For now throwing an exception when trying to read/write coalescing
>settings to a device that doesn't support them is still the best option.
>
>However, there's a need to easily distinguish and ignore this error in
>operations that try to access all properties of a Device class instance,
>e.g. enable_readonly_cache. In such cases the tester probably doesn't
>care that coalescing isn't supported and has no option to skip it for
>the cache generation operation leading to the recipe failing with an
>exception.
>
>Handling device capabilities dynamically is a larger feature that might
>be hard to implement for now so instead a special
>DeviceFeatureNotSupported exception class is added that can be safely
>ignored when performing these "bulk"/"iterative" operations.
>
>Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Ack to series.
Acked-by: Jan Tluka <jtluka(a)redhat.com>
pushed, thanks for review.
-Ondrej