Skip to content

Commit 776e53c

Browse files
committed
refactor(pathfinder): unify dynamic-lib subprocess probing
Consolidate canary and test subprocess entrypoints behind a shared module and JSON payload, update call sites/tests accordingly, and remove the old test-only subprocess helpers. Made-with: Cursor
1 parent e20ef78 commit 776e53c

12 files changed

+286
-175
lines changed

cuda_pathfinder/cuda/pathfinder/_dynamic_libs/canary_probe_subprocess.py

Lines changed: 0 additions & 43 deletions
This file was deleted.
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/usr/bin/env python
2+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
from __future__ import annotations
6+
7+
import os
8+
import sys
9+
from collections.abc import Sequence
10+
11+
from cuda.pathfinder._dynamic_libs.lib_descriptor import LIB_DESCRIPTORS
12+
from cuda.pathfinder._dynamic_libs.load_dl_common import DynamicLibNotFoundError, LoadedDL
13+
from cuda.pathfinder._dynamic_libs.platform_loader import LOADER
14+
from cuda.pathfinder._dynamic_libs.subprocess_protocol import (
15+
MODE_CANARY,
16+
MODE_LOAD,
17+
STATUS_NOT_FOUND,
18+
STATUS_OK,
19+
VALID_MODES,
20+
format_dynamic_lib_subprocess_payload,
21+
)
22+
23+
24+
def _probe_canary_abs_path(libname: str) -> str | None:
25+
desc = LIB_DESCRIPTORS.get(libname)
26+
if desc is None:
27+
raise ValueError(f"Unsupported canary library name: {libname!r}")
28+
try:
29+
loaded: LoadedDL | None = LOADER.load_with_system_search(desc)
30+
except DynamicLibNotFoundError:
31+
return None
32+
if loaded is None:
33+
return None
34+
abs_path = loaded.abs_path
35+
if not isinstance(abs_path, str):
36+
return None
37+
return abs_path
38+
39+
40+
def _validate_abs_path(abs_path: str) -> None:
41+
assert abs_path, f"empty path: {abs_path=!r}"
42+
assert os.path.isabs(abs_path), f"not absolute: {abs_path=!r}"
43+
assert os.path.isfile(abs_path), f"not a file: {abs_path=!r}"
44+
45+
46+
def _load_nvidia_dynamic_lib_for_test(libname: str) -> str:
47+
# Keep imports inside the subprocess body so startup stays focused on the
48+
# code under test rather than the parent test module.
49+
from cuda.pathfinder import load_nvidia_dynamic_lib
50+
from cuda.pathfinder._dynamic_libs.load_nvidia_dynamic_lib import _load_lib_no_cache
51+
from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import (
52+
SUPPORTED_LINUX_SONAMES,
53+
SUPPORTED_WINDOWS_DLLS,
54+
)
55+
from cuda.pathfinder._utils.platform_aware import IS_WINDOWS
56+
57+
loaded_dl_fresh = load_nvidia_dynamic_lib(libname)
58+
if loaded_dl_fresh.was_already_loaded_from_elsewhere:
59+
raise RuntimeError("loaded_dl_fresh.was_already_loaded_from_elsewhere")
60+
61+
abs_path = loaded_dl_fresh.abs_path
62+
if not isinstance(abs_path, str):
63+
raise RuntimeError(f"loaded_dl_fresh.abs_path is not a string: {abs_path!r}")
64+
_validate_abs_path(abs_path)
65+
assert loaded_dl_fresh.found_via is not None
66+
67+
loaded_dl_from_cache = load_nvidia_dynamic_lib(libname)
68+
if loaded_dl_from_cache is not loaded_dl_fresh:
69+
raise RuntimeError("loaded_dl_from_cache is not loaded_dl_fresh")
70+
71+
loaded_dl_no_cache = _load_lib_no_cache(libname)
72+
supported_libs = SUPPORTED_WINDOWS_DLLS if IS_WINDOWS else SUPPORTED_LINUX_SONAMES
73+
if not loaded_dl_no_cache.was_already_loaded_from_elsewhere and libname in supported_libs:
74+
raise RuntimeError("not loaded_dl_no_cache.was_already_loaded_from_elsewhere")
75+
abs_path_no_cache = loaded_dl_no_cache.abs_path
76+
if not isinstance(abs_path_no_cache, str):
77+
raise RuntimeError(f"loaded_dl_no_cache.abs_path is not a string: {abs_path_no_cache!r}")
78+
if not os.path.samefile(abs_path_no_cache, abs_path):
79+
raise RuntimeError(f"not os.path.samefile({abs_path_no_cache=!r}, {abs_path=!r})")
80+
_validate_abs_path(abs_path_no_cache)
81+
return abs_path
82+
83+
84+
def probe_dynamic_lib_and_print_json(libname: str, mode: str) -> None:
85+
if mode == MODE_CANARY:
86+
abs_path = _probe_canary_abs_path(libname)
87+
status = STATUS_OK if abs_path is not None else STATUS_NOT_FOUND
88+
print(format_dynamic_lib_subprocess_payload(status, abs_path))
89+
return
90+
91+
if mode == MODE_LOAD:
92+
try:
93+
abs_path = _load_nvidia_dynamic_lib_for_test(libname)
94+
except DynamicLibNotFoundError:
95+
print(format_dynamic_lib_subprocess_payload(STATUS_NOT_FOUND, None))
96+
return
97+
print(format_dynamic_lib_subprocess_payload(STATUS_OK, abs_path))
98+
return
99+
100+
raise ValueError(f"Unsupported subprocess probe mode: {mode!r}")
101+
102+
103+
def main(argv: Sequence[str] | None = None) -> int:
104+
args = list(sys.argv[1:] if argv is None else argv)
105+
if len(args) != 2 or args[0] not in VALID_MODES:
106+
modes = ", ".join(VALID_MODES)
107+
raise SystemExit(
108+
f"Usage: python -m cuda.pathfinder._dynamic_libs.dynamic_lib_subprocess <mode> <libname>\nModes: {modes}"
109+
)
110+
mode, libname = args
111+
probe_dynamic_lib_and_print_json(libname, mode)
112+
return 0
113+
114+
115+
if __name__ == "__main__":
116+
raise SystemExit(main())

cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@
44
from __future__ import annotations
55

66
import functools
7-
import json
87
import struct
98
import subprocess
109
import sys
11-
from pathlib import Path
1210
from typing import TYPE_CHECKING
1311

1412
from cuda.pathfinder._dynamic_libs.lib_descriptor import LIB_DESCRIPTORS
@@ -28,6 +26,15 @@
2826
find_via_ctk_root,
2927
run_find_steps,
3028
)
29+
from cuda.pathfinder._dynamic_libs.subprocess_protocol import (
30+
DYNAMIC_LIB_SUBPROCESS_CWD,
31+
MODE_CANARY,
32+
STATUS_NOT_FOUND,
33+
STATUS_OK,
34+
DynamicLibSubprocessPayload,
35+
build_dynamic_lib_subprocess_command,
36+
parse_dynamic_lib_subprocess_payload,
37+
)
3138
from cuda.pathfinder._utils.platform_aware import IS_WINDOWS
3239

3340
if TYPE_CHECKING:
@@ -40,9 +47,7 @@
4047
name for name, desc in LIB_DESCRIPTORS.items() if (desc.windows_dlls if IS_WINDOWS else desc.linux_sonames)
4148
)
4249
_PLATFORM_NAME = "Windows" if IS_WINDOWS else "Linux"
43-
_CANARY_PROBE_MODULE = "cuda.pathfinder._dynamic_libs.canary_probe_subprocess"
4450
_CANARY_PROBE_TIMEOUT_SECONDS = 10.0
45-
_CANARY_PROBE_IMPORT_ROOT = Path(__file__).resolve().parents[3]
4651

4752
# Driver libraries: shipped with the NVIDIA display driver, always on the
4853
# system linker path. These skip all CTK search steps (site-packages,
@@ -99,32 +104,30 @@ def _resolve_system_loaded_abs_path_in_subprocess(libname: str) -> str | None:
99104
"""Resolve a canary library's absolute path in a fresh Python subprocess."""
100105
try:
101106
result = subprocess.run( # noqa: S603 - trusted argv: current interpreter + internal probe module
102-
[sys.executable, "-m", _CANARY_PROBE_MODULE, libname],
107+
build_dynamic_lib_subprocess_command(MODE_CANARY, libname),
103108
capture_output=True,
104109
text=True,
105110
timeout=_CANARY_PROBE_TIMEOUT_SECONDS,
106111
check=False,
107-
cwd=_CANARY_PROBE_IMPORT_ROOT,
112+
cwd=DYNAMIC_LIB_SUBPROCESS_CWD,
108113
)
109114
except subprocess.TimeoutExpired as exc:
110115
_raise_canary_probe_child_process_error(timeout=exc.timeout, stderr=exc.stderr)
111116

112117
if result.returncode != 0:
113118
_raise_canary_probe_child_process_error(returncode=result.returncode, stderr=result.stderr)
114119

115-
# Use the final non-empty line in case earlier output lines are emitted.
116-
lines = [line for line in result.stdout.splitlines() if line.strip()]
117-
if not lines:
118-
raise RuntimeError(f"Canary probe child process produced no stdout payload for {libname!r}")
119-
try:
120-
payload = json.loads(lines[-1])
121-
except json.JSONDecodeError:
122-
raise RuntimeError(
123-
f"Canary probe child process emitted invalid JSON payload for {libname!r}: {lines[-1]!r}"
124-
) from None
125-
if isinstance(payload, str):
126-
return payload
127-
if payload is None:
120+
payload: DynamicLibSubprocessPayload = parse_dynamic_lib_subprocess_payload(
121+
result.stdout,
122+
libname=libname,
123+
error_label="Canary probe child process",
124+
)
125+
abs_path: str | None = payload.abs_path
126+
if payload.status == STATUS_OK:
127+
if abs_path is None:
128+
raise RuntimeError(f"Canary probe child process emitted unexpected payload for {libname!r}: {payload!r}")
129+
return abs_path
130+
if payload.status == STATUS_NOT_FOUND:
128131
return None
129132
raise RuntimeError(f"Canary probe child process emitted unexpected payload for {libname!r}: {payload!r}")
130133

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
from __future__ import annotations
5+
6+
import json
7+
import sys
8+
from dataclasses import dataclass
9+
from pathlib import Path
10+
from typing import Literal
11+
12+
MODE_CANARY: Literal["canary"] = "canary"
13+
MODE_LOAD: Literal["load"] = "load"
14+
VALID_MODES: tuple[Literal["canary"], Literal["load"]] = (MODE_CANARY, MODE_LOAD)
15+
16+
STATUS_OK: Literal["ok"] = "ok"
17+
STATUS_NOT_FOUND: Literal["not-found"] = "not-found"
18+
VALID_STATUSES: tuple[Literal["ok"], Literal["not-found"]] = (STATUS_OK, STATUS_NOT_FOUND)
19+
20+
DYNAMIC_LIB_SUBPROCESS_MODULE = "cuda.pathfinder._dynamic_libs.dynamic_lib_subprocess"
21+
DYNAMIC_LIB_SUBPROCESS_CWD = Path(__file__).resolve().parents[3]
22+
23+
24+
@dataclass(frozen=True)
25+
class DynamicLibSubprocessPayload:
26+
status: Literal["ok", "not-found"]
27+
abs_path: str | None
28+
29+
30+
def format_dynamic_lib_subprocess_payload(status: Literal["ok", "not-found"], abs_path: str | None) -> str:
31+
if status not in VALID_STATUSES:
32+
raise ValueError(f"Unsupported subprocess payload status: {status!r}")
33+
return json.dumps({"status": status, "abs_path": abs_path})
34+
35+
36+
def build_dynamic_lib_subprocess_command(mode: str, libname: str) -> list[str]:
37+
if mode not in VALID_MODES:
38+
raise ValueError(f"Unsupported subprocess probe mode: {mode!r}")
39+
return [sys.executable, "-m", DYNAMIC_LIB_SUBPROCESS_MODULE, mode, libname]
40+
41+
42+
def parse_dynamic_lib_subprocess_payload(
43+
stdout: str,
44+
*,
45+
libname: str,
46+
error_label: str,
47+
) -> DynamicLibSubprocessPayload:
48+
# Use the final non-empty line in case earlier output lines are emitted.
49+
lines = [line for line in stdout.splitlines() if line.strip()]
50+
if not lines:
51+
raise RuntimeError(f"{error_label} produced no stdout payload for {libname!r}")
52+
try:
53+
payload = json.loads(lines[-1])
54+
except json.JSONDecodeError:
55+
raise RuntimeError(f"{error_label} emitted invalid JSON payload for {libname!r}: {lines[-1]!r}") from None
56+
if not isinstance(payload, dict):
57+
raise RuntimeError(f"{error_label} emitted unexpected payload for {libname!r}: {payload!r}")
58+
status = payload.get("status")
59+
abs_path = payload.get("abs_path")
60+
if status == STATUS_OK:
61+
if not isinstance(abs_path, str):
62+
raise RuntimeError(f"{error_label} emitted unexpected payload for {libname!r}: {payload!r}")
63+
return DynamicLibSubprocessPayload(status=STATUS_OK, abs_path=abs_path)
64+
if status == STATUS_NOT_FOUND:
65+
if abs_path is not None:
66+
raise RuntimeError(f"{error_label} emitted unexpected payload for {libname!r}: {payload!r}")
67+
return DynamicLibSubprocessPayload(status=STATUS_NOT_FOUND, abs_path=None)
68+
raise RuntimeError(f"{error_label} emitted unexpected payload for {libname!r}: {payload!r}")

cuda_pathfinder/cuda/pathfinder/_testing/__init__.py

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)