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
106 lines
3.2 KiB
Python
106 lines
3.2 KiB
Python
"""The agent's startup report of which runtime landed on the GPU (#1451).
|
|
|
|
Both runtimes fall back to the CPU without raising, so the report is the only
|
|
thing that says so. These pin the distinction it exists for: onnxruntime
|
|
listing the CUDA provider is not the same as the provider being able to load
|
|
its libraries.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import types
|
|
|
|
from agent.fc_agent import accel
|
|
|
|
|
|
def _ort(providers, preload=None):
|
|
mod = types.SimpleNamespace(
|
|
__version__="1.30.0",
|
|
__file__="/site/onnxruntime/__init__.py",
|
|
get_available_providers=lambda: providers,
|
|
)
|
|
if preload is not None:
|
|
mod.preload_dlls = preload
|
|
return mod
|
|
|
|
|
|
def _imp(mod):
|
|
return lambda name: mod
|
|
|
|
|
|
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 = []
|
|
s = accel.onnx_status(
|
|
_imp(_ort(GPU_BUILD, lambda: calls.append("preload"))),
|
|
load=_loader(calls, _Cudart()),
|
|
)
|
|
assert s["device"] == "cuda"
|
|
assert calls[0] == "preload"
|
|
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 load(path, mode=0):
|
|
if path.endswith("providers_cuda.so"):
|
|
raise OSError("libcudart.so.13: cannot open shared object file")
|
|
|
|
s = accel.onnx_status(_imp(_ort(GPU_BUILD)), load=load)
|
|
assert s["device"] == "cpu"
|
|
assert "libcudart.so.13" in s["error"]
|
|
|
|
|
|
def test_onnx_cpu_build_never_tries_the_cuda_library():
|
|
def load(path, mode=0):
|
|
raise AssertionError("a CPU build has no CUDA provider to load")
|
|
|
|
s = accel.onnx_status(_imp(_ort(["CPUExecutionProvider"])), load=load)
|
|
assert s["device"] == "cpu"
|
|
|
|
|
|
def test_torch_reports_cpu_when_cuda_is_unavailable():
|
|
torch = types.SimpleNamespace(
|
|
__version__="2.14.0+cu130",
|
|
version=types.SimpleNamespace(cuda="13.0"),
|
|
cuda=types.SimpleNamespace(is_available=lambda: False),
|
|
)
|
|
s = accel.torch_status(_imp(torch))
|
|
assert s == {"version": "2.14.0+cu130", "cuda_build": "13.0", "device": "cpu"}
|
|
|
|
|
|
def test_a_missing_runtime_is_reported_not_raised():
|
|
def imp(name):
|
|
raise ImportError(f"No module named {name!r}")
|
|
|
|
assert accel.torch_status(imp)["device"] == "unavailable"
|
|
assert accel.onnx_status(imp)["device"] == "unavailable"
|