feat(axelera): busy time as npu usage in npu_usages

The Metis has no utilization readout without the axsystemserver broker,
which cannot run alongside a live detector. Report the worker busy time
(fps * inference time) as a real load indicator instead, plus the board
temperature, under npu_usages[axelera].
This commit is contained in:
patrykorwat 2026-08-19 20:05:58 +00:00
parent 24dc4edf51
commit 1ae0843c00

View File

@ -180,6 +180,7 @@ def get_processing_stats(
config: FrigateConfig,
stats: dict[str, str],
hwaccel_errors: dict[str, float],
stats_tracking: StatsTrackingTypes,
) -> None:
"""Get stats for cpu / gpu."""
@ -187,7 +188,7 @@ def get_processing_stats(
stats_tasks = [
asyncio.create_task(set_gpu_stats(config, stats, hwaccel_errors)),
asyncio.create_task(set_cpu_stats(stats)),
asyncio.create_task(set_npu_usages(config, stats)),
asyncio.create_task(set_npu_usages(config, stats, stats_tracking)),
]
if config.telemetry.stats.network_bandwidth:
@ -324,7 +325,11 @@ async def set_gpu_stats(
all_stats["gpu_usages"] = stats
async def set_npu_usages(config: FrigateConfig, all_stats: dict[str, Any]) -> None:
async def set_npu_usages(
config: FrigateConfig,
all_stats: dict[str, Any],
stats_tracking: StatsTrackingTypes,
) -> None:
stats: dict[str, dict] = {}
for detector in config.detectors.values():
@ -341,13 +346,31 @@ async def set_npu_usages(config: FrigateConfig, all_stats: dict[str, Any]) -> No
axcl_usage = get_axcl_npu_stats()
stats["axengine"] = axcl_usage
elif detector.type == "axelera":
# Axelera Metis: temperature from the board controller.
# There is no utilization readout without the axsystemserver
# broker, which cannot run alongside a live detector.
# Axelera Metis: board temperature + busy time from the worker.
# MVM utilization needs the axsystemserver broker, which cannot
# run alongside a live detector; busy time (fps * s) is computed
# from Frigate's own measurements as a real load indicator.
axelera_entry = None
metis_temp = get_axelera_board_temp()
if metis_temp is not None:
stats["axelera"] = {"mem": "-%", "temp": metis_temp}
axelera_entry = {"mem": "-%", "temp": metis_temp}
npu_det = stats_tracking.get("detectors", {}).get("axelera")
if npu_det is not None:
total_fps = sum(
cam.detection_fps.value
for cam in stats_tracking.get("camera_metrics", {}).values()
)
avg_sec = npu_det.avg_inference_speed.value
if total_fps > 0 and avg_sec > 0:
axelera_entry["npu"] = round(
min(100.0, total_fps * avg_sec * 100.0), 1
)
if axelera_entry is not None:
stats["axelera"] = axelera_entry
if stats:
all_stats["npu_usages"] = stats
@ -499,7 +522,7 @@ def stats_snapshot(
embeddings_metrics.classification_cps[key].value, 2
)
get_processing_stats(config, stats, hwaccel_errors)
get_processing_stats(config, stats, hwaccel_errors, stats_tracking)
stats["service"] = {
"uptime": (int(time.time()) - stats_tracking["started"]),