diff --git a/lisa/_assets/__init__.py b/lisa/_assets/__init__.py index a66bdbb6f6f40a51e0ad5f197b3fe44ecd03d429..69deff6da3447d201dc1cc4efead1cb39380ff6c 100644 --- a/lisa/_assets/__init__.py +++ b/lisa/_assets/__init__.py @@ -18,6 +18,8 @@ import os import stat import platform +import shutil +from pathlib import Path def _get_abi(): machine = platform.machine() @@ -58,14 +60,49 @@ del _get_abi_bin HOST_BINARIES = ABI_BINARIES[HOST_ABI] -HOST_PATH = ':'.join(( - os.path.join(ASSETS_PATH, 'binaries', HOST_ABI), - os.path.join(ASSETS_PATH, 'scripts'), - os.environ['PATH'] -)) +def _make_path(abi=None): + abi = abi or HOST_ABI + + compos = [ + os.path.join(ASSETS_PATH, 'binaries', abi), + os.path.join(ASSETS_PATH, 'scripts'), + ] + + if abi == HOST_ABI: + path = os.environ['PATH'] + use_system = bool(int(os.environ.get('LISA_USE_SYSTEM_BIN', 0))) + if use_system: + compos = [path] + compos + else: + compos = compos + [path] + + return ':'.join(compos) + +HOST_PATH = _make_path(HOST_ABI) """ Value to be used as the ``PATH`` env var on the host. """ +def get_bin(name, abi=None): + """ + Return the path to a tool bundled in LISA. + + :param abi: ABI of the binary. If ``abi`` is not the host ABI, + ``LISA_USE_SYSTEM_BIN`` is ignored. + :type abi: str or None + + The result is influenced by the ``LISA_USE_SYSTEM_BIN`` environment + variable: + + * If it is set to ``0`` or unset, it will give priority to the binaries + bundled inside the :mod:`lisa` package. + * If it is set to ``1``, it will use the bundled binaries as a fallback + only. + """ + path = shutil.which(name, path=_make_path(abi)) + if path: + return Path(path).resolve() + else: + raise FileNotFoundError(f'Could not locate the tool: {name}') # vim :set tabstop=4 shiftwidth=4 textwidth=80 expandtab diff --git a/lisa/trace.py b/lisa/trace.py index 64b27e5b39964e6460c1a72e4f1b8053a62c9eed..e27c9333e295e3b782980a34b42cfe01a0b638b9 100644 --- a/lisa/trace.py +++ b/lisa/trace.py @@ -60,6 +60,7 @@ from lisa.datautils import SignalDesc, df_add_delta, df_deduplicate, df_window, from lisa.version import VERSION_TOKEN from lisa._typeclass import FromString, IntListFromStringInstance from lisa._kmod import LISAFtraceDynamicKmod +from lisa._assets import get_bin class TaskID(namedtuple('TaskID', ('pid', 'comm'))): @@ -1567,6 +1568,8 @@ class TxtTraceParser(TxtTraceParserBase): be reused in another context (cached on disk), and the set of events in a :class:`Trace` object can be expanded dynamically. """ + bin_ = get_bin('trace-cmd') + if not os.path.exists(path): raise FileNotFoundError(f'Unable to locate specified trace file: {path}') @@ -1595,7 +1598,7 @@ class TxtTraceParser(TxtTraceParserBase): kernel_events = { event.split(':', 1)[1] for event in subprocess.check_output( - ['trace-cmd', 'report', '-N', '-E', '--', path], + [bin_, 'report', '-N', '-E', '--', path], stderr=subprocess.DEVNULL, universal_newlines=True, ).splitlines() @@ -1615,7 +1618,7 @@ class TxtTraceParser(TxtTraceParserBase): symbols_address = dict( parse(line) for line in subprocess.check_output( - ['trace-cmd', 'report', '-N', '-f', '--', path], + [bin_, 'report', '-N', '-f', '--', path], stderr=subprocess.DEVNULL, universal_newlines=True, ).splitlines() @@ -1629,7 +1632,7 @@ class TxtTraceParser(TxtTraceParserBase): if 'cpus-count' in needed_metadata: regex = re.compile(rb'cpus=(?P\d+)') with subprocess.Popen( - ['trace-cmd', 'report', '-N', '--', path], + [bin_, 'report', '-N', '--', path], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, ) as p: @@ -1648,7 +1651,7 @@ class TxtTraceParser(TxtTraceParserBase): pre_filled_metadata=pre_filled_metadata, ) cmd = [ - 'trace-cmd', + bin_, 'report', # Do not load any plugin, so that we get fully reproducible results '-N',