diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_common.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_common.py index 416718f5a..2e6c9eb17 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_common.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_common.py @@ -16,6 +16,7 @@ class LoadedDL: abs_path: Optional[str] was_already_loaded_from_elsewhere: bool _handle_uint: int # Platform-agnostic unsigned pointer value + found_via: str def load_dependencies(libname: str, load_func: Callable[[str], LoadedDL]) -> None: diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_linux.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_linux.py index a7de858b7..040e24705 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_linux.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_linux.py @@ -138,7 +138,9 @@ def check_if_already_loaded_from_elsewhere(libname: str, _have_abs_path: bool) - except OSError: continue else: - return LoadedDL(abs_path_for_dynamic_library(libname, handle), True, handle._handle) + return LoadedDL( + abs_path_for_dynamic_library(libname, handle), True, handle._handle, "was-already-loaded-from-elsewhere" + ) return None @@ -170,7 +172,7 @@ def load_with_system_search(libname: str) -> Optional[LoadedDL]: abs_path = abs_path_for_dynamic_library(libname, handle) if abs_path is None: raise RuntimeError(f"No expected symbol for {libname=!r}") - return LoadedDL(abs_path, False, handle._handle) + return LoadedDL(abs_path, False, handle._handle, "system-search") return None @@ -193,7 +195,7 @@ def _work_around_known_bugs(libname: str, found_path: str) -> None: ctypes.CDLL(dep_path, CDLL_MODE) -def load_with_abs_path(libname: str, found_path: str) -> LoadedDL: +def load_with_abs_path(libname: str, found_path: str, found_via: Optional[str] = None) -> LoadedDL: """Load a dynamic library from the given path. Args: @@ -211,4 +213,4 @@ def load_with_abs_path(libname: str, found_path: str) -> LoadedDL: handle = _load_lib(libname, found_path) except OSError as e: raise RuntimeError(f"Failed to dlopen {found_path}: {e}") from e - return LoadedDL(found_path, False, handle._handle) + return LoadedDL(found_path, False, handle._handle, found_via) diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_windows.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_windows.py index 5da6d9b84..d8ac53fe8 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_windows.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_windows.py @@ -100,7 +100,10 @@ def abs_path_for_dynamic_library(libname: str, handle: ctypes.wintypes.HMODULE) return buffer.value -def check_if_already_loaded_from_elsewhere(libname: str, have_abs_path: bool) -> Optional[LoadedDL]: +def check_if_already_loaded_from_elsewhere( + libname: str, + have_abs_path: bool, +) -> Optional[LoadedDL]: for dll_name in SUPPORTED_WINDOWS_DLLS.get(libname, ()): handle = kernel32.GetModuleHandleW(dll_name) if handle: @@ -110,7 +113,7 @@ def check_if_already_loaded_from_elsewhere(libname: str, have_abs_path: bool) -> # load_with_abs_path(). To make the side-effect more deterministic, # activate it even if the library was already loaded from elsewhere. add_dll_directory(abs_path) - return LoadedDL(abs_path, True, ctypes_handle_to_unsigned_int(handle)) + return LoadedDL(abs_path, True, ctypes_handle_to_unsigned_int(handle), "was-already-loaded-from-elsewhere") return None @@ -128,12 +131,12 @@ def load_with_system_search(libname: str) -> Optional[LoadedDL]: handle = kernel32.LoadLibraryExW(dll_name, None, 0) if handle: abs_path = abs_path_for_dynamic_library(libname, handle) - return LoadedDL(abs_path, False, ctypes_handle_to_unsigned_int(handle)) + return LoadedDL(abs_path, False, ctypes_handle_to_unsigned_int(handle), "system-search") return None -def load_with_abs_path(libname: str, found_path: str) -> LoadedDL: +def load_with_abs_path(libname: str, found_path: str, found_via: Optional[str] = None) -> LoadedDL: """Load a dynamic library from the given path. Args: @@ -156,4 +159,4 @@ def load_with_abs_path(libname: str, found_path: str) -> LoadedDL: error_code = ctypes.GetLastError() # type: ignore[attr-defined] raise RuntimeError(f"Failed to load DLL at {found_path}: Windows error {error_code}") - return LoadedDL(found_path, False, ctypes_handle_to_unsigned_int(handle)) + return LoadedDL(found_path, False, ctypes_handle_to_unsigned_int(handle), found_via) diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py index 6a8392589..fe553a434 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py @@ -26,8 +26,14 @@ def _load_lib_no_cache(libname: str) -> LoadedDL: finder = _FindNvidiaDynamicLib(libname) abs_path = finder.try_site_packages() - if abs_path is None: + + abs_path = finder.try_site_packages() + if abs_path is not None: + found_via = "site-packages" + else: abs_path = finder.try_with_conda_prefix() + if abs_path is not None: + found_via = "conda" # If the library was already loaded by someone else, reproduce any OS-specific # side-effects we would have applied on a direct absolute-path load (e.g., @@ -49,8 +55,10 @@ def _load_lib_no_cache(libname: str) -> LoadedDL: abs_path = finder.try_with_cuda_home() if abs_path is None: finder.raise_not_found_error() + else: + found_via = "CUDA_HOME" - return load_with_abs_path(libname, abs_path) + return load_with_abs_path(libname, abs_path, found_via) @functools.cache diff --git a/cuda_pathfinder/cuda/pathfinder/_version.py b/cuda_pathfinder/cuda/pathfinder/_version.py index 56364e619..cb42a4a3c 100644 --- a/cuda_pathfinder/cuda/pathfinder/_version.py +++ b/cuda_pathfinder/cuda/pathfinder/_version.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -__version__ = "1.3.1a0" +__version__ = "1.3.1" diff --git a/cuda_pathfinder/docs/nv-versions.json b/cuda_pathfinder/docs/nv-versions.json index db8fecd82..f25c50bc6 100644 --- a/cuda_pathfinder/docs/nv-versions.json +++ b/cuda_pathfinder/docs/nv-versions.json @@ -3,6 +3,10 @@ "version": "latest", "url": "https://nvidia.github.io/cuda-python/cuda-pathfinder/latest/" }, + { + "version": "1.3.1", + "url": "https://nvidia.github.io/cuda-python/cuda-pathfinder/1.3.1/" + }, { "version": "1.3.0", "url": "https://nvidia.github.io/cuda-python/cuda-pathfinder/1.3.0/" diff --git a/cuda_pathfinder/docs/source/release.rst b/cuda_pathfinder/docs/source/release.rst index b46579557..cd837b57f 100644 --- a/cuda_pathfinder/docs/source/release.rst +++ b/cuda_pathfinder/docs/source/release.rst @@ -7,6 +7,7 @@ Release Notes .. toctree:: :maxdepth: 3 + 1.3.1 1.3.0 1.2.3 1.2.2 diff --git a/cuda_pathfinder/docs/source/release/1.X.Y-notes.rst b/cuda_pathfinder/docs/source/release/1.3.1-notes.rst similarity index 72% rename from cuda_pathfinder/docs/source/release/1.X.Y-notes.rst rename to cuda_pathfinder/docs/source/release/1.3.1-notes.rst index 55a9c0628..8214716ca 100644 --- a/cuda_pathfinder/docs/source/release/1.X.Y-notes.rst +++ b/cuda_pathfinder/docs/source/release/1.3.1-notes.rst @@ -3,10 +3,10 @@ .. py:currentmodule:: cuda.pathfinder -``cuda-pathfinder`` 1.X.Y Release notes +``cuda-pathfinder`` 1.3.1 Release notes ======================================= -Released on TBD +Released on Oct 13, 2025 Highlights ---------- @@ -14,3 +14,6 @@ Highlights * supported_nvidia_libs.py updates: add nvidia-cublasmp-cu12, nvidia-cublasmp-cu13, nvidia-cudss-cu13 (`PR #1089 `_) + +* Add ``LoadedDL.found_via`` + (`PR #1049 `_) diff --git a/cuda_pathfinder/tests/child_load_nvidia_dynamic_lib_helper.py b/cuda_pathfinder/tests/child_load_nvidia_dynamic_lib_helper.py index 72ee80c89..685d2eda2 100644 --- a/cuda_pathfinder/tests/child_load_nvidia_dynamic_lib_helper.py +++ b/cuda_pathfinder/tests/child_load_nvidia_dynamic_lib_helper.py @@ -43,6 +43,7 @@ def child_process_func(libname): if loaded_dl_fresh.was_already_loaded_from_elsewhere: raise RuntimeError("loaded_dl_fresh.was_already_loaded_from_elsewhere") validate_abs_path(loaded_dl_fresh.abs_path) + assert loaded_dl_fresh.found_via is not None loaded_dl_from_cache = load_nvidia_dynamic_lib(libname) if loaded_dl_from_cache is not loaded_dl_fresh: