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

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:
2026-09-24 18:28:26 -04:00
co-authored by Claude Opus 5.5
parent f127c50207
commit 42a40d71a4
2 changed files with 58 additions and 7 deletions
+23 -2
View File
@@ -69,9 +69,30 @@ 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:
out["device"] = "cuda"
return out return out
# 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
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:
+35 -5
View File
@@ -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"]