fix: the agent's ONNX check asks CUDA for a device instead of trusting that the libraries loaded (1451)
CI and images / lint (push) Successful in 2s
CI and images / extension-version (push) Successful in 3s
CI and images / frontend-build (push) Successful in 24s
CI and images / backend-lint-and-test (push) Successful in 33s
CI and images / integration (push) Successful in 2m19s
CI and images / sign-extension (push) Successful in 3s
CI and images / build-web (push) Successful in 5s
CI and images / smoke-web (push) Successful in 41s
CI and images / build-agent (push) Successful in 5m42s
CI and images / promote (push) Successful in 2s
CI and images / lint (push) Successful in 2s
CI and images / extension-version (push) Successful in 3s
CI and images / frontend-build (push) Successful in 24s
CI and images / backend-lint-and-test (push) Successful in 33s
CI and images / integration (push) Successful in 2m19s
CI and images / sign-extension (push) Successful in 3s
CI and images / build-web (push) Successful in 5s
CI and images / smoke-web (push) Successful in 41s
CI and images / build-agent (push) Successful in 5m42s
CI and images / promote (push) Successful in 2s
It reported "onnx on GPU" beside torch failing cuInit with "CUDA unknown error". Every library resolved, but no device could be used. The check now calls cudaGetDeviceCount and reports the CUDA error when there is one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR
This commit is contained in:
+23
-2
@@ -69,11 +69,32 @@ def onnx_status(imp=importlib.import_module, load=ctypes.CDLL) -> dict:
|
|||||||
except OSError as e:
|
except OSError as e:
|
||||||
out["device"] = "cpu"
|
out["device"] = "cpu"
|
||||||
out["error"] = str(e)
|
out["error"] = str(e)
|
||||||
else:
|
return out
|
||||||
out["device"] = "cuda"
|
# Loading proves the libraries resolve, NOT that a GPU can be used: on
|
||||||
|
# 2026-09-24 this reported "onnx on GPU" beside torch failing cuInit with
|
||||||
|
# "CUDA unknown error" (a driver update awaiting a reboot). Asking the CUDA
|
||||||
|
# runtime for a device initialises the driver the provider would use.
|
||||||
|
error = _cuda_device_error(load)
|
||||||
|
out["device"] = "cpu" if error else "cuda"
|
||||||
|
if error:
|
||||||
|
out["error"] = error
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def _cuda_device_error(load=ctypes.CDLL) -> str | None:
|
||||||
|
"""None when the CUDA runtime can reach a device, else why it cannot."""
|
||||||
|
try:
|
||||||
|
cudart = load("libcudart.so.13")
|
||||||
|
except OSError as e:
|
||||||
|
return str(e)
|
||||||
|
count = ctypes.c_int(0)
|
||||||
|
rc = cudart.cudaGetDeviceCount(ctypes.byref(count))
|
||||||
|
if rc != 0:
|
||||||
|
cudart.cudaGetErrorString.restype = ctypes.c_char_p
|
||||||
|
return f"cudaGetDeviceCount: {cudart.cudaGetErrorString(rc).decode()} ({rc})"
|
||||||
|
return None if count.value > 0 else "no CUDA device visible"
|
||||||
|
|
||||||
|
|
||||||
def report() -> dict:
|
def report() -> dict:
|
||||||
"""Check both runtimes, log the result, and keep it for /status."""
|
"""Check both runtimes, log the result, and keep it for /status."""
|
||||||
LAST.clear()
|
LAST.clear()
|
||||||
|
|||||||
@@ -28,15 +28,45 @@ def _imp(mod):
|
|||||||
return lambda name: mod
|
return lambda name: mod
|
||||||
|
|
||||||
|
|
||||||
def test_onnx_on_gpu_when_the_cuda_provider_loads():
|
class _Cudart:
|
||||||
|
"""libcudart as ctypes sees it: cudaGetDeviceCount writes through a pointer."""
|
||||||
|
|
||||||
|
def __init__(self, rc=0, count=1):
|
||||||
|
self.rc = rc
|
||||||
|
self.count = count
|
||||||
|
self.cudaGetErrorString = lambda rc: b"unknown error"
|
||||||
|
|
||||||
|
def cudaGetDeviceCount(self, ref):
|
||||||
|
ref._obj.value = self.count
|
||||||
|
return self.rc
|
||||||
|
|
||||||
|
|
||||||
|
def _loader(calls, cudart):
|
||||||
|
def load(path, mode=0):
|
||||||
|
calls.append(path)
|
||||||
|
return cudart if path == "libcudart.so.13" else None
|
||||||
|
return load
|
||||||
|
|
||||||
|
|
||||||
|
GPU_BUILD = ["CUDAExecutionProvider", "CPUExecutionProvider"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_onnx_on_gpu_when_the_provider_loads_and_a_device_answers():
|
||||||
calls = []
|
calls = []
|
||||||
s = accel.onnx_status(
|
s = accel.onnx_status(
|
||||||
_imp(_ort(["CUDAExecutionProvider", "CPUExecutionProvider"], lambda: calls.append("preload"))),
|
_imp(_ort(GPU_BUILD, lambda: calls.append("preload"))),
|
||||||
load=lambda path, mode=0: calls.append(path),
|
load=_loader(calls, _Cudart()),
|
||||||
)
|
)
|
||||||
assert s["device"] == "cuda"
|
assert s["device"] == "cuda"
|
||||||
assert calls[0] == "preload"
|
assert calls[0] == "preload"
|
||||||
assert calls[-1].endswith("capi/libonnxruntime_providers_cuda.so")
|
assert any(c.endswith("capi/libonnxruntime_providers_cuda.so") for c in calls)
|
||||||
|
|
||||||
|
|
||||||
|
def test_onnx_libraries_loading_is_not_a_gpu_when_cuda_cannot_initialise():
|
||||||
|
"""The 2026-09-24 case: every library resolved, cuInit failed."""
|
||||||
|
s = accel.onnx_status(_imp(_ort(GPU_BUILD)), load=_loader([], _Cudart(rc=999)))
|
||||||
|
assert s["device"] == "cpu"
|
||||||
|
assert "unknown error" in s["error"]
|
||||||
|
|
||||||
|
|
||||||
def test_onnx_listed_but_unloadable_reports_cpu_with_the_reason():
|
def test_onnx_listed_but_unloadable_reports_cpu_with_the_reason():
|
||||||
@@ -44,7 +74,7 @@ def test_onnx_listed_but_unloadable_reports_cpu_with_the_reason():
|
|||||||
if path.endswith("providers_cuda.so"):
|
if path.endswith("providers_cuda.so"):
|
||||||
raise OSError("libcudart.so.13: cannot open shared object file")
|
raise OSError("libcudart.so.13: cannot open shared object file")
|
||||||
|
|
||||||
s = accel.onnx_status(_imp(_ort(["CUDAExecutionProvider", "CPUExecutionProvider"])), load=load)
|
s = accel.onnx_status(_imp(_ort(GPU_BUILD)), load=load)
|
||||||
assert s["device"] == "cpu"
|
assert s["device"] == "cpu"
|
||||||
assert "libcudart.so.13" in s["error"]
|
assert "libcudart.so.13" in s["error"]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user