Skip to content

Commit 016a103

Browse files
committed
Introduce _load_and_report_path_linux(), add supported_libs.EXPECTED_LIB_SYMBOLS
1 parent efa983c commit 016a103

File tree

3 files changed

+73
-5
lines changed

3 files changed

+73
-5
lines changed

cuda_bindings/cuda/bindings/_path_finder/load_nvidia_dynamic_library.py

+37-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#
33
# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE
44

5+
import ctypes
56
import functools
67
import sys
78

@@ -16,13 +17,27 @@
1617
_WINBASE_LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000
1718

1819
else:
19-
import ctypes
20+
import ctypes.util
2021
import os
2122

2223
_LINUX_CDLL_MODE = os.RTLD_NOW | os.RTLD_GLOBAL
2324

25+
_LIBDL_PATH = ctypes.util.find_library("dl") or "libdl.so.2"
26+
_LIBDL = ctypes.CDLL(_LIBDL_PATH)
27+
_LIBDL.dladdr.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
28+
_LIBDL.dladdr.restype = ctypes.c_int
29+
30+
class Dl_info(ctypes.Structure):
31+
_fields_ = [
32+
("dli_fname", ctypes.c_char_p), # path to .so
33+
("dli_fbase", ctypes.c_void_p),
34+
("dli_sname", ctypes.c_char_p),
35+
("dli_saddr", ctypes.c_void_p),
36+
]
37+
38+
2439
from .find_nvidia_dynamic_library import _find_nvidia_dynamic_library
25-
from .supported_libs import DIRECT_DEPENDENCIES, SUPPORTED_WINDOWS_DLLS
40+
from .supported_libs import DIRECT_DEPENDENCIES, EXPECTED_LIB_SYMBOLS, SUPPORTED_WINDOWS_DLLS
2641

2742

2843
@functools.cache
@@ -62,6 +77,21 @@ def _windows_load_with_dll_basename(name: str) -> int:
6277
return None
6378

6479

80+
def _load_and_report_path_linux(libname, soname: str) -> (int, str):
81+
handle = ctypes.CDLL(soname, _LINUX_CDLL_MODE)
82+
for symbol_name in EXPECTED_LIB_SYMBOLS[libname]:
83+
symbol = getattr(handle, symbol_name, None)
84+
if symbol is not None:
85+
break
86+
else:
87+
raise RuntimeError(f"No expected symbol for {libname=!r}")
88+
addr = ctypes.cast(symbol, ctypes.c_void_p)
89+
info = Dl_info()
90+
if _LIBDL.dladdr(addr, ctypes.byref(info)) == 0:
91+
raise OSError(f"dladdr failed for {soname}")
92+
return handle, info.dli_fname.decode()
93+
94+
6595
@functools.cache
6696
def load_nvidia_dynamic_library(libname: str) -> int:
6797
for dep in DIRECT_DEPENDENCIES.get(libname, ()):
@@ -76,11 +106,12 @@ def load_nvidia_dynamic_library(libname: str) -> int:
76106
return handle
77107
else:
78108
try:
79-
handle = ctypes.CDLL(found.lib_searched_for, _LINUX_CDLL_MODE)
80-
except OSError:
81-
pass
109+
handle, abs_path = _load_and_report_path_linux(libname, found.lib_searched_for)
110+
except OSError as e:
111+
print(f"SYSTEM OSError for {libname=!r}: {e!r}", flush=True)
82112
else:
83113
# Use `cdef void* ptr = <void*><uintptr_t>` in cython to convert back to void*
114+
print(f"SYSTEM ABS_PATH for {libname=!r}: {abs_path}", flush=True)
84115
return handle._handle # C unsigned int
85116
found.raise_if_abs_path_is_None()
86117

@@ -98,4 +129,5 @@ def load_nvidia_dynamic_library(libname: str) -> int:
98129
except OSError as e:
99130
raise RuntimeError(f"Failed to dlopen {found.abs_path}: {e}") from e
100131
# Use `cdef void* ptr = <void*><uintptr_t>` in cython to convert back to void*
132+
print(f"FOUND ABS_PATH for {libname=!r}: {found.abs_path}", flush=True)
101133
return handle._handle # C unsigned int

cuda_bindings/cuda/bindings/_path_finder/supported_libs.py

+32
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,35 @@
9494
"nvrtc": ("nvrtc64_120_0.dll", "nvrtc64_112_0.dll"),
9595
"nvvm": ("nvvm64_40_0.dll",),
9696
}
97+
98+
# Based on nm output for Linux x86_64 /usr/local/cuda (12.8.1)
99+
EXPECTED_LIB_SYMBOLS = {
100+
"nvJitLink": ("nvJitLinkVersion",),
101+
"nvrtc": ("nvrtcVersion",),
102+
"nvvm": ("nvvmVersion",),
103+
"cudart": ("cudaRuntimeGetVersion",),
104+
"nvfatbin": ("nvFatbinVersion",),
105+
"cublas": ("cublasGetVersion",),
106+
"cublasLt": ("cublasLtGetVersion",),
107+
"cufft": ("cufftGetVersion",),
108+
"cufftw": ("fftwf_malloc",),
109+
"curand": ("curandGetVersion",),
110+
"cusolver": ("cusolverGetVersion",),
111+
"cusolverMg": ("cusolverMgCreate",),
112+
"cusparse": ("cusparseGetVersion",),
113+
"nppc": ("nppGetLibVersion",),
114+
"nppial": ("nppiAdd_32f_C1R",),
115+
"nppicc": ("nppiColorToGray_8u_C3C1R",),
116+
"nppidei": ("nppiCopy_8u_C1R",),
117+
"nppif": ("nppiFilterSobelHorizBorder_8u_C1R",),
118+
"nppig": ("nppiResize_8u_C1R",),
119+
"nppim": ("nppiErode_8u_C1R",),
120+
"nppist": ("nppiMean_8u_C1R",),
121+
"nppisu": ("nppiFree",),
122+
"nppitc": ("nppiThreshold_8u_C1R",),
123+
"npps": ("nppsAdd_32f",),
124+
"nvblas": ("dgemm",),
125+
"cufile": ("cuFileGetVersion",),
126+
# "cufile_rdma": ("rdma_buffer_reg",),
127+
"nvjpeg": ("nvjpegCreate",),
128+
}

cuda_bindings/tests/test_path_finder.py

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ def test_all_libnames_windows_dlls_consistency():
1818
assert tuple(sorted(ALL_LIBNAMES)) == tuple(sorted(supported_libs.SUPPORTED_WINDOWS_DLLS.keys()))
1919

2020

21+
def test_all_libnames_expected_lib_symbols_consistency():
22+
assert tuple(sorted(ALL_LIBNAMES)) == tuple(sorted(supported_libs.EXPECTED_LIB_SYMBOLS.keys()))
23+
24+
2125
def _build_subprocess_failed_for_libname_message(libname, result):
2226
return (
2327
f"Subprocess failed for {libname=!r} with exit code {result.returncode}\n"

0 commit comments

Comments
 (0)