diff --git a/lisa/tests/scheduler/load_tracking.py b/lisa/tests/scheduler/load_tracking.py index 09e363dc736bc55c8a7334752f10693a96a00fb3..f5518e4175a7b495c284c211096291d274122dbf 100644 --- a/lisa/tests/scheduler/load_tracking.py +++ b/lisa/tests/scheduler/load_tracking.py @@ -29,7 +29,7 @@ from lisa.tests.base import ( RTATestBundle ) from lisa.target import Target -from lisa.utils import ArtifactPath, ExekallTaggable, groupby, kwargs_forwarded_to, memoized +from lisa.utils import ArtifactPath, ExekallTaggable, groupby, kwargs_forwarded_to, memoized, ignore_exceps from lisa.datautils import df_refit_index, series_dereference, series_mean from lisa.wlgen.rta import PeriodicWload, RTAPhase from lisa.trace import MissingTraceEventError @@ -569,22 +569,10 @@ class InvarianceBase(TestBundleBase, LoadTrackingHelpers, abc.ABC): ) )) - @contextlib.contextmanager - def deprioritize_high_prio_wq(): - try: - target.write_value('/sys/kernel/debug/workqueue/high_prio_wq', '0', verify=True) - except TargetStableError: - undo = False - else: - undo = True - - try: - yield - finally: - if undo: - target.write_value('/sys/kernel/debug/workqueue/high_prio_wq', '1', verify=True) - - with deprioritize_high_prio_wq(): + with ignore_exceps( + (FileNotFoundError, TargetStableError), + target.revertable_write_value('/sys/kernel/debug/workqueue/high_prio_wq', '0') + ): for cpu, (all_freqs, freq_list) in sorted(cpu_freqs.items()): for freq in freq_list: item_dir = ArtifactPath.join(res_dir, f"{InvarianceItemBase.task_prefix}_{cpu}@{freq}") diff --git a/lisa/utils.py b/lisa/utils.py index e9552dafa41414802232ff97076f8805a6f95c8a..e3582f0d8773413c210410ccbda87b15d4e98c48 100644 --- a/lisa/utils.py +++ b/lisa/utils.py @@ -2727,6 +2727,50 @@ def nullcontext(enter_result=None): yield enter_result +@contextlib.contextmanager +def ignore_exceps(exceps, cm, callback=None): + """ + Wrap a context manager and handle exceptions raised in ``__enter__()`` and + ``__exit__()``. + + :param exceps: Tuple of exceptions to catch. + :type exceps: BaseException or tuple(BaseException) + + :type callback: Function called in case of exception. It will be passed + ``"enter"`` or ``"exit"`` to indicate what part failed, then the + context manager then the exception. The return value will be returned + by the wrapped ``__enter__()`` and ``__exit__()``. + :type callback: collections.abc.Callable or None + + .. note:: If the ``__enter__()`` method failed, ``__exit__()`` will not be + called. + """ + + if callback is None: + callback = lambda *args: None + + failed_enter = False + + class Wrapped: + def __enter__(self): + nonlocal failed_enter + try: + return cm.__enter__() + except exceps as e: + failed_enter = True + return callback('enter', cm, e) + + def __exit__(self, *args, **kwargs): + if not failed_enter: + try: + return cm.__exit__(*args, **kwargs) + except exceps as e: + return callback('exit', cm, e) + + with Wrapped() as x: + yield x + + class ExekallTaggable: """ Allows tagging the objects produced in exekall expressions ID.