From e6fdb3be9be7284019780f723ede64b916251e61 Mon Sep 17 00:00:00 2001 From: Xavier Karma Date: Fri, 6 Nov 2026 18:25:17 +0530 Subject: [PATCH] fix(perf): hand host binaries the host environment in the baseline script nvidia-smi (vram_mib) and wtype (inject probe) ran without env=host_env(), so under an AppImage bundle they inherit the bundle's library paths. The AST guard now covers the measurement script as well as src/vocalinux, and the script gains the module logger the Style rules require. --- scripts/measure_perf_baseline.py | 13 ++++++++++++- tests/test_host_process.py | 6 +++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/scripts/measure_perf_baseline.py b/scripts/measure_perf_baseline.py index dfb4be2..2fb326a 100644 --- a/scripts/measure_perf_baseline.py +++ b/scripts/measure_perf_baseline.py @@ -12,6 +12,7 @@ from __future__ import annotations import argparse import json +import logging import math import os import platform @@ -23,6 +24,8 @@ import time from pathlib import Path from typing import Any, Optional +logger = logging.getLogger(__name__) + PROTOCOL_VERSION = "1.0.0" _VMRSS_RE = re.compile(r"^VmRSS:\s+(\d+)\s+kB", re.MULTILINE) @@ -117,6 +120,9 @@ def parse_nvidia_smi_memory(csv_text: str) -> Optional[tuple[int, int]]: def vram_mib() -> Optional[tuple[int, int]]: """Return ``(total_mib, free_mib)`` of the first NVIDIA GPU, if any.""" + # Lazy: the parse-only subcommands must run without the package installed. + from vocalinux.utils.host_process import host_env + try: proc = subprocess.run( [ @@ -127,8 +133,10 @@ def vram_mib() -> Optional[tuple[int, int]]: capture_output=True, text=True, timeout=30, + env=host_env(), ) - except (OSError, subprocess.SubprocessError): + except (OSError, subprocess.SubprocessError) as error: + logger.debug("nvidia-smi unavailable: %s", error) return None if proc.returncode != 0: return None @@ -441,6 +449,8 @@ def cmd_inject_probe(args: argparse.Namespace) -> int: if wayland: import shutil + from vocalinux.utils.host_process import host_env + if shutil.which("wtype") is not None and backend != "x11": for _ in range(5): begin = time.monotonic() @@ -449,6 +459,7 @@ def cmd_inject_probe(args: argparse.Namespace) -> int: capture_output=True, text=True, timeout=10, + env=host_env(), ) wtype_roundtrips.append(time.monotonic() - begin) try: diff --git a/tests/test_host_process.py b/tests/test_host_process.py index 705c980..de8ef10 100644 --- a/tests/test_host_process.py +++ b/tests/test_host_process.py @@ -14,6 +14,10 @@ from vocalinux.utils.host_process import host_env REPO_ROOT = Path(__file__).resolve().parents[1] SOURCE = REPO_ROOT / "src" / "vocalinux" +#: The measurement script drives the app's own probes (nvidia-smi, wtype, the +#: injector) on the target machine, so it obeys the same rule as the package. +#: Build-tool scripts (uv, git, cmake) run outside any bundle and are exempt. +MEASUREMENT_SCRIPT = REPO_ROOT / "scripts" / "measure_perf_baseline.py" SUBPROCESS_FUNCS = {"run", "Popen", "check_output", "check_call", "call"} @@ -78,7 +82,7 @@ def test_host_binaries_get_a_stripped_environment_and_our_own_python_does_not(): dies on the wrong GLib, and our own interpreter stripped of it cannot find its stdlib or GI stack.""" inherit, stripped = [], [] - for path in sorted(SOURCE.rglob("*.py")): + for path in sorted([*SOURCE.rglob("*.py"), MEASUREMENT_SCRIPT]): for node in ast.walk(ast.parse(path.read_text(encoding="utf-8"))): if not _is_subprocess_call(node): continue