mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-11 05:35:25 +03:00
Reorganize stats and show graphs in system metrics
This commit is contained in:
parent
483d64e419
commit
ba98d491ae
58
web/src/components/graph/SystemGraph.tsx
Normal file
58
web/src/components/graph/SystemGraph.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import Chart from "react-apexcharts";
|
||||||
|
|
||||||
|
type SystemGraphProps = {
|
||||||
|
graphId: string;
|
||||||
|
title: string;
|
||||||
|
unit: string;
|
||||||
|
data: ApexAxisChartSeries;
|
||||||
|
};
|
||||||
|
export default function SystemGraph({
|
||||||
|
graphId,
|
||||||
|
title,
|
||||||
|
unit,
|
||||||
|
data,
|
||||||
|
}: SystemGraphProps) {
|
||||||
|
return (
|
||||||
|
<Chart
|
||||||
|
type="line"
|
||||||
|
options={{
|
||||||
|
chart: {
|
||||||
|
id: graphId,
|
||||||
|
selection: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
toolbar: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
zoom: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
show: true,
|
||||||
|
showForSingleSeries: true,
|
||||||
|
position: "top",
|
||||||
|
onItemClick: {
|
||||||
|
toggleDataSeries: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: title,
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
type: "datetime",
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
tickAmount: 3,
|
||||||
|
labels: {
|
||||||
|
formatter: (value) => {
|
||||||
|
return `${value.toFixed(2)} ${unit}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
series={data}
|
||||||
|
height="100%"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,9 +1,222 @@
|
|||||||
import Heading from "@/components/ui/heading";
|
import Heading from "@/components/ui/heading";
|
||||||
|
import useSWR from "swr";
|
||||||
|
import { FrigateStats } from "@/types/stats";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import SystemGraph from "@/components/graph/SystemGraph";
|
||||||
|
|
||||||
function System() {
|
function System() {
|
||||||
|
// stats
|
||||||
|
const { data: statsHistory } = useSWR<FrigateStats[]>("stats/history", {
|
||||||
|
revalidateOnFocus: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// stats data pieces
|
||||||
|
const inferenceTimeSeries = useMemo(() => {
|
||||||
|
if (!statsHistory) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const series: {
|
||||||
|
[key: string]: { name: string; data: { x: any; y: any }[] };
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
statsHistory.forEach((stats) => {
|
||||||
|
const statTime = new Date(stats.service.last_updated * 1000);
|
||||||
|
|
||||||
|
Object.entries(stats.detectors).forEach(([key, stats]) => {
|
||||||
|
if (!(key in series)) {
|
||||||
|
series[key] = { name: `${key} (${stats.pid})`, data: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
series[key].data.push({ x: statTime, y: stats.inference_speed });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return Object.values(series);
|
||||||
|
}, [statsHistory]);
|
||||||
|
const cpuMemSeries = useMemo(() => {
|
||||||
|
if (!statsHistory) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const series: {
|
||||||
|
[key: string]: { name: string; data: { x: any; y: any }[] };
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
statsHistory.forEach((stats) => {
|
||||||
|
const statTime = new Date(stats.service.last_updated * 1000);
|
||||||
|
|
||||||
|
Object.entries(stats.detectors).forEach(([key, detectorStats]) => {
|
||||||
|
const cpuKey = `${key}-cpu`;
|
||||||
|
const memKey = `${key}-mem`;
|
||||||
|
|
||||||
|
if (!(cpuKey in series)) {
|
||||||
|
series[cpuKey] = { name: `${key} Cpu`, data: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(memKey in series)) {
|
||||||
|
series[memKey] = { name: `${key} Memory`, data: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const detUsages = stats.cpu_usages[detectorStats.pid.toString()];
|
||||||
|
|
||||||
|
series[cpuKey].data.push({ x: statTime, y: detUsages.cpu });
|
||||||
|
series[memKey].data.push({ x: statTime, y: detUsages.mem });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return Object.values(series);
|
||||||
|
}, [statsHistory]);
|
||||||
|
const gpuSeries = useMemo(() => {
|
||||||
|
if (!statsHistory) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const series: {
|
||||||
|
[key: string]: { name: string; data: { x: any; y: any }[] };
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
statsHistory.forEach((stats) => {
|
||||||
|
const statTime = new Date(stats.service.last_updated * 1000);
|
||||||
|
|
||||||
|
Object.entries(stats.gpu_usages || []).forEach(([key, stats]) => {
|
||||||
|
if (!(key in series)) {
|
||||||
|
series[key] = { name: key, data: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
series[key].data.push({ x: statTime, y: stats.gpu });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return Object.keys(series).length > 0 ? Object.values(series) : [];
|
||||||
|
}, [statsHistory]);
|
||||||
|
const gpuMemSeries = useMemo(() => {
|
||||||
|
if (!statsHistory) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const series: {
|
||||||
|
[key: string]: { name: string; data: { x: any; y: any }[] };
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
statsHistory.forEach((stats) => {
|
||||||
|
const statTime = new Date(stats.service.last_updated * 1000);
|
||||||
|
|
||||||
|
Object.entries(stats.gpu_usages || {}).forEach(([key, stats]) => {
|
||||||
|
if (!(key in series)) {
|
||||||
|
series[key] = { name: key, data: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
series[key].data.push({ x: statTime, y: stats.mem });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return Object.values(series);
|
||||||
|
}, [statsHistory]);
|
||||||
|
const otherProcessCpuSeries = useMemo(() => {
|
||||||
|
if (!statsHistory) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const series: {
|
||||||
|
[key: string]: { name: string; data: { x: any; y: any }[] };
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
statsHistory.forEach((stats) => {
|
||||||
|
const statTime = new Date(stats.service.last_updated * 1000);
|
||||||
|
|
||||||
|
Object.entries(stats.processes).forEach(([key, procStats]) => {
|
||||||
|
if (procStats.pid.toString() in stats.cpu_usages) {
|
||||||
|
if (!(key in series)) {
|
||||||
|
series[key] = { name: `${key} (${procStats.pid})`, data: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
series[key].data.push({
|
||||||
|
x: statTime,
|
||||||
|
y: stats.cpu_usages[procStats.pid.toString()].cpu,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return Object.keys(series).length > 0 ? Object.values(series) : [];
|
||||||
|
}, [statsHistory]);
|
||||||
|
const otherProcessMemSeries = useMemo(() => {
|
||||||
|
if (!statsHistory) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const series: {
|
||||||
|
[key: string]: { name: string; data: { x: any; y: any }[] };
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
statsHistory.forEach((stats) => {
|
||||||
|
const statTime = new Date(stats.service.last_updated * 1000);
|
||||||
|
|
||||||
|
Object.entries(stats.processes).forEach(([key, procStats]) => {
|
||||||
|
if (procStats.pid.toString() in stats.cpu_usages) {
|
||||||
|
if (!(key in series)) {
|
||||||
|
series[key] = { name: key, data: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
series[key].data.push({
|
||||||
|
x: statTime,
|
||||||
|
y: stats.cpu_usages[procStats.pid.toString()].mem,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return Object.values(series);
|
||||||
|
}, [statsHistory]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Heading as="h2">System</Heading>
|
<Heading as="h2">System</Heading>
|
||||||
|
|
||||||
|
<Heading as="h4">Detectors</Heading>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2">
|
||||||
|
<SystemGraph
|
||||||
|
graphId="detector-inference"
|
||||||
|
title="Inference Speed"
|
||||||
|
unit="ms"
|
||||||
|
data={inferenceTimeSeries}
|
||||||
|
/>
|
||||||
|
<SystemGraph
|
||||||
|
graphId="detector-usages"
|
||||||
|
title="CPU / Memory"
|
||||||
|
unit="%"
|
||||||
|
data={cpuMemSeries}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{gpuSeries.length > 0 && (
|
||||||
|
<>
|
||||||
|
<Heading as="h4">GPUs</Heading>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2">
|
||||||
|
<SystemGraph
|
||||||
|
graphId="detector-inference"
|
||||||
|
title="GPU Usage"
|
||||||
|
unit="%"
|
||||||
|
data={gpuSeries}
|
||||||
|
/>
|
||||||
|
<SystemGraph
|
||||||
|
graphId="detector-usages"
|
||||||
|
title="GPU Memory"
|
||||||
|
unit="%"
|
||||||
|
data={gpuMemSeries}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<Heading as="h4">Other Processes</Heading>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2">
|
||||||
|
<SystemGraph
|
||||||
|
graphId="process-cpu"
|
||||||
|
title="CPU"
|
||||||
|
unit="%"
|
||||||
|
data={otherProcessCpuSeries}
|
||||||
|
/>
|
||||||
|
<SystemGraph
|
||||||
|
graphId="process-mem"
|
||||||
|
title="Memory"
|
||||||
|
unit="%"
|
||||||
|
data={otherProcessMemSeries}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user