mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-03 13:54:55 +03:00
Improve Intel stats collection
This commit is contained in:
parent
c35cee2d2f
commit
3835e7649c
@ -261,45 +261,33 @@ async def set_gpu_stats(
|
|||||||
else:
|
else:
|
||||||
stats["jetson-gpu"] = {"gpu": "", "mem": ""}
|
stats["jetson-gpu"] = {"gpu": "", "mem": ""}
|
||||||
hwaccel_errors.append(args)
|
hwaccel_errors.append(args)
|
||||||
elif "qsv" in args:
|
elif "qsv" in args or ("vaapi" in args and not is_vaapi_amd_driver()):
|
||||||
if not config.telemetry.stats.intel_gpu_stats:
|
if not config.telemetry.stats.intel_gpu_stats:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# intel QSV GPU
|
if "intel-gpu" not in stats:
|
||||||
intel_usage = get_intel_gpu_stats(config.telemetry.stats.intel_gpu_device)
|
# intel GPU (QSV or VAAPI both use the same physical GPU)
|
||||||
|
|
||||||
if intel_usage is not None:
|
|
||||||
stats["intel-qsv"] = intel_usage or {"gpu": "", "mem": ""}
|
|
||||||
else:
|
|
||||||
stats["intel-qsv"] = {"gpu": "", "mem": ""}
|
|
||||||
hwaccel_errors.append(args)
|
|
||||||
elif "vaapi" in args:
|
|
||||||
if is_vaapi_amd_driver():
|
|
||||||
if not config.telemetry.stats.amd_gpu_stats:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# AMD VAAPI GPU
|
|
||||||
amd_usage = get_amd_gpu_stats()
|
|
||||||
|
|
||||||
if amd_usage:
|
|
||||||
stats["amd-vaapi"] = amd_usage
|
|
||||||
else:
|
|
||||||
stats["amd-vaapi"] = {"gpu": "", "mem": ""}
|
|
||||||
hwaccel_errors.append(args)
|
|
||||||
else:
|
|
||||||
if not config.telemetry.stats.intel_gpu_stats:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# intel VAAPI GPU
|
|
||||||
intel_usage = get_intel_gpu_stats(
|
intel_usage = get_intel_gpu_stats(
|
||||||
config.telemetry.stats.intel_gpu_device
|
config.telemetry.stats.intel_gpu_device
|
||||||
)
|
)
|
||||||
|
|
||||||
if intel_usage is not None:
|
if intel_usage is not None:
|
||||||
stats["intel-vaapi"] = intel_usage or {"gpu": "", "mem": ""}
|
stats["intel-gpu"] = intel_usage or {"gpu": "", "mem": ""}
|
||||||
else:
|
else:
|
||||||
stats["intel-vaapi"] = {"gpu": "", "mem": ""}
|
stats["intel-gpu"] = {"gpu": "", "mem": ""}
|
||||||
hwaccel_errors.append(args)
|
hwaccel_errors.append(args)
|
||||||
|
elif "vaapi" in args:
|
||||||
|
if not config.telemetry.stats.amd_gpu_stats:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# AMD VAAPI GPU
|
||||||
|
amd_usage = get_amd_gpu_stats()
|
||||||
|
|
||||||
|
if amd_usage:
|
||||||
|
stats["amd-vaapi"] = amd_usage
|
||||||
|
else:
|
||||||
|
stats["amd-vaapi"] = {"gpu": "", "mem": ""}
|
||||||
|
hwaccel_errors.append(args)
|
||||||
elif "preset-rk" in args:
|
elif "preset-rk" in args:
|
||||||
rga_usage = get_rockchip_gpu_stats()
|
rga_usage = get_rockchip_gpu_stats()
|
||||||
|
|
||||||
|
|||||||
@ -39,8 +39,12 @@ class TestGpuStats(unittest.TestCase):
|
|||||||
process.stdout = self.intel_results
|
process.stdout = self.intel_results
|
||||||
sp.return_value = process
|
sp.return_value = process
|
||||||
intel_stats = get_intel_gpu_stats(False)
|
intel_stats = get_intel_gpu_stats(False)
|
||||||
print(f"the intel stats are {intel_stats}")
|
# rc6 values: 47.844741 and 100.0 → avg 73.92 → gpu = 100 - 73.92 = 26.08%
|
||||||
|
# Render/3D/0: 0.0 and 0.0 → enc = 0.0%
|
||||||
|
# Video/0: 4.533124 and 0.0 → dec = 2.27%
|
||||||
assert intel_stats == {
|
assert intel_stats == {
|
||||||
"gpu": "1.13%",
|
"gpu": "26.08%",
|
||||||
"mem": "-%",
|
"mem": "-%",
|
||||||
|
"enc": "0.0%",
|
||||||
|
"dec": "2.27%",
|
||||||
}
|
}
|
||||||
|
|||||||
@ -265,14 +265,30 @@ def get_amd_gpu_stats() -> Optional[dict[str, str]]:
|
|||||||
|
|
||||||
|
|
||||||
def get_intel_gpu_stats(intel_gpu_device: Optional[str]) -> Optional[dict[str, str]]:
|
def get_intel_gpu_stats(intel_gpu_device: Optional[str]) -> Optional[dict[str, str]]:
|
||||||
"""Get stats using intel_gpu_top."""
|
"""Get stats using intel_gpu_top.
|
||||||
|
|
||||||
|
Returns overall GPU usage derived from rc6 residency (idle time),
|
||||||
|
plus individual engine breakdowns:
|
||||||
|
- enc: Render/3D engine (compute/shader encoder, used by QSV)
|
||||||
|
- dec: Video engines (fixed-function codec, used by VAAPI)
|
||||||
|
"""
|
||||||
|
|
||||||
def get_stats_manually(output: str) -> dict[str, str]:
|
def get_stats_manually(output: str) -> dict[str, str]:
|
||||||
"""Find global stats via regex when json fails to parse."""
|
"""Find global stats via regex when json fails to parse."""
|
||||||
reading = "".join(output)
|
reading = "".join(output)
|
||||||
results: dict[str, str] = {}
|
results: dict[str, str] = {}
|
||||||
|
|
||||||
# render is used for qsv
|
# rc6 residency for overall GPU usage
|
||||||
|
rc6_match = re.search(r'"rc6":\{"value":([\d.]+)', reading)
|
||||||
|
if rc6_match:
|
||||||
|
rc6_value = float(rc6_match.group(1))
|
||||||
|
results["gpu"] = f"{round(100.0 - rc6_value, 2)}%"
|
||||||
|
else:
|
||||||
|
results["gpu"] = "-%"
|
||||||
|
|
||||||
|
results["mem"] = "-%"
|
||||||
|
|
||||||
|
# Render/3D is the compute/encode engine
|
||||||
render = []
|
render = []
|
||||||
for result in re.findall(r'"Render/3D/0":{[a-z":\d.,%]+}', reading):
|
for result in re.findall(r'"Render/3D/0":{[a-z":\d.,%]+}', reading):
|
||||||
packet = json.loads(result[14:])
|
packet = json.loads(result[14:])
|
||||||
@ -280,11 +296,9 @@ def get_intel_gpu_stats(intel_gpu_device: Optional[str]) -> Optional[dict[str, s
|
|||||||
render.append(float(single))
|
render.append(float(single))
|
||||||
|
|
||||||
if render:
|
if render:
|
||||||
render_avg = sum(render) / len(render)
|
results["enc"] = f"{round(sum(render) / len(render), 2)}%"
|
||||||
else:
|
|
||||||
render_avg = 1
|
|
||||||
|
|
||||||
# video is used for vaapi
|
# Video engines are the fixed-function decode engines
|
||||||
video = []
|
video = []
|
||||||
for result in re.findall(r'"Video/\d":{[a-z":\d.,%]+}', reading):
|
for result in re.findall(r'"Video/\d":{[a-z":\d.,%]+}', reading):
|
||||||
packet = json.loads(result[10:])
|
packet = json.loads(result[10:])
|
||||||
@ -292,12 +306,8 @@ def get_intel_gpu_stats(intel_gpu_device: Optional[str]) -> Optional[dict[str, s
|
|||||||
video.append(float(single))
|
video.append(float(single))
|
||||||
|
|
||||||
if video:
|
if video:
|
||||||
video_avg = sum(video) / len(video)
|
results["dec"] = f"{round(sum(video) / len(video), 2)}%"
|
||||||
else:
|
|
||||||
video_avg = 1
|
|
||||||
|
|
||||||
results["gpu"] = f"{round((video_avg + render_avg) / 2, 2)}%"
|
|
||||||
results["mem"] = "-%"
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
intel_gpu_top_command = [
|
intel_gpu_top_command = [
|
||||||
@ -336,10 +346,16 @@ def get_intel_gpu_stats(intel_gpu_device: Optional[str]) -> Optional[dict[str, s
|
|||||||
return get_stats_manually(output)
|
return get_stats_manually(output)
|
||||||
|
|
||||||
results: dict[str, str] = {}
|
results: dict[str, str] = {}
|
||||||
|
rc6_values = []
|
||||||
render = {"global": []}
|
render = {"global": []}
|
||||||
video = {"global": []}
|
video = {"global": []}
|
||||||
|
|
||||||
for block in data:
|
for block in data:
|
||||||
|
# rc6 residency: percentage of time GPU is idle
|
||||||
|
rc6 = block.get("rc6", {}).get("value")
|
||||||
|
if rc6 is not None:
|
||||||
|
rc6_values.append(float(rc6))
|
||||||
|
|
||||||
global_engine = block.get("engines")
|
global_engine = block.get("engines")
|
||||||
|
|
||||||
if global_engine:
|
if global_engine:
|
||||||
@ -373,11 +389,22 @@ def get_intel_gpu_stats(intel_gpu_device: Optional[str]) -> Optional[dict[str, s
|
|||||||
if video_frame is not None:
|
if video_frame is not None:
|
||||||
video[key].append(float(video_frame))
|
video[key].append(float(video_frame))
|
||||||
|
|
||||||
if render["global"] and video["global"]:
|
# Overall GPU usage from rc6 (idle) residency
|
||||||
results["gpu"] = (
|
if rc6_values:
|
||||||
f"{round(((sum(render['global']) / len(render['global'])) + (sum(video['global']) / len(video['global']))) / 2, 2)}%"
|
rc6_avg = sum(rc6_values) / len(rc6_values)
|
||||||
|
results["gpu"] = f"{round(100.0 - rc6_avg, 2)}%"
|
||||||
|
|
||||||
|
results["mem"] = "-%"
|
||||||
|
|
||||||
|
# Encoder: Render/3D engine (compute/shader encode)
|
||||||
|
if render["global"]:
|
||||||
|
results["enc"] = (
|
||||||
|
f"{round(sum(render['global']) / len(render['global']), 2)}%"
|
||||||
)
|
)
|
||||||
results["mem"] = "-%"
|
|
||||||
|
# Decoder: Video engine (fixed-function codec)
|
||||||
|
if video["global"]:
|
||||||
|
results["dec"] = f"{round(sum(video['global']) / len(video['global']), 2)}%"
|
||||||
|
|
||||||
if len(render.keys()) > 1:
|
if len(render.keys()) > 1:
|
||||||
results["clients"] = {}
|
results["clients"] = {}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user