mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-07-14 16:01:13 +03:00
Handle case where GPU supports multiple engines
This commit is contained in:
parent
fcd05ec7bc
commit
9df6a5f902
@ -40,18 +40,18 @@ class TestGpuStats(unittest.TestCase):
|
|||||||
"driver": "i915",
|
"driver": "i915",
|
||||||
"pid": "100",
|
"pid": "100",
|
||||||
"engines": {
|
"engines": {
|
||||||
"render": (1_000_000_000, 0),
|
"render": (1_000_000_000, 0, 1),
|
||||||
"video": (5_000_000_000, 0),
|
"video": (5_000_000_000, 0, 1),
|
||||||
"video-enhance": (200_000_000, 0),
|
"video-enhance": (200_000_000, 0, 1),
|
||||||
"compute": (0, 0),
|
"compute": (0, 0, 1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
("0000:00:02.0", "2", "200"): {
|
("0000:00:02.0", "2", "200"): {
|
||||||
"driver": "i915",
|
"driver": "i915",
|
||||||
"pid": "200",
|
"pid": "200",
|
||||||
"engines": {
|
"engines": {
|
||||||
"render": (0, 0),
|
"render": (0, 0, 1),
|
||||||
"compute": (2_000_000_000, 0),
|
"compute": (2_000_000_000, 0, 1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -60,18 +60,18 @@ class TestGpuStats(unittest.TestCase):
|
|||||||
"driver": "i915",
|
"driver": "i915",
|
||||||
"pid": "100",
|
"pid": "100",
|
||||||
"engines": {
|
"engines": {
|
||||||
"render": (1_200_000_000, 0),
|
"render": (1_200_000_000, 0, 1),
|
||||||
"video": (5_500_000_000, 0),
|
"video": (5_500_000_000, 0, 1),
|
||||||
"video-enhance": (300_000_000, 0),
|
"video-enhance": (300_000_000, 0, 1),
|
||||||
"compute": (0, 0),
|
"compute": (0, 0, 1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
("0000:00:02.0", "2", "200"): {
|
("0000:00:02.0", "2", "200"): {
|
||||||
"driver": "i915",
|
"driver": "i915",
|
||||||
"pid": "200",
|
"pid": "200",
|
||||||
"engines": {
|
"engines": {
|
||||||
"render": (0, 0),
|
"render": (0, 0, 1),
|
||||||
"compute": (2_100_000_000, 0),
|
"compute": (2_100_000_000, 0, 1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -92,6 +92,64 @@ class TestGpuStats(unittest.TestCase):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@patch("frigate.stats.intel_gpu_info.intel_gpu_name_resolver.get_names")
|
||||||
|
@patch("frigate.util.services.time.sleep")
|
||||||
|
@patch("frigate.util.services.time.monotonic")
|
||||||
|
@patch("frigate.util.services._read_intel_drm_fdinfo")
|
||||||
|
def test_intel_gpu_stats_xe_capacity(
|
||||||
|
self, read_fdinfo, monotonic, sleep, get_names
|
||||||
|
):
|
||||||
|
# Xe engines report cumulative cycles paired with total cycles, plus a
|
||||||
|
# per-class capacity. drm-cycles-* is summed across every instance of a
|
||||||
|
# class, so on Battlemage (capacity 2 for vcs/vecs) busy/total must be
|
||||||
|
# divided by capacity to land in 0-100%.
|
||||||
|
monotonic.side_effect = [0.0, 1.0]
|
||||||
|
get_names.return_value = {"0000:03:00.0": "Intel Arc"}
|
||||||
|
|
||||||
|
# Deltas over the window (busy, total): render 200/1000 cap 1 = 20%,
|
||||||
|
# video 800/1000 cap 2 = 40%, video-enhance 400/1000 cap 2 = 20%,
|
||||||
|
# compute 100/1000 cap 1 = 10%. Without the capacity divisor video/
|
||||||
|
# video-enhance would read 80%/40% and dec would clamp at 100%.
|
||||||
|
snapshot_a = {
|
||||||
|
("0000:03:00.0", "1", "300"): {
|
||||||
|
"driver": "xe",
|
||||||
|
"pid": "300",
|
||||||
|
"engines": {
|
||||||
|
"render": (0, 0, 1),
|
||||||
|
"video": (0, 0, 2),
|
||||||
|
"video-enhance": (0, 0, 2),
|
||||||
|
"compute": (0, 0, 1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
snapshot_b = {
|
||||||
|
("0000:03:00.0", "1", "300"): {
|
||||||
|
"driver": "xe",
|
||||||
|
"pid": "300",
|
||||||
|
"engines": {
|
||||||
|
"render": (200, 1000, 1),
|
||||||
|
"video": (800, 1000, 2),
|
||||||
|
"video-enhance": (400, 1000, 2),
|
||||||
|
"compute": (100, 1000, 1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
read_fdinfo.side_effect = [snapshot_a, snapshot_b]
|
||||||
|
|
||||||
|
intel_stats = get_intel_gpu_stats(None)
|
||||||
|
|
||||||
|
assert intel_stats == {
|
||||||
|
"0000:03:00.0": {
|
||||||
|
"name": "Intel Arc",
|
||||||
|
"vendor": "intel",
|
||||||
|
"gpu": "90.0%",
|
||||||
|
"mem": "-%",
|
||||||
|
"compute": "30.0%",
|
||||||
|
"dec": "60.0%",
|
||||||
|
"clients": {"300": "90.0%"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
@patch("frigate.util.services._read_intel_drm_fdinfo")
|
@patch("frigate.util.services._read_intel_drm_fdinfo")
|
||||||
def test_intel_gpu_stats_no_clients(self, read_fdinfo):
|
def test_intel_gpu_stats_no_clients(self, read_fdinfo):
|
||||||
read_fdinfo.return_value = {}
|
read_fdinfo.return_value = {}
|
||||||
|
|||||||
@ -360,7 +360,7 @@ def _read_intel_drm_fdinfo(target_pdev: str | None) -> dict:
|
|||||||
if key in snapshot:
|
if key in snapshot:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
engines: dict[str, tuple[int, int]] = {}
|
engines: dict[str, tuple[int, int, int]] = {}
|
||||||
|
|
||||||
if driver == "i915":
|
if driver == "i915":
|
||||||
for fkey, engine in _I915_ENGINE_KEYS.items():
|
for fkey, engine in _I915_ENGINE_KEYS.items():
|
||||||
@ -368,19 +368,34 @@ def _read_intel_drm_fdinfo(target_pdev: str | None) -> dict:
|
|||||||
if not raw:
|
if not raw:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
engines[engine] = (int(raw.split()[0]), 0)
|
engines[engine] = (int(raw.split()[0]), 0, 1)
|
||||||
except (ValueError, IndexError):
|
except (ValueError, IndexError):
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
for suffix, engine in _XE_ENGINE_KEYS.items():
|
for suffix, engine in _XE_ENGINE_KEYS.items():
|
||||||
busy_raw = fields.get(f"drm-cycles-{suffix}")
|
busy_raw = fields.get(f"drm-cycles-{suffix}")
|
||||||
total_raw = fields.get(f"drm-total-cycles-{suffix}")
|
total_raw = fields.get(f"drm-total-cycles-{suffix}")
|
||||||
|
|
||||||
if not (busy_raw and total_raw):
|
if not (busy_raw and total_raw):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# drm-cycles-* is summed across every instance of the engine
|
||||||
|
# class while drm-total-cycles-* tracks a single instance, so
|
||||||
|
# busy/total scales up to the capacity (e.g. Battlemage
|
||||||
|
# reports 2 for vcs/vecs). Capture it to divide back out;
|
||||||
|
# absent means a single engine, so default to 1.
|
||||||
|
capacity_raw = fields.get(f"drm-engine-capacity-{suffix}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
capacity = int(capacity_raw.split()[0]) if capacity_raw else 1
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
capacity = 1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
engines[engine] = (
|
engines[engine] = (
|
||||||
int(busy_raw.split()[0]),
|
int(busy_raw.split()[0]),
|
||||||
int(total_raw.split()[0]),
|
int(total_raw.split()[0]),
|
||||||
|
max(1, capacity),
|
||||||
)
|
)
|
||||||
except (ValueError, IndexError):
|
except (ValueError, IndexError):
|
||||||
continue
|
continue
|
||||||
@ -450,11 +465,13 @@ def get_intel_gpu_stats(
|
|||||||
pid_pct = per_pdev_pid_pct.setdefault(pdev, {})
|
pid_pct = per_pdev_pid_pct.setdefault(pdev, {})
|
||||||
|
|
||||||
client_total = 0.0
|
client_total = 0.0
|
||||||
for engine, (busy_b, total_b) in data_b["engines"].items():
|
for engine, (busy_b, total_b, capacity) in data_b["engines"].items():
|
||||||
if engine not in engine_pct:
|
if engine not in engine_pct:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
busy_a, total_a = data_a["engines"].get(engine, (busy_b, total_b))
|
busy_a, total_a, _ = data_a["engines"].get(
|
||||||
|
engine, (busy_b, total_b, capacity)
|
||||||
|
)
|
||||||
|
|
||||||
if data_b["driver"] == "i915":
|
if data_b["driver"] == "i915":
|
||||||
delta = max(0, busy_b - busy_a)
|
delta = max(0, busy_b - busy_a)
|
||||||
@ -464,7 +481,9 @@ def get_intel_gpu_stats(
|
|||||||
delta_total = total_b - total_a
|
delta_total = total_b - total_a
|
||||||
if delta_total <= 0:
|
if delta_total <= 0:
|
||||||
continue
|
continue
|
||||||
pct = min(100.0, delta_busy / delta_total * 100.0)
|
# Normalize by capacity so a class with N engine instances
|
||||||
|
# (busy summed across all N) reports 0-100%, not 0-N*100%.
|
||||||
|
pct = min(100.0, delta_busy / (delta_total * capacity) * 100.0)
|
||||||
|
|
||||||
engine_pct[engine] += pct
|
engine_pct[engine] += pct
|
||||||
client_total += pct
|
client_total += pct
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user