Files
FabledCurator/tests/test_agent_accel.py
T
bvandeusenandClaude Opus 5.5 cc53d8db7b
CI and images / lint (push) Successful in 3s
CI and images / extension-version (push) Successful in 3s
CI and images / frontend-build (push) Successful in 27s
CI and images / backend-lint-and-test (push) Successful in 34s
CI and images / integration (push) Successful in 2m22s
CI and images / sign-extension (push) Successful in 4s
CI and images / build-web (push) Successful in 2m46s
CI and images / smoke-web (push) Successful in 50s
CI and images / build-agent (push) Successful in 6m35s
CI and images / promote (push) Successful in 2s
feat: a GPU agent on the CPU shows as degraded, in the System view and on its own page (4410)
torch and onnxruntime both fall back to the CPU without raising, so the agent
that ran CPU-bound for weeks after a driver update leased and checked in like
a healthy one.

- The agent sends its startup accel report on every lease and heartbeat.
- The server keeps a bounded copy on the roster row. A running agent with a
  runtime off the GPU becomes `degraded`, with a sentence naming the runtime
  and the reason.
- The top nav shows it amber.
- The agent page carries a banner, and its pill reads "CPU only".

Also: the bandwidth field gets the page's − / + stepper, and both number
fields drop the browser's spin arrows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR
2026-09-24 19:09:07 -04:00

123 lines
3.7 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"
def test_summary_is_what_the_server_stores(monkeypatch):
"""Device plus a bounded reason, per runtime — sent on every lease."""
monkeypatch.setattr(accel, "LAST", {
"torch": {"version": "2.14.0", "device": "cuda", "gpu": "RTX"},
"onnx": {"version": "1.30.0", "device": "cpu", "error": "e" * 500},
})
assert accel.summary() == {
"torch": {"device": "cuda"},
"onnx": {"device": "cpu", "error": "e" * 200},
}
def test_summary_before_the_report_is_none(monkeypatch):
monkeypatch.setattr(accel, "LAST", {})
assert accel.summary() is None