From e40c7c77173926c3370de62628e3e84e8c2c64f8 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Sun, 7 Jul 2024 11:31:24 +0200 Subject: [PATCH] twister: DeviceHandler improve DUT selection Improve DUT selection at DeviceHandler: for each DUT it counts how many test instances have been failed on it during the current twister execution, so the next available DUT will be chosen ordering the eligible DUTs by less failures occured so far. The new selection mechanism should increase chances to retry failed tests on different DUTs, for instance to resolve ploblems when some DUTs have connectivity or HW issues slowing down test plan execution, or even block the execution when only one test suite runs whereas the same first DUT candidate in the list is not working and others were not chosen. Signed-off-by: Dmitrii Golovanov --- scripts/pylib/twister/twisterlib/handlers.py | 13 ++-- scripts/tests/twister/test_handlers.py | 72 +++++++++++++++++++- 2 files changed, 79 insertions(+), 6 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/handlers.py b/scripts/pylib/twister/twisterlib/handlers.py index aeb252f872060f..9ec0eade2153ca 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -460,14 +460,20 @@ def monitor_serial(self, ser, halt_event, harness): def device_is_available(self, instance): device = instance.platform.name fixture = instance.testsuite.harness_config.get("fixture") - dut_found = False + duts_found = [] for d in self.duts: if fixture and fixture not in map(lambda f: f.split(sep=':')[0], d.fixtures): continue if d.platform != device or (d.serial is None and d.serial_pty is None): continue - dut_found = True + duts_found.append(d) + + if not duts_found: + raise TwisterException(f"No device to serve as {device} platform.") + + # Select an available DUT with less failures + for d in sorted(duts_found, key=lambda _dut: _dut.failures): d.lock.acquire() avail = False if d.available: @@ -480,9 +486,6 @@ def device_is_available(self, instance): if avail: return d - if not dut_found: - raise TwisterException(f"No device to serve as {device} platform.") - return None def make_dut_available(self, dut): diff --git a/scripts/tests/twister/test_handlers.py b/scripts/tests/twister/test_handlers.py index ec4db7859c5804..b857ae3cc20a48 100644 --- a/scripts/tests/twister/test_handlers.py +++ b/scripts/tests/twister/test_handlers.py @@ -738,6 +738,7 @@ def test_devicehandler_monitor_serial( fixtures=[], platform='dummy_platform', available=1, + failures=0, counter_increment=mock.Mock(), counter=0 ), @@ -745,6 +746,7 @@ def test_devicehandler_monitor_serial( fixtures=['dummy fixture'], platform='another_platform', available=1, + failures=0, counter_increment=mock.Mock(), counter=0 ), @@ -754,6 +756,7 @@ def test_devicehandler_monitor_serial( serial_pty=None, serial=None, available=1, + failures=0, counter_increment=mock.Mock(), counter=0 ), @@ -762,12 +765,73 @@ def test_devicehandler_monitor_serial( platform='dummy_platform', serial_pty=mock.Mock(), available=1, + failures=0, + counter_increment=mock.Mock(), + counter=0 + ), + mock.Mock( + fixtures=['dummy fixture'], + platform='dummy_platform', + serial_pty=mock.Mock(), + available=1, + failures=0, counter_increment=mock.Mock(), counter=0 ) ], 3 ), + ( + 'dummy_platform', + 'dummy fixture', + [ + mock.Mock( + fixtures=[], + platform='dummy_platform', + available=1, + failures=0, + counter_increment=mock.Mock(), + counter=0 + ), + mock.Mock( + fixtures=['dummy fixture'], + platform='another_platform', + available=1, + failures=0, + counter_increment=mock.Mock(), + counter=0 + ), + mock.Mock( + fixtures=['dummy fixture'], + platform='dummy_platform', + serial_pty=None, + serial=None, + available=1, + failures=0, + counter_increment=mock.Mock(), + counter=0 + ), + mock.Mock( + fixtures=['dummy fixture'], + platform='dummy_platform', + serial_pty=mock.Mock(), + available=1, + failures=1, + counter_increment=mock.Mock(), + counter=0 + ), + mock.Mock( + fixtures=['dummy fixture'], + platform='dummy_platform', + serial_pty=mock.Mock(), + available=1, + failures=0, + counter_increment=mock.Mock(), + counter=0 + ) + ], + 4 + ), ( 'dummy_platform', 'dummy fixture', @@ -783,6 +847,7 @@ def test_devicehandler_monitor_serial( platform='dummy_platform', serial_pty=mock.Mock(), counter_increment=mock.Mock(), + failures=0, available=0 ), mock.Mock( @@ -790,6 +855,7 @@ def test_devicehandler_monitor_serial( platform='dummy_platform', serial_pty=mock.Mock(), counter_increment=mock.Mock(), + failures=0, available=0 ), mock.Mock( @@ -797,6 +863,7 @@ def test_devicehandler_monitor_serial( platform='dummy_platform', serial=mock.Mock(), counter_increment=mock.Mock(), + failures=0, available=0 ), mock.Mock( @@ -804,6 +871,7 @@ def test_devicehandler_monitor_serial( platform='dummy_platform', serial=mock.Mock(), counter_increment=mock.Mock(), + failures=0, available=0 ) ], @@ -814,7 +882,9 @@ def test_devicehandler_monitor_serial( @pytest.mark.parametrize( 'platform_name, fixture, duts, expected', TESTDATA_10, - ids=['one good dut', 'exception - no duts', 'no available duts'] + ids=['two good duts, select the first one', + 'two duts, the first was failed once, select the second not failed', + 'exception - no duts', 'no available duts'] ) def test_devicehandler_device_is_available( mocked_instance,