1840b1e01SJuraj Linkeš# SPDX-License-Identifier: BSD-3-Clause 2840b1e01SJuraj Linkeš# Copyright(c) 2023 PANTHEON.tech s.r.o. 3840b1e01SJuraj Linkeš# Copyright(c) 2023 University of New Hampshire 4840b1e01SJuraj Linkeš 56ef07151SJuraj Linkeš"""POSIX compliant OS translator. 66ef07151SJuraj Linkeš 76ef07151SJuraj LinkešTranslates OS-unaware calls into POSIX compliant calls/utilities. POSIX is a set of standards 86ef07151SJuraj Linkešfor portability between Unix operating systems which not all Linux distributions 96ef07151SJuraj Linkeš(or the tools most frequently bundled with said distributions) adhere to. Most of Linux 106ef07151SJuraj Linkešdistributions are mostly compliant though. 116ef07151SJuraj LinkešThis intermediate module implements the common parts of mostly POSIX compliant distributions. 126ef07151SJuraj Linkeš""" 136ef07151SJuraj Linkeš 14840b1e01SJuraj Linkešimport re 15840b1e01SJuraj Linkešfrom collections.abc import Iterable 16441c5fbfSTomáš Ďurovecfrom pathlib import Path, PurePath, PurePosixPath 17840b1e01SJuraj Linkeš 18c72ff85dSLuca Vizzarrofrom framework.config import Architecture 19840b1e01SJuraj Linkešfrom framework.exception import DPDKBuildError, RemoteCommandExecutionError 20840b1e01SJuraj Linkešfrom framework.settings import SETTINGS 2180158fd4STomáš Ďurovecfrom framework.utils import ( 2280158fd4STomáš Ďurovec MesonArgs, 2380158fd4STomáš Ďurovec TarCompressionFormat, 2480158fd4STomáš Ďurovec convert_to_list_of_string, 2580158fd4STomáš Ďurovec create_tarball, 2680158fd4STomáš Ďurovec extract_tarball, 2780158fd4STomáš Ďurovec) 28840b1e01SJuraj Linkeš 29c72ff85dSLuca Vizzarrofrom .os_session import OSSession, OSSessionInfo 30840b1e01SJuraj Linkeš 31840b1e01SJuraj Linkeš 32840b1e01SJuraj Linkešclass PosixSession(OSSession): 336ef07151SJuraj Linkeš """An intermediary class implementing the POSIX standard.""" 34840b1e01SJuraj Linkeš 35840b1e01SJuraj Linkeš @staticmethod 36840b1e01SJuraj Linkeš def combine_short_options(**opts: bool) -> str: 376ef07151SJuraj Linkeš """Combine shell options into one argument. 386ef07151SJuraj Linkeš 396ef07151SJuraj Linkeš These are options such as ``-x``, ``-v``, ``-f`` which are combined into ``-xvf``. 406ef07151SJuraj Linkeš 416ef07151SJuraj Linkeš Args: 426ef07151SJuraj Linkeš opts: The keys are option names (usually one letter) and the bool values indicate 436ef07151SJuraj Linkeš whether to include the option in the resulting argument. 446ef07151SJuraj Linkeš 456ef07151SJuraj Linkeš Returns: 466ef07151SJuraj Linkeš The options combined into one argument. 476ef07151SJuraj Linkeš """ 48840b1e01SJuraj Linkeš ret_opts = "" 49840b1e01SJuraj Linkeš for opt, include in opts.items(): 50840b1e01SJuraj Linkeš if include: 51840b1e01SJuraj Linkeš ret_opts = f"{ret_opts}{opt}" 52840b1e01SJuraj Linkeš 53840b1e01SJuraj Linkeš if ret_opts: 54840b1e01SJuraj Linkeš ret_opts = f" -{ret_opts}" 55840b1e01SJuraj Linkeš 56840b1e01SJuraj Linkeš return ret_opts 57840b1e01SJuraj Linkeš 58840b1e01SJuraj Linkeš def guess_dpdk_remote_dir(self, remote_dir: str | PurePath) -> PurePosixPath: 596ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.guess_dpdk_remote_dir`.""" 60840b1e01SJuraj Linkeš remote_guess = self.join_remote_path(remote_dir, "dpdk-*") 61840b1e01SJuraj Linkeš result = self.send_command(f"ls -d {remote_guess} | tail -1") 62840b1e01SJuraj Linkeš return PurePosixPath(result.stdout) 63840b1e01SJuraj Linkeš 64840b1e01SJuraj Linkeš def get_remote_tmp_dir(self) -> PurePosixPath: 656ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.get_remote_tmp_dir`.""" 66840b1e01SJuraj Linkeš return PurePosixPath("/tmp") 67840b1e01SJuraj Linkeš 68840b1e01SJuraj Linkeš def get_dpdk_build_env_vars(self, arch: Architecture) -> dict: 696ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.get_dpdk_build_env_vars`. 706ef07151SJuraj Linkeš 716ef07151SJuraj Linkeš Supported architecture: ``i686``. 72840b1e01SJuraj Linkeš """ 73840b1e01SJuraj Linkeš env_vars = {} 74840b1e01SJuraj Linkeš if arch == Architecture.i686: 75840b1e01SJuraj Linkeš # find the pkg-config path and store it in PKG_CONFIG_LIBDIR 76840b1e01SJuraj Linkeš out = self.send_command("find /usr -type d -name pkgconfig") 77840b1e01SJuraj Linkeš pkg_path = "" 78840b1e01SJuraj Linkeš res_path = out.stdout.split("\r\n") 79840b1e01SJuraj Linkeš for cur_path in res_path: 80840b1e01SJuraj Linkeš if "i386" in cur_path: 81840b1e01SJuraj Linkeš pkg_path = cur_path 82840b1e01SJuraj Linkeš break 83840b1e01SJuraj Linkeš assert pkg_path != "", "i386 pkg-config path not found" 84840b1e01SJuraj Linkeš 85840b1e01SJuraj Linkeš env_vars["CFLAGS"] = "-m32" 86840b1e01SJuraj Linkeš env_vars["PKG_CONFIG_LIBDIR"] = pkg_path 87840b1e01SJuraj Linkeš 88840b1e01SJuraj Linkeš return env_vars 89840b1e01SJuraj Linkeš 90840b1e01SJuraj Linkeš def join_remote_path(self, *args: str | PurePath) -> PurePosixPath: 916ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.join_remote_path`.""" 92840b1e01SJuraj Linkeš return PurePosixPath(*args) 93840b1e01SJuraj Linkeš 94f9957667STomáš Ďurovec def remote_path_exists(self, remote_path: str | PurePath) -> bool: 95f9957667STomáš Ďurovec """Overrides :meth:`~.os_session.OSSession.remote_path_exists`.""" 96f9957667STomáš Ďurovec result = self.send_command(f"test -e {remote_path}") 97f9957667STomáš Ďurovec return not result.return_code 98f9957667STomáš Ďurovec 99441c5fbfSTomáš Ďurovec def copy_from(self, source_file: str | PurePath, destination_dir: str | Path) -> None: 1006ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.copy_from`.""" 101441c5fbfSTomáš Ďurovec self.remote_session.copy_from(source_file, destination_dir) 102840b1e01SJuraj Linkeš 103441c5fbfSTomáš Ďurovec def copy_to(self, source_file: str | Path, destination_dir: str | PurePath) -> None: 1046ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.copy_to`.""" 105441c5fbfSTomáš Ďurovec self.remote_session.copy_to(source_file, destination_dir) 106840b1e01SJuraj Linkeš 10780158fd4STomáš Ďurovec def copy_dir_from( 10880158fd4STomáš Ďurovec self, 10980158fd4STomáš Ďurovec source_dir: str | PurePath, 11080158fd4STomáš Ďurovec destination_dir: str | Path, 11180158fd4STomáš Ďurovec compress_format: TarCompressionFormat = TarCompressionFormat.none, 11280158fd4STomáš Ďurovec exclude: str | list[str] | None = None, 11380158fd4STomáš Ďurovec ) -> None: 11480158fd4STomáš Ďurovec """Overrides :meth:`~.os_session.OSSession.copy_dir_from`.""" 11580158fd4STomáš Ďurovec source_dir = PurePath(source_dir) 11680158fd4STomáš Ďurovec remote_tarball_path = self.create_remote_tarball(source_dir, compress_format, exclude) 11780158fd4STomáš Ďurovec 11880158fd4STomáš Ďurovec self.copy_from(remote_tarball_path, destination_dir) 11980158fd4STomáš Ďurovec self.remove_remote_file(remote_tarball_path) 12080158fd4STomáš Ďurovec 12180158fd4STomáš Ďurovec tarball_path = Path(destination_dir, f"{source_dir.name}.{compress_format.extension}") 12280158fd4STomáš Ďurovec extract_tarball(tarball_path) 12380158fd4STomáš Ďurovec tarball_path.unlink() 12480158fd4STomáš Ďurovec 12580158fd4STomáš Ďurovec def copy_dir_to( 12680158fd4STomáš Ďurovec self, 12780158fd4STomáš Ďurovec source_dir: str | Path, 12880158fd4STomáš Ďurovec destination_dir: str | PurePath, 12980158fd4STomáš Ďurovec compress_format: TarCompressionFormat = TarCompressionFormat.none, 13080158fd4STomáš Ďurovec exclude: str | list[str] | None = None, 13180158fd4STomáš Ďurovec ) -> None: 13280158fd4STomáš Ďurovec """Overrides :meth:`~.os_session.OSSession.copy_dir_to`.""" 13380158fd4STomáš Ďurovec source_dir = Path(source_dir) 13480158fd4STomáš Ďurovec tarball_path = create_tarball(source_dir, compress_format, exclude=exclude) 13580158fd4STomáš Ďurovec self.copy_to(tarball_path, destination_dir) 13680158fd4STomáš Ďurovec tarball_path.unlink() 13780158fd4STomáš Ďurovec 13880158fd4STomáš Ďurovec remote_tar_path = self.join_remote_path( 13980158fd4STomáš Ďurovec destination_dir, f"{source_dir.name}.{compress_format.extension}" 14080158fd4STomáš Ďurovec ) 14180158fd4STomáš Ďurovec self.extract_remote_tarball(remote_tar_path) 14280158fd4STomáš Ďurovec self.remove_remote_file(remote_tar_path) 14380158fd4STomáš Ďurovec 14480158fd4STomáš Ďurovec def remove_remote_file(self, remote_file_path: str | PurePath, force: bool = True) -> None: 14580158fd4STomáš Ďurovec """Overrides :meth:`~.os_session.OSSession.remove_remote_dir`.""" 14680158fd4STomáš Ďurovec opts = PosixSession.combine_short_options(f=force) 14780158fd4STomáš Ďurovec self.send_command(f"rm{opts} {remote_file_path}") 14880158fd4STomáš Ďurovec 149840b1e01SJuraj Linkeš def remove_remote_dir( 150840b1e01SJuraj Linkeš self, 151840b1e01SJuraj Linkeš remote_dir_path: str | PurePath, 152840b1e01SJuraj Linkeš recursive: bool = True, 153840b1e01SJuraj Linkeš force: bool = True, 154840b1e01SJuraj Linkeš ) -> None: 1556ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.remove_remote_dir`.""" 156840b1e01SJuraj Linkeš opts = PosixSession.combine_short_options(r=recursive, f=force) 157840b1e01SJuraj Linkeš self.send_command(f"rm{opts} {remote_dir_path}") 158840b1e01SJuraj Linkeš 15980158fd4STomáš Ďurovec def create_remote_tarball( 160840b1e01SJuraj Linkeš self, 16180158fd4STomáš Ďurovec remote_dir_path: str | PurePath, 16280158fd4STomáš Ďurovec compress_format: TarCompressionFormat = TarCompressionFormat.none, 16380158fd4STomáš Ďurovec exclude: str | list[str] | None = None, 16480158fd4STomáš Ďurovec ) -> PurePosixPath: 16580158fd4STomáš Ďurovec """Overrides :meth:`~.os_session.OSSession.create_remote_tarball`.""" 16680158fd4STomáš Ďurovec 16780158fd4STomáš Ďurovec def generate_tar_exclude_args(exclude_patterns) -> str: 16880158fd4STomáš Ďurovec """Generate args to exclude patterns when creating a tarball. 16980158fd4STomáš Ďurovec 17080158fd4STomáš Ďurovec Args: 17180158fd4STomáš Ďurovec exclude_patterns: Patterns for files or directories to exclude from the tarball. 17280158fd4STomáš Ďurovec These patterns are used with `tar`'s `--exclude` option. 17380158fd4STomáš Ďurovec 17480158fd4STomáš Ďurovec Returns: 17580158fd4STomáš Ďurovec The generated string args to exclude the specified patterns. 17680158fd4STomáš Ďurovec """ 17780158fd4STomáš Ďurovec if exclude_patterns: 17880158fd4STomáš Ďurovec exclude_patterns = convert_to_list_of_string(exclude_patterns) 17980158fd4STomáš Ďurovec return "".join([f" --exclude={pattern}" for pattern in exclude_patterns]) 18080158fd4STomáš Ďurovec return "" 18180158fd4STomáš Ďurovec 18280158fd4STomáš Ďurovec posix_remote_dir_path = PurePosixPath(remote_dir_path) 18380158fd4STomáš Ďurovec target_tarball_path = PurePosixPath(f"{remote_dir_path}.{compress_format.extension}") 18480158fd4STomáš Ďurovec 18580158fd4STomáš Ďurovec self.send_command( 18680158fd4STomáš Ďurovec f"tar caf {target_tarball_path}{generate_tar_exclude_args(exclude)} " 18780158fd4STomáš Ďurovec f"-C {posix_remote_dir_path.parent} {posix_remote_dir_path.name}", 18880158fd4STomáš Ďurovec 60, 18980158fd4STomáš Ďurovec ) 19080158fd4STomáš Ďurovec 19180158fd4STomáš Ďurovec return target_tarball_path 19280158fd4STomáš Ďurovec 19380158fd4STomáš Ďurovec def extract_remote_tarball( 19480158fd4STomáš Ďurovec self, remote_tarball_path: str | PurePath, expected_dir: str | PurePath | None = None 195840b1e01SJuraj Linkeš ) -> None: 1966ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.extract_remote_tarball`.""" 197840b1e01SJuraj Linkeš self.send_command( 198840b1e01SJuraj Linkeš f"tar xfm {remote_tarball_path} -C {PurePosixPath(remote_tarball_path).parent}", 199840b1e01SJuraj Linkeš 60, 200840b1e01SJuraj Linkeš ) 201840b1e01SJuraj Linkeš if expected_dir: 202840b1e01SJuraj Linkeš self.send_command(f"ls {expected_dir}", verify=True) 203840b1e01SJuraj Linkeš 204*b935bdc3SLuca Vizzarro def is_remote_dir(self, remote_path: PurePath) -> bool: 205f9957667STomáš Ďurovec """Overrides :meth:`~.os_session.OSSession.is_remote_dir`.""" 206f9957667STomáš Ďurovec result = self.send_command(f"test -d {remote_path}") 207f9957667STomáš Ďurovec return not result.return_code 208f9957667STomáš Ďurovec 209*b935bdc3SLuca Vizzarro def is_remote_tarfile(self, remote_tarball_path: PurePath) -> bool: 210f9957667STomáš Ďurovec """Overrides :meth:`~.os_session.OSSession.is_remote_tarfile`.""" 211f9957667STomáš Ďurovec result = self.send_command(f"tar -tvf {remote_tarball_path}") 212f9957667STomáš Ďurovec return not result.return_code 213f9957667STomáš Ďurovec 214f9957667STomáš Ďurovec def get_tarball_top_dir( 215f9957667STomáš Ďurovec self, remote_tarball_path: str | PurePath 216f9957667STomáš Ďurovec ) -> str | PurePosixPath | None: 217f9957667STomáš Ďurovec """Overrides :meth:`~.os_session.OSSession.get_tarball_top_dir`.""" 218f9957667STomáš Ďurovec members = self.send_command(f"tar tf {remote_tarball_path}").stdout.split() 219f9957667STomáš Ďurovec 220f9957667STomáš Ďurovec top_dirs = [] 221f9957667STomáš Ďurovec for member in members: 222f9957667STomáš Ďurovec parts_of_member = PurePosixPath(member).parts 223f9957667STomáš Ďurovec if parts_of_member: 224f9957667STomáš Ďurovec top_dirs.append(parts_of_member[0]) 225f9957667STomáš Ďurovec 226f9957667STomáš Ďurovec if len(set(top_dirs)) == 1: 227f9957667STomáš Ďurovec return top_dirs[0] 228f9957667STomáš Ďurovec return None 229f9957667STomáš Ďurovec 230840b1e01SJuraj Linkeš def build_dpdk( 231840b1e01SJuraj Linkeš self, 232840b1e01SJuraj Linkeš env_vars: dict, 233840b1e01SJuraj Linkeš meson_args: MesonArgs, 234840b1e01SJuraj Linkeš remote_dpdk_dir: str | PurePath, 235840b1e01SJuraj Linkeš remote_dpdk_build_dir: str | PurePath, 236840b1e01SJuraj Linkeš rebuild: bool = False, 237840b1e01SJuraj Linkeš timeout: float = SETTINGS.compile_timeout, 238840b1e01SJuraj Linkeš ) -> None: 2396ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.build_dpdk`.""" 240840b1e01SJuraj Linkeš try: 241840b1e01SJuraj Linkeš if rebuild: 242840b1e01SJuraj Linkeš # reconfigure, then build 243840b1e01SJuraj Linkeš self._logger.info("Reconfiguring DPDK build.") 244840b1e01SJuraj Linkeš self.send_command( 245840b1e01SJuraj Linkeš f"meson configure {meson_args} {remote_dpdk_build_dir}", 246840b1e01SJuraj Linkeš timeout, 247840b1e01SJuraj Linkeš verify=True, 248840b1e01SJuraj Linkeš env=env_vars, 249840b1e01SJuraj Linkeš ) 250840b1e01SJuraj Linkeš else: 251840b1e01SJuraj Linkeš # fresh build - remove target dir first, then build from scratch 252840b1e01SJuraj Linkeš self._logger.info("Configuring DPDK build from scratch.") 253840b1e01SJuraj Linkeš self.remove_remote_dir(remote_dpdk_build_dir) 254840b1e01SJuraj Linkeš self.send_command( 255840b1e01SJuraj Linkeš f"meson setup {meson_args} {remote_dpdk_dir} {remote_dpdk_build_dir}", 256840b1e01SJuraj Linkeš timeout, 257840b1e01SJuraj Linkeš verify=True, 258840b1e01SJuraj Linkeš env=env_vars, 259840b1e01SJuraj Linkeš ) 260840b1e01SJuraj Linkeš 261840b1e01SJuraj Linkeš self._logger.info("Building DPDK.") 262840b1e01SJuraj Linkeš self.send_command( 263840b1e01SJuraj Linkeš f"ninja -C {remote_dpdk_build_dir}", timeout, verify=True, env=env_vars 264840b1e01SJuraj Linkeš ) 265840b1e01SJuraj Linkeš except RemoteCommandExecutionError as e: 266840b1e01SJuraj Linkeš raise DPDKBuildError(f"DPDK build failed when doing '{e.command}'.") 267840b1e01SJuraj Linkeš 268840b1e01SJuraj Linkeš def get_dpdk_version(self, build_dir: str | PurePath) -> str: 2696ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.get_dpdk_version`.""" 270840b1e01SJuraj Linkeš out = self.send_command(f"cat {self.join_remote_path(build_dir, 'VERSION')}", verify=True) 271840b1e01SJuraj Linkeš return out.stdout 272840b1e01SJuraj Linkeš 273840b1e01SJuraj Linkeš def kill_cleanup_dpdk_apps(self, dpdk_prefix_list: Iterable[str]) -> None: 2746ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.kill_cleanup_dpdk_apps`.""" 275840b1e01SJuraj Linkeš self._logger.info("Cleaning up DPDK apps.") 276840b1e01SJuraj Linkeš dpdk_runtime_dirs = self._get_dpdk_runtime_dirs(dpdk_prefix_list) 277840b1e01SJuraj Linkeš if dpdk_runtime_dirs: 278840b1e01SJuraj Linkeš # kill and cleanup only if DPDK is running 279840b1e01SJuraj Linkeš dpdk_pids = self._get_dpdk_pids(dpdk_runtime_dirs) 280840b1e01SJuraj Linkeš for dpdk_pid in dpdk_pids: 281840b1e01SJuraj Linkeš self.send_command(f"kill -9 {dpdk_pid}", 20) 282840b1e01SJuraj Linkeš self._check_dpdk_hugepages(dpdk_runtime_dirs) 283840b1e01SJuraj Linkeš self._remove_dpdk_runtime_dirs(dpdk_runtime_dirs) 284840b1e01SJuraj Linkeš 285840b1e01SJuraj Linkeš def _get_dpdk_runtime_dirs(self, dpdk_prefix_list: Iterable[str]) -> list[PurePosixPath]: 2866ef07151SJuraj Linkeš """Find runtime directories DPDK apps are currently using. 2876ef07151SJuraj Linkeš 2886ef07151SJuraj Linkeš Args: 2896ef07151SJuraj Linkeš dpdk_prefix_list: The prefixes DPDK apps were started with. 2906ef07151SJuraj Linkeš 2916ef07151SJuraj Linkeš Returns: 2926ef07151SJuraj Linkeš The paths of DPDK apps' runtime dirs. 2936ef07151SJuraj Linkeš """ 294840b1e01SJuraj Linkeš prefix = PurePosixPath("/var", "run", "dpdk") 295840b1e01SJuraj Linkeš if not dpdk_prefix_list: 296840b1e01SJuraj Linkeš remote_prefixes = self._list_remote_dirs(prefix) 297840b1e01SJuraj Linkeš if not remote_prefixes: 298840b1e01SJuraj Linkeš dpdk_prefix_list = [] 299840b1e01SJuraj Linkeš else: 300840b1e01SJuraj Linkeš dpdk_prefix_list = remote_prefixes 301840b1e01SJuraj Linkeš 302840b1e01SJuraj Linkeš return [PurePosixPath(prefix, dpdk_prefix) for dpdk_prefix in dpdk_prefix_list] 303840b1e01SJuraj Linkeš 304840b1e01SJuraj Linkeš def _list_remote_dirs(self, remote_path: str | PurePath) -> list[str] | None: 3056ef07151SJuraj Linkeš """Contents of remote_path. 3066ef07151SJuraj Linkeš 3076ef07151SJuraj Linkeš Args: 3086ef07151SJuraj Linkeš remote_path: List the contents of this path. 3096ef07151SJuraj Linkeš 3106ef07151SJuraj Linkeš Returns: 3116ef07151SJuraj Linkeš The contents of remote_path. If remote_path doesn't exist, return None. 312840b1e01SJuraj Linkeš """ 313840b1e01SJuraj Linkeš out = self.send_command(f"ls -l {remote_path} | awk '/^d/ {{print $NF}}'").stdout 314840b1e01SJuraj Linkeš if "No such file or directory" in out: 315840b1e01SJuraj Linkeš return None 316840b1e01SJuraj Linkeš else: 317840b1e01SJuraj Linkeš return out.splitlines() 318840b1e01SJuraj Linkeš 319840b1e01SJuraj Linkeš def _get_dpdk_pids(self, dpdk_runtime_dirs: Iterable[str | PurePath]) -> list[int]: 3206ef07151SJuraj Linkeš """Find PIDs of running DPDK apps. 3216ef07151SJuraj Linkeš 3226ef07151SJuraj Linkeš Look at each "config" file found in dpdk_runtime_dirs and find the PIDs of processes 3236ef07151SJuraj Linkeš that opened those file. 3246ef07151SJuraj Linkeš 3256ef07151SJuraj Linkeš Args: 3266ef07151SJuraj Linkeš dpdk_runtime_dirs: The paths of DPDK apps' runtime dirs. 3276ef07151SJuraj Linkeš 3286ef07151SJuraj Linkeš Returns: 3296ef07151SJuraj Linkeš The PIDs of running DPDK apps. 3306ef07151SJuraj Linkeš """ 331840b1e01SJuraj Linkeš pids = [] 332840b1e01SJuraj Linkeš pid_regex = r"p(\d+)" 333840b1e01SJuraj Linkeš for dpdk_runtime_dir in dpdk_runtime_dirs: 334840b1e01SJuraj Linkeš dpdk_config_file = PurePosixPath(dpdk_runtime_dir, "config") 335f9957667STomáš Ďurovec if self.remote_path_exists(dpdk_config_file): 336840b1e01SJuraj Linkeš out = self.send_command(f"lsof -Fp {dpdk_config_file}").stdout 337840b1e01SJuraj Linkeš if out and "No such file or directory" not in out: 338840b1e01SJuraj Linkeš for out_line in out.splitlines(): 339840b1e01SJuraj Linkeš match = re.match(pid_regex, out_line) 340840b1e01SJuraj Linkeš if match: 341840b1e01SJuraj Linkeš pids.append(int(match.group(1))) 342840b1e01SJuraj Linkeš return pids 343840b1e01SJuraj Linkeš 344840b1e01SJuraj Linkeš def _check_dpdk_hugepages(self, dpdk_runtime_dirs: Iterable[str | PurePath]) -> None: 3456ef07151SJuraj Linkeš """Check there aren't any leftover hugepages. 3466ef07151SJuraj Linkeš 3476ef07151SJuraj Linkeš If any hugepages are found, emit a warning. The hugepages are investigated in the 3486ef07151SJuraj Linkeš "hugepage_info" file of dpdk_runtime_dirs. 3496ef07151SJuraj Linkeš 3506ef07151SJuraj Linkeš Args: 3516ef07151SJuraj Linkeš dpdk_runtime_dirs: The paths of DPDK apps' runtime dirs. 3526ef07151SJuraj Linkeš """ 353840b1e01SJuraj Linkeš for dpdk_runtime_dir in dpdk_runtime_dirs: 354840b1e01SJuraj Linkeš hugepage_info = PurePosixPath(dpdk_runtime_dir, "hugepage_info") 355f9957667STomáš Ďurovec if self.remote_path_exists(hugepage_info): 356840b1e01SJuraj Linkeš out = self.send_command(f"lsof -Fp {hugepage_info}").stdout 357840b1e01SJuraj Linkeš if out and "No such file or directory" not in out: 358840b1e01SJuraj Linkeš self._logger.warning("Some DPDK processes did not free hugepages.") 359840b1e01SJuraj Linkeš self._logger.warning("*******************************************") 360840b1e01SJuraj Linkeš self._logger.warning(out) 361840b1e01SJuraj Linkeš self._logger.warning("*******************************************") 362840b1e01SJuraj Linkeš 363840b1e01SJuraj Linkeš def _remove_dpdk_runtime_dirs(self, dpdk_runtime_dirs: Iterable[str | PurePath]) -> None: 364840b1e01SJuraj Linkeš for dpdk_runtime_dir in dpdk_runtime_dirs: 365840b1e01SJuraj Linkeš self.remove_remote_dir(dpdk_runtime_dir) 366840b1e01SJuraj Linkeš 367840b1e01SJuraj Linkeš def get_dpdk_file_prefix(self, dpdk_prefix: str) -> str: 3686ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.get_dpdk_file_prefix`.""" 369840b1e01SJuraj Linkeš return "" 370840b1e01SJuraj Linkeš 371840b1e01SJuraj Linkeš def get_compiler_version(self, compiler_name: str) -> str: 3726ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.get_compiler_version`.""" 373840b1e01SJuraj Linkeš match compiler_name: 374840b1e01SJuraj Linkeš case "gcc": 375840b1e01SJuraj Linkeš return self.send_command( 376840b1e01SJuraj Linkeš f"{compiler_name} --version", SETTINGS.timeout 377840b1e01SJuraj Linkeš ).stdout.split("\n")[0] 378840b1e01SJuraj Linkeš case "clang": 379840b1e01SJuraj Linkeš return self.send_command( 380840b1e01SJuraj Linkeš f"{compiler_name} --version", SETTINGS.timeout 381840b1e01SJuraj Linkeš ).stdout.split("\n")[0] 382840b1e01SJuraj Linkeš case "msvc": 383840b1e01SJuraj Linkeš return self.send_command("cl", SETTINGS.timeout).stdout 384840b1e01SJuraj Linkeš case "icc": 385840b1e01SJuraj Linkeš return self.send_command(f"{compiler_name} -V", SETTINGS.timeout).stdout 386840b1e01SJuraj Linkeš case _: 387840b1e01SJuraj Linkeš raise ValueError(f"Unknown compiler {compiler_name}") 388840b1e01SJuraj Linkeš 389c72ff85dSLuca Vizzarro def get_node_info(self) -> OSSessionInfo: 3906ef07151SJuraj Linkeš """Overrides :meth:`~.os_session.OSSession.get_node_info`.""" 391840b1e01SJuraj Linkeš os_release_info = self.send_command( 392840b1e01SJuraj Linkeš "awk -F= '$1 ~ /^NAME$|^VERSION$/ {print $2}' /etc/os-release", 393840b1e01SJuraj Linkeš SETTINGS.timeout, 394840b1e01SJuraj Linkeš ).stdout.split("\n") 395840b1e01SJuraj Linkeš kernel_version = self.send_command("uname -r", SETTINGS.timeout).stdout 396c72ff85dSLuca Vizzarro return OSSessionInfo(os_release_info[0].strip(), os_release_info[1].strip(), kernel_version) 397