mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-03 13:54:55 +03:00
More accurately label Intel stats
This commit is contained in:
parent
d03a24b8fe
commit
db066df2c4
@ -360,6 +360,11 @@ class CustomCollector(object):
|
|||||||
"GPU encoder utilisation %",
|
"GPU encoder utilisation %",
|
||||||
labels=["gpu_name"],
|
labels=["gpu_name"],
|
||||||
)
|
)
|
||||||
|
gpu_compute_usages = GaugeMetricFamily(
|
||||||
|
"frigate_gpu_compute_usage_percent",
|
||||||
|
"GPU compute / encode utilisation %",
|
||||||
|
labels=["gpu_name"],
|
||||||
|
)
|
||||||
gpu_dec_usages = GaugeMetricFamily(
|
gpu_dec_usages = GaugeMetricFamily(
|
||||||
"frigate_gpu_decoder_usage_percent",
|
"frigate_gpu_decoder_usage_percent",
|
||||||
"GPU decoder utilisation %",
|
"GPU decoder utilisation %",
|
||||||
@ -371,6 +376,9 @@ class CustomCollector(object):
|
|||||||
self.add_metric(gpu_usages, [gpu_name], gpu_stats, "gpu")
|
self.add_metric(gpu_usages, [gpu_name], gpu_stats, "gpu")
|
||||||
self.add_metric(gpu_mem_usages, [gpu_name], gpu_stats, "mem")
|
self.add_metric(gpu_mem_usages, [gpu_name], gpu_stats, "mem")
|
||||||
self.add_metric(gpu_enc_usages, [gpu_name], gpu_stats, "enc")
|
self.add_metric(gpu_enc_usages, [gpu_name], gpu_stats, "enc")
|
||||||
|
self.add_metric(
|
||||||
|
gpu_compute_usages, [gpu_name], gpu_stats, "compute"
|
||||||
|
)
|
||||||
self.add_metric(gpu_dec_usages, [gpu_name], gpu_stats, "dec")
|
self.add_metric(gpu_dec_usages, [gpu_name], gpu_stats, "dec")
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
@ -378,6 +386,7 @@ class CustomCollector(object):
|
|||||||
yield gpu_usages
|
yield gpu_usages
|
||||||
yield gpu_mem_usages
|
yield gpu_mem_usages
|
||||||
yield gpu_enc_usages
|
yield gpu_enc_usages
|
||||||
|
yield gpu_compute_usages
|
||||||
yield gpu_dec_usages
|
yield gpu_dec_usages
|
||||||
|
|
||||||
# service stats
|
# service stats
|
||||||
|
|||||||
@ -45,6 +45,6 @@ class TestGpuStats(unittest.TestCase):
|
|||||||
assert intel_stats == {
|
assert intel_stats == {
|
||||||
"gpu": "26.08%",
|
"gpu": "26.08%",
|
||||||
"mem": "-%",
|
"mem": "-%",
|
||||||
"enc": "0.0%",
|
"compute": "0.0%",
|
||||||
"dec": "2.27%",
|
"dec": "2.27%",
|
||||||
}
|
}
|
||||||
|
|||||||
@ -296,7 +296,7 @@ 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:
|
||||||
results["enc"] = f"{round(sum(render) / len(render), 2)}%"
|
results["compute"] = f"{round(sum(render) / len(render), 2)}%"
|
||||||
|
|
||||||
# Video engines are the fixed-function decode engines
|
# Video engines are the fixed-function decode engines
|
||||||
video = []
|
video = []
|
||||||
@ -395,9 +395,9 @@ def get_intel_gpu_stats(intel_gpu_device: Optional[str]) -> Optional[dict[str, s
|
|||||||
|
|
||||||
results["mem"] = "-%"
|
results["mem"] = "-%"
|
||||||
|
|
||||||
# Encoder: Render/3D engine (compute/shader encode)
|
# Compute: Render/3D engine (compute/shader workloads and QSV encode)
|
||||||
if render_global:
|
if render_global:
|
||||||
results["enc"] = f"{round(sum(render_global) / len(render_global), 2)}%"
|
results["compute"] = f"{round(sum(render_global) / len(render_global), 2)}%"
|
||||||
|
|
||||||
# Decoder: Video engine (fixed-function codec)
|
# Decoder: Video engine (fixed-function codec)
|
||||||
if video_global:
|
if video_global:
|
||||||
|
|||||||
@ -78,6 +78,7 @@
|
|||||||
"gpuUsage": "GPU Usage",
|
"gpuUsage": "GPU Usage",
|
||||||
"gpuMemory": "GPU Memory",
|
"gpuMemory": "GPU Memory",
|
||||||
"gpuEncoder": "GPU Encoder",
|
"gpuEncoder": "GPU Encoder",
|
||||||
|
"gpuCompute": "GPU Compute / Encode",
|
||||||
"gpuDecoder": "GPU Decoder",
|
"gpuDecoder": "GPU Decoder",
|
||||||
"gpuTemperature": "GPU Temperature",
|
"gpuTemperature": "GPU Temperature",
|
||||||
"gpuInfo": {
|
"gpuInfo": {
|
||||||
@ -188,6 +189,7 @@
|
|||||||
"cameraFfmpeg": "{{camName}} FFmpeg",
|
"cameraFfmpeg": "{{camName}} FFmpeg",
|
||||||
"cameraCapture": "{{camName}} capture",
|
"cameraCapture": "{{camName}} capture",
|
||||||
"cameraDetect": "{{camName}} detect",
|
"cameraDetect": "{{camName}} detect",
|
||||||
|
"cameraGpu": "{{camName}} GPU",
|
||||||
"cameraFramesPerSecond": "{{camName}} frames per second",
|
"cameraFramesPerSecond": "{{camName}} frames per second",
|
||||||
"cameraDetectionsPerSecond": "{{camName}} detections per second",
|
"cameraDetectionsPerSecond": "{{camName}} detections per second",
|
||||||
"cameraSkippedDetectionsPerSecond": "{{camName}} skipped detections per second"
|
"cameraSkippedDetectionsPerSecond": "{{camName}} skipped detections per second"
|
||||||
|
|||||||
@ -60,8 +60,10 @@ export type GpuStats = {
|
|||||||
mem: string;
|
mem: string;
|
||||||
enc?: string;
|
enc?: string;
|
||||||
dec?: string;
|
dec?: string;
|
||||||
|
compute?: string;
|
||||||
pstate?: string;
|
pstate?: string;
|
||||||
temp?: number;
|
temp?: number;
|
||||||
|
clients?: { [pid: string]: string };
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NpuStats = {
|
export type NpuStats = {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { CameraLineGraph } from "@/components/graph/LineGraph";
|
|||||||
import CameraInfoDialog from "@/components/overlay/CameraInfoDialog";
|
import CameraInfoDialog from "@/components/overlay/CameraInfoDialog";
|
||||||
import { ConnectionQualityIndicator } from "@/components/camera/ConnectionQualityIndicator";
|
import { ConnectionQualityIndicator } from "@/components/camera/ConnectionQualityIndicator";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import { FrigateStats } from "@/types/stats";
|
import { FrigateStats } from "@/types/stats";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
@ -43,7 +44,7 @@ export default function CameraMetrics({
|
|||||||
[
|
[
|
||||||
"stats/history",
|
"stats/history",
|
||||||
{
|
{
|
||||||
keys: "cpu_usages,cameras,camera_fps,detection_fps,skipped_fps,service",
|
keys: "cpu_usages,gpu_usages,cameras,camera_fps,detection_fps,skipped_fps,service",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
@ -183,6 +184,64 @@ export default function CameraMetrics({
|
|||||||
return series;
|
return series;
|
||||||
}, [config, getCameraName, statsHistory, t]);
|
}, [config, getCameraName, statsHistory, t]);
|
||||||
|
|
||||||
|
const cameraGpuSeries = useMemo(() => {
|
||||||
|
if (!statsHistory || statsHistory.length == 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find GPU entry with per-client data
|
||||||
|
const firstGpu = statsHistory.find((s) => s?.gpu_usages);
|
||||||
|
if (!firstGpu?.gpu_usages) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const gpuWithClients = Object.values(firstGpu.gpu_usages).find(
|
||||||
|
(g) => g.clients,
|
||||||
|
);
|
||||||
|
if (!gpuWithClients) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const series: {
|
||||||
|
[cam: string]: {
|
||||||
|
[key: string]: { name: string; data: { x: number; y: string }[] };
|
||||||
|
};
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
statsHistory.forEach((stats, statsIdx) => {
|
||||||
|
if (!stats) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gpuClients = Object.values(stats.gpu_usages || {}).find(
|
||||||
|
(g) => g.clients,
|
||||||
|
)?.clients;
|
||||||
|
|
||||||
|
Object.entries(stats.cameras).forEach(([key, camStats]) => {
|
||||||
|
if (!config?.cameras[key].enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(key in series)) {
|
||||||
|
const camName = getCameraName(key);
|
||||||
|
series[key] = {};
|
||||||
|
series[key]["gpu"] = {
|
||||||
|
name: t("cameras.label.cameraGpu", { camName: camName }),
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const pid = camStats.ffmpeg_pid?.toString();
|
||||||
|
series[key]["gpu"].data.push({
|
||||||
|
x: statsIdx,
|
||||||
|
y: (gpuClients && pid ? gpuClients[pid] : undefined)
|
||||||
|
?.slice(0, -1) ?? "0",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return series;
|
||||||
|
}, [config, getCameraName, statsHistory, t]);
|
||||||
|
|
||||||
const cameraFpsSeries = useMemo(() => {
|
const cameraFpsSeries = useMemo(() => {
|
||||||
if (!statsHistory) {
|
if (!statsHistory) {
|
||||||
return {};
|
return {};
|
||||||
@ -332,7 +391,11 @@ export default function CameraMetrics({
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
key={camera.name}
|
key={camera.name}
|
||||||
className="grid gap-2 sm:grid-cols-2"
|
className={cn(
|
||||||
|
"grid gap-2 sm:grid-cols-2",
|
||||||
|
Object.keys(cameraGpuSeries).length > 0 &&
|
||||||
|
"lg:grid-cols-3",
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{Object.keys(cameraCpuSeries).includes(camera.name) ? (
|
{Object.keys(cameraCpuSeries).includes(camera.name) ? (
|
||||||
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||||
@ -350,6 +413,20 @@ export default function CameraMetrics({
|
|||||||
) : (
|
) : (
|
||||||
<Skeleton className="aspect-video size-full" />
|
<Skeleton className="aspect-video size-full" />
|
||||||
)}
|
)}
|
||||||
|
{Object.keys(cameraGpuSeries).includes(camera.name) && (
|
||||||
|
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||||
|
<div className="mb-5">GPU</div>
|
||||||
|
<CameraLineGraph
|
||||||
|
graphId={`${camera.name}-gpu`}
|
||||||
|
unit="%"
|
||||||
|
dataLabels={["gpu"]}
|
||||||
|
updateTimes={updateTimes}
|
||||||
|
data={Object.values(
|
||||||
|
cameraGpuSeries[camera.name] || {},
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{Object.keys(cameraFpsSeries).includes(camera.name) ? (
|
{Object.keys(cameraFpsSeries).includes(camera.name) ? (
|
||||||
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||||
<div className="mb-5">
|
<div className="mb-5">
|
||||||
|
|||||||
@ -334,6 +334,43 @@ export default function GeneralMetrics({
|
|||||||
return Object.keys(series).length > 0 ? Object.values(series) : undefined;
|
return Object.keys(series).length > 0 ? Object.values(series) : undefined;
|
||||||
}, [statsHistory]);
|
}, [statsHistory]);
|
||||||
|
|
||||||
|
const gpuComputeSeries = useMemo(() => {
|
||||||
|
if (!statsHistory) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const series: {
|
||||||
|
[key: string]: { name: string; data: { x: number; y: string }[] };
|
||||||
|
} = {};
|
||||||
|
let hasValidGpu = false;
|
||||||
|
|
||||||
|
statsHistory.forEach((stats, statsIdx) => {
|
||||||
|
if (!stats) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.entries(stats.gpu_usages || {}).forEach(([key, stats]) => {
|
||||||
|
if (!(key in series)) {
|
||||||
|
series[key] = { name: key, data: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.compute) {
|
||||||
|
hasValidGpu = true;
|
||||||
|
series[key].data.push({
|
||||||
|
x: statsIdx + 1,
|
||||||
|
y: stats.compute.slice(0, -1),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hasValidGpu) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.keys(series).length > 0 ? Object.values(series) : undefined;
|
||||||
|
}, [statsHistory]);
|
||||||
|
|
||||||
const gpuDecSeries = useMemo(() => {
|
const gpuDecSeries = useMemo(() => {
|
||||||
if (!statsHistory) {
|
if (!statsHistory) {
|
||||||
return [];
|
return [];
|
||||||
@ -742,8 +779,9 @@ export default function GeneralMetrics({
|
|||||||
className={cn(
|
className={cn(
|
||||||
"mt-4 grid grid-cols-1 gap-2 sm:grid-cols-2",
|
"mt-4 grid grid-cols-1 gap-2 sm:grid-cols-2",
|
||||||
gpuTempSeries?.length && "md:grid-cols-3",
|
gpuTempSeries?.length && "md:grid-cols-3",
|
||||||
gpuEncSeries?.length && "xl:grid-cols-4",
|
(gpuEncSeries?.length || gpuComputeSeries?.length) &&
|
||||||
gpuEncSeries?.length &&
|
"xl:grid-cols-4",
|
||||||
|
(gpuEncSeries?.length || gpuComputeSeries?.length) &&
|
||||||
gpuTempSeries?.length &&
|
gpuTempSeries?.length &&
|
||||||
"3xl:grid-cols-5",
|
"3xl:grid-cols-5",
|
||||||
)}
|
)}
|
||||||
@ -856,6 +894,30 @@ export default function GeneralMetrics({
|
|||||||
) : (
|
) : (
|
||||||
<Skeleton className="aspect-video w-full" />
|
<Skeleton className="aspect-video w-full" />
|
||||||
)}
|
)}
|
||||||
|
{statsHistory.length != 0 ? (
|
||||||
|
<>
|
||||||
|
{gpuComputeSeries && gpuComputeSeries?.length != 0 && (
|
||||||
|
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||||
|
<div className="mb-5">
|
||||||
|
{t("general.hardwareInfo.gpuCompute")}
|
||||||
|
</div>
|
||||||
|
{gpuComputeSeries.map((series) => (
|
||||||
|
<ThresholdBarGraph
|
||||||
|
key={series.name}
|
||||||
|
graphId={`${series.name}-compute`}
|
||||||
|
unit="%"
|
||||||
|
name={series.name}
|
||||||
|
threshold={GPUMemThreshold}
|
||||||
|
updateTimes={updateTimes}
|
||||||
|
data={[series]}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Skeleton className="aspect-video w-full" />
|
||||||
|
)}
|
||||||
{statsHistory.length != 0 ? (
|
{statsHistory.length != 0 ? (
|
||||||
<>
|
<>
|
||||||
{gpuDecSeries && gpuDecSeries?.length != 0 && (
|
{gpuDecSeries && gpuDecSeries?.length != 0 && (
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user