Improve System Health pane (#24188)

* build out system health pane

* tweaks

* fixes

* fix notice link so it opens the correct camera

* tweak language
This commit is contained in:
Josh Hawkins
2026-09-12 07:30:04 -06:00
committed by Nicolas Mowen
parent 6d33b31bc6
commit 70ce193e09
57 changed files with 3965 additions and 464 deletions
+109 -15
View File
@@ -18,6 +18,36 @@ logger = logging.getLogger(__name__)
# Process-wide lock serializing all OpenVINO compile/inference calls
_OPENVINO_LOCK = threading.Lock()
# model file path -> (model type, device the runner actually loaded on); the
# embeddings maintainer folds this per enrichment for the stats endpoint.
# Models load on several threads (reindex, lazy first use), so writes and
# snapshots go through the lock.
loaded_devices: dict[str, tuple[str, str]] = {}
_loaded_devices_lock = threading.Lock()
def record_loaded_device(model_path: str, model_type: str, device: str) -> None:
"""Record the device a model loaded on, for the enrichment stats."""
with _loaded_devices_lock:
loaded_devices[model_path] = (model_type, device)
logger.info("Loaded %s model on %s", model_type, device)
def snapshot_loaded_devices() -> dict[str, tuple[str, str]]:
"""A copy that is safe to iterate while other threads load models."""
with _loaded_devices_lock:
return dict(loaded_devices)
_PROVIDER_LABELS = {
"CUDAExecutionProvider": "CUDA",
"TensorrtExecutionProvider": "TensorRT",
"MIGraphXExecutionProvider": "MIGraphX",
"OpenVINOExecutionProvider": "OpenVINO",
"CPUExecutionProvider": "CPU",
}
def is_arm64_platform() -> bool:
"""Check if we're running on an ARM platform."""
@@ -117,6 +147,12 @@ class BaseModelRunner(ABC):
"""Run inference with the model."""
pass
@property
@abstractmethod
def device_name(self) -> str:
"""Short label of the device the model actually loaded on."""
pass
class ONNXModelRunner(BaseModelRunner):
"""Run ONNX models using ONNX Runtime."""
@@ -174,6 +210,18 @@ class ONNXModelRunner(BaseModelRunner):
return self.ort.run(None, input)
@property
def device_name(self) -> str:
providers = self.ort.get_providers()
if not providers:
return "CPU"
provider = providers[0]
return _PROVIDER_LABELS.get(
provider, provider.removesuffix("ExecutionProvider")
)
class CudaGraphRunner(BaseModelRunner):
"""Encapsulates CUDA Graph capture and replay using ONNX Runtime IOBinding.
@@ -261,6 +309,10 @@ class CudaGraphRunner(BaseModelRunner):
self._session.run_with_iobinding(self._io_binding, ro)
return self._io_binding.copy_outputs_to_cpu()
@property
def device_name(self) -> str:
return "CUDA"
class OpenVINOModelRunner(BaseModelRunner):
"""OpenVINO model runner that handles inference efficiently."""
@@ -337,6 +389,8 @@ class OpenVINOModelRunner(BaseModelRunner):
if device == "NPU" and OpenVINOModelRunner.is_detection_model(model_type):
compile_config["NPU_TURBO"] = "YES"
self.compiled_device = device
# Compile model under the shared lock
with _OPENVINO_LOCK:
try:
@@ -368,6 +422,22 @@ class OpenVINOModelRunner(BaseModelRunner):
# model is complex and has dynamic shape
pass
@property
def device_name(self) -> str:
device = self.compiled_device
if device == "AUTO":
try:
resolved = self.compiled_model.get_property("EXECUTION_DEVICES")
if resolved:
device = ",".join(str(d) for d in resolved)
except Exception:
# older OpenVINO builds do not expose the property
pass
return f"OpenVINO {device}"
def get_input_names(self) -> list[str]:
"""Get input names for the model."""
return [input.get_any_name() for input in self.compiled_model.inputs]
@@ -515,6 +585,10 @@ class RKNNModelRunner(BaseModelRunner):
logger.error(f"Error loading RKNN model: {e}")
raise
@property
def device_name(self) -> str:
return "RKNN"
def get_input_names(self) -> list[str]:
"""Get input names for the model."""
# For detection models, we typically use "input" as the default input name
@@ -595,6 +669,14 @@ class RKNNModelRunner(BaseModelRunner):
pass
def _record_runner(
model_path: str, model_type: str, runner: BaseModelRunner
) -> BaseModelRunner:
"""Record the device a freshly loaded runner ended up on."""
record_loaded_device(model_path, model_type, runner.device_name)
return runner
def get_optimized_runner(
model_path: str, device: str | None, model_type: str, **kwargs
) -> BaseModelRunner:
@@ -605,7 +687,7 @@ def get_optimized_runner(
rknn_path = auto_convert_model(model_path)
if rknn_path:
return RKNNModelRunner(rknn_path)
return _record_runner(model_path, model_type, RKNNModelRunner(rknn_path))
providers, options = get_ort_providers(device == "CPU", device, **kwargs)
@@ -614,7 +696,11 @@ def get_optimized_runner(
# In other images we will get CUDA / ROCm which are preferred over OpenVINO
# There is currently no way to prioritize OpenVINO over CUDA / ROCm in these images
if device != "CPU" and is_openvino_gpu_npu_available():
return OpenVINOModelRunner(model_path, device, model_type, **kwargs)
return _record_runner(
model_path,
model_type,
OpenVINOModelRunner(model_path, device, model_type, **kwargs),
)
if (
CudaGraphRunner.is_model_supported(model_type)
@@ -624,13 +710,17 @@ def get_optimized_runner(
**options[0],
"enable_cuda_graph": True,
}
return CudaGraphRunner(
ort.InferenceSession(
model_path,
providers=providers,
provider_options=options,
return _record_runner(
model_path,
model_type,
CudaGraphRunner(
ort.InferenceSession(
model_path,
providers=providers,
provider_options=options,
),
options[0]["device_id"],
),
options[0]["device_id"],
)
if (
@@ -642,12 +732,16 @@ def get_optimized_runner(
providers.pop(0)
options.pop(0)
return ONNXModelRunner(
ort.InferenceSession(
model_path,
sess_options=get_ort_session_options(model_type),
providers=providers,
provider_options=options,
return _record_runner(
model_path,
model_type,
ONNXModelRunner(
ort.InferenceSession(
model_path,
sess_options=get_ort_session_options(model_type),
providers=providers,
provider_options=options,
),
model_type=model_type,
),
model_type=model_type,
)