From 8295a0d11a22e85019f1c0c78a62d81ff38af5d9 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Fri, 29 Mar 2024 14:57:33 -0600 Subject: [PATCH] Get system graphs working for inference time --- frigate/stats/emitter.py | 5 +- web/src/components/graph/SystemGraph.tsx | 104 ++++++++++++++++------- web/src/pages/System.tsx | 76 ++++++++++++----- web/src/types/graph.ts | 20 +++++ 4 files changed, 151 insertions(+), 54 deletions(-) diff --git a/frigate/stats/emitter.py b/frigate/stats/emitter.py index 048436514..c35b2e595 100644 --- a/frigate/stats/emitter.py +++ b/frigate/stats/emitter.py @@ -14,6 +14,9 @@ from frigate.types import StatsTrackingTypes logger = logging.getLogger(__name__) +MAX_STATS_POINTS = 120 + + class StatsEmitter(threading.Thread): def __init__( self, @@ -55,7 +58,7 @@ class StatsEmitter(threading.Thread): self.config, self.stats_tracking, self.hwaccel_errors ) self.stats_history.append(stats) - self.stats_history = self.stats_history[-10:] + self.stats_history = self.stats_history[-MAX_STATS_POINTS:] self.requestor.send_data("stats", json.dumps(stats)) logger.debug("Finished stats collection") logger.info("Exiting stats emitter...") diff --git a/web/src/components/graph/SystemGraph.tsx b/web/src/components/graph/SystemGraph.tsx index dbc45ebf5..aa1e4cd26 100644 --- a/web/src/components/graph/SystemGraph.tsx +++ b/web/src/components/graph/SystemGraph.tsx @@ -1,54 +1,92 @@ +import { Threshold } from "@/types/graph"; +import { useMemo } from "react"; import Chart from "react-apexcharts"; type SystemGraphProps = { graphId: string; - title?: string; + name: string; unit: string; + threshold: Threshold; data: ApexAxisChartSeries; }; export default function SystemGraph({ graphId, - title, + name, unit, + threshold, data, }: SystemGraphProps) { + const lastValue = useMemo( + // @ts-expect-error y is valid + () => data[0].data[data[0].data.length - 1]?.y ?? 0, + [data], + ); + return ( - +
+
{name}
+
+ {lastValue} + {unit} +
+
+ { + if (value >= threshold.error) { + return "#FA5252"; + } else if (value >= threshold.warning) { + return "#aa00aa"; + } else { + return "#404040"; + } + }, + ], + grid: { show: false, }, - zoom: { + legend: { + show: false, + }, + dataLabels: { enabled: false, }, - }, - legend: { - show: true, - showForSingleSeries: true, - position: "top", - horizontalAlign: "left", - onItemClick: { - toggleDataSeries: true, + xaxis: { + type: "datetime", + axisBorder: { + show: false, + }, + axisTicks: { + show: false, + }, + labels: { + format: "h:mm", + datetimeUTC: false, + }, }, - }, - dataLabels: { - enabled: false, - }, - xaxis: { - type: "datetime", - }, - yaxis: { - show: false, - }, - }} - series={data} - height="120" - /> + yaxis: { + show: false, + max: lastValue * 2, + }, + }} + series={data} + height="120" + /> + ); } diff --git a/web/src/pages/System.tsx b/web/src/pages/System.tsx index f20ee319e..757264c05 100644 --- a/web/src/pages/System.tsx +++ b/web/src/pages/System.tsx @@ -1,4 +1,3 @@ -import Heading from "@/components/ui/heading"; import useSWR from "swr"; import { FrigateStats } from "@/types/stats"; import { useEffect, useMemo, useState } from "react"; @@ -6,11 +5,17 @@ import SystemGraph from "@/components/graph/SystemGraph"; import { useFrigateStats } from "@/api/ws"; import TimeAgo from "@/components/dynamic/TimeAgo"; import { FrigateConfig } from "@/types/frigateConfig"; +import { + DetectorCpuThreshold, + DetectorMemThreshold, + InferenceThreshold, +} from "@/types/graph"; function System() { const { data: config } = useSWR("config"); // stats + const { data: initialStats } = useSWR("stats/history", { revalidateOnFocus: false, }); @@ -42,9 +47,10 @@ function System() { } setStatsHistory([...statsHistory, updatedStats]); - }, [initialStats, updatedStats, statsHistory]); + }, [initialStats, updatedStats]); // stats data pieces + const detInferenceTimeSeries = useMemo(() => { if (!statsHistory) { return []; @@ -200,6 +206,10 @@ function System() { const statTime = new Date(stats.service.last_updated * 1000); Object.entries(stats.cameras).forEach(([key, camStats]) => { + if (!config?.cameras[key].enabled) { + return; + } + if (!(key in series)) { const camName = key.replaceAll("_", " "); series[key] = {}; @@ -210,11 +220,11 @@ function System() { series[key]["ffmpeg"].data.push({ x: statTime, - y: stats.cpu_usages[camStats.ffmpeg_pid.toString()].cpu, + y: stats.cpu_usages[camStats.ffmpeg_pid.toString()]?.cpu ?? 0.0, }); series[key]["capture"].data.push({ x: statTime, - y: stats.cpu_usages[camStats.capture_pid.toString()].cpu, + y: stats.cpu_usages[camStats.capture_pid?.toString()]?.cpu ?? 0, }); series[key]["detect"].data.push({ x: statTime, @@ -348,32 +358,45 @@ function System() { -
+
-
Inference Speed
+
Detector Inference Speed
{detInferenceTimeSeries.map((series) => ( ))}
-
- +
+
Detector CPU Usage
+ {detCpuSeries.map((series) => ( + + ))}
-
- +
+
Detector Memory Usage
+ {detMemSeries.map((series) => ( + + ))}
@@ -383,6 +406,19 @@ function System() { export default System; /** + *
+ +
+
+ +
+ * * Detectors