Skip to content

Commit 281e39b

Browse files
committed
Add diagnostics for Windows CUPTI reload detection
Capture the first load result, basename probe results, and relevant enumerated modules so we can determine why cupti reload detection still fails on real Windows 13.2.1 systems. Made-with: Cursor
1 parent cf5da9c commit 281e39b

2 files changed

Lines changed: 78 additions & 3 deletions

File tree

cuda_pathfinder/cuda/pathfinder/_dynamic_libs/dynamic_lib_subprocess.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
# Any production-code impact is negligible since the extra logic only runs
2828
# in the subprocess entrypoint and only in test mode.
2929

30+
_CUPTI_DIAGNOSTICS_ENVVAR = "CUDA_PATHFINDER_WINDOWS_CUPTI_ALREADY_LOADED_DIAGNOSTICS"
31+
3032

3133
def _probe_canary_abs_path(libname: str) -> str | None:
3234
desc = LIB_DESCRIPTORS.get(libname)
@@ -48,6 +50,26 @@ def _validate_abs_path(abs_path: str) -> None:
4850
assert os.path.isfile(abs_path), f"not a file: {abs_path=!r}"
4951

5052

53+
def _cupti_diagnostics_enabled(libname: str) -> bool:
54+
raw = os.environ.get(_CUPTI_DIAGNOSTICS_ENVVAR)
55+
if libname != "cupti" or raw is None:
56+
return False
57+
return raw.strip().lower() not in ("", "0", "false", "no")
58+
59+
60+
def _emit_cupti_diagnostic(message: str) -> None:
61+
print(f"[cuda.pathfinder][cupti-diag] {message}", file=sys.stderr)
62+
63+
64+
def _emit_loaded_dl_diagnostic(label: str, loaded_dl: LoadedDL) -> None:
65+
_emit_cupti_diagnostic(
66+
f"{label}: abs_path={loaded_dl.abs_path!r}"
67+
f" found_via={loaded_dl.found_via!r}"
68+
f" was_already_loaded_from_elsewhere={loaded_dl.was_already_loaded_from_elsewhere}"
69+
f" handle=0x{loaded_dl._handle_uint:x}"
70+
)
71+
72+
5173
def _load_nvidia_dynamic_lib_for_test(libname: str) -> str:
5274
"""Test-only loader used by the subprocess entrypoint."""
5375
# Keep imports inside the subprocess body so startup stays focused on the
@@ -60,7 +82,10 @@ def _load_nvidia_dynamic_lib_for_test(libname: str) -> str:
6082
)
6183
from cuda.pathfinder._utils.platform_aware import IS_WINDOWS
6284

85+
diagnostics_enabled = _cupti_diagnostics_enabled(libname)
6386
loaded_dl_fresh = load_nvidia_dynamic_lib(libname)
87+
if diagnostics_enabled:
88+
_emit_loaded_dl_diagnostic("fresh load", loaded_dl_fresh)
6489
if loaded_dl_fresh.was_already_loaded_from_elsewhere:
6590
raise RuntimeError("loaded_dl_fresh.was_already_loaded_from_elsewhere")
6691

@@ -75,6 +100,8 @@ def _load_nvidia_dynamic_lib_for_test(libname: str) -> str:
75100
raise RuntimeError("loaded_dl_from_cache is not loaded_dl_fresh")
76101

77102
loaded_dl_no_cache = _load_lib_no_cache(libname)
103+
if diagnostics_enabled:
104+
_emit_loaded_dl_diagnostic("second uncached load", loaded_dl_no_cache)
78105
supported_libs = SUPPORTED_WINDOWS_DLLS if IS_WINDOWS else SUPPORTED_LINUX_SONAMES
79106
if not loaded_dl_no_cache.was_already_loaded_from_elsewhere and libname in supported_libs:
80107
raise RuntimeError("not loaded_dl_no_cache.was_already_loaded_from_elsewhere")

cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_windows.py

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import ctypes.wintypes
88
import os
99
import struct
10+
import sys
1011
from collections.abc import Iterator
1112
from typing import TYPE_CHECKING
1213

@@ -62,6 +63,19 @@
6263
]
6364
psapi.EnumProcessModules.restype = ctypes.wintypes.BOOL
6465

66+
_CUPTI_DIAGNOSTICS_ENVVAR = "CUDA_PATHFINDER_WINDOWS_CUPTI_ALREADY_LOADED_DIAGNOSTICS"
67+
68+
69+
def _cupti_diagnostics_enabled(desc_name: str) -> bool:
70+
raw = os.environ.get(_CUPTI_DIAGNOSTICS_ENVVAR)
71+
if desc_name != "cupti" or raw is None:
72+
return False
73+
return raw.strip().lower() not in ("", "0", "false", "no")
74+
75+
76+
def _emit_cupti_diagnostic(message: str) -> None:
77+
sys.stderr.write(f"[cuda.pathfinder][cupti-diag] {message}\n")
78+
6579

6680
def ctypes_handle_to_unsigned_int(handle: ctypes.wintypes.HMODULE) -> int:
6781
"""Convert ctypes HMODULE to unsigned int."""
@@ -142,20 +156,52 @@ def _iter_loaded_module_handles() -> Iterator[ctypes.wintypes.HMODULE]:
142156
capacity = count
143157

144158

145-
def _find_loaded_module(dll_names: tuple[str, ...]) -> tuple[ctypes.wintypes.HMODULE, str] | None:
159+
def _find_loaded_module(
160+
dll_names: tuple[str, ...],
161+
*,
162+
diagnostics_enabled: bool = False,
163+
) -> tuple[ctypes.wintypes.HMODULE, str] | None:
146164
wanted = {dll_name.casefold() for dll_name in dll_names}
165+
relevant_modules: list[str] = []
147166
for handle in _iter_loaded_module_handles():
148167
abs_path = abs_path_for_dynamic_library("loaded module", handle)
149-
if os.path.basename(abs_path).casefold() in wanted:
168+
basename = os.path.basename(abs_path)
169+
basename_casefold = basename.casefold()
170+
if diagnostics_enabled and ("cupti" in basename_casefold or "nvperf" in basename_casefold):
171+
relevant_modules.append(f"0x{ctypes_handle_to_unsigned_int(handle):x}:{abs_path}")
172+
if basename_casefold in wanted:
173+
if diagnostics_enabled:
174+
_emit_cupti_diagnostic(
175+
"enumerated relevant modules: " + (" | ".join(relevant_modules) if relevant_modules else "<none>")
176+
)
177+
_emit_cupti_diagnostic(
178+
f"enumeration match: basename={basename!r} abs_path={abs_path!r}"
179+
f" handle=0x{ctypes_handle_to_unsigned_int(handle):x}"
180+
)
150181
return handle, abs_path
182+
if diagnostics_enabled:
183+
_emit_cupti_diagnostic(
184+
"enumerated relevant modules: " + (" | ".join(relevant_modules) if relevant_modules else "<none>")
185+
)
151186
return None
152187

153188

154189
def check_if_already_loaded_from_elsewhere(desc: LibDescriptor, have_abs_path: bool) -> LoadedDL | None:
190+
diagnostics_enabled = _cupti_diagnostics_enabled(desc.name)
191+
basename_probe_results: list[str] = []
155192
for dll_name in desc.windows_dlls:
156193
handle = kernel32.GetModuleHandleW(dll_name)
194+
if diagnostics_enabled:
195+
handle_text = "0x0" if not handle else f"0x{ctypes_handle_to_unsigned_int(handle):x}"
196+
basename_probe_results.append(f"{dll_name}={handle_text}")
157197
if handle:
158198
abs_path = abs_path_for_dynamic_library(desc.name, handle)
199+
if diagnostics_enabled:
200+
_emit_cupti_diagnostic("basename GetModuleHandleW results: " + ", ".join(basename_probe_results))
201+
_emit_cupti_diagnostic(
202+
f"basename match: dll_name={dll_name!r} abs_path={abs_path!r}"
203+
f" handle=0x{ctypes_handle_to_unsigned_int(handle):x}"
204+
)
159205
if have_abs_path and desc.requires_add_dll_directory:
160206
# This is a side-effect if the pathfinder loads the library via
161207
# load_with_abs_path(). To make the side-effect more deterministic,
@@ -164,7 +210,9 @@ def check_if_already_loaded_from_elsewhere(desc: LibDescriptor, have_abs_path: b
164210
return LoadedDL(abs_path, True, ctypes_handle_to_unsigned_int(handle), "was-already-loaded-from-elsewhere")
165211
# Observed on newer Windows CUPTI builds: GetModuleHandleW(basename)
166212
# can miss an already loaded DLL, so fall back to enumerating loaded modules.
167-
loaded = _find_loaded_module(desc.windows_dlls)
213+
if diagnostics_enabled:
214+
_emit_cupti_diagnostic("basename GetModuleHandleW results: " + ", ".join(basename_probe_results))
215+
loaded = _find_loaded_module(desc.windows_dlls, diagnostics_enabled=diagnostics_enabled)
168216
if loaded is not None:
169217
handle, abs_path = loaded
170218
if have_abs_path and desc.requires_add_dll_directory:

0 commit comments

Comments
 (0)