From bc2ad7f9bedb67cddd019288c1adce8ee427d726 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Mon, 7 Oct 2024 19:34:41 -0600 Subject: [PATCH] Implement GPU info for nvidia GPU --- web/src/components/overlay/GPUInfoDialog.tsx | 100 +++++++++++++++++++ web/src/components/overlay/VainfoDialog.tsx | 55 ---------- web/src/types/stats.ts | 11 ++ web/src/views/system/GeneralMetrics.tsx | 36 ++++--- 4 files changed, 135 insertions(+), 67 deletions(-) create mode 100644 web/src/components/overlay/GPUInfoDialog.tsx delete mode 100644 web/src/components/overlay/VainfoDialog.tsx diff --git a/web/src/components/overlay/GPUInfoDialog.tsx b/web/src/components/overlay/GPUInfoDialog.tsx new file mode 100644 index 000000000..90564ed4e --- /dev/null +++ b/web/src/components/overlay/GPUInfoDialog.tsx @@ -0,0 +1,100 @@ +import useSWR from "swr"; +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, +} from "../ui/dialog"; +import ActivityIndicator from "../indicators/activity-indicator"; +import { GpuInfo, Nvinfo, Vainfo } from "@/types/stats"; +import { Button } from "../ui/button"; +import copy from "copy-to-clipboard"; + +type GPUInfoDialogProps = { + showGpuInfo: boolean; + gpuType: GpuInfo; + setShowGpuInfo: (show: boolean) => void; +}; +export default function GPUInfoDialog({ + showGpuInfo, + gpuType, + setShowGpuInfo, +}: GPUInfoDialogProps) { + const { data: vainfo } = useSWR( + showGpuInfo && gpuType == "vainfo" ? "vainfo" : null, + ); + const { data: nvinfo } = useSWR( + showGpuInfo && gpuType == "nvinfo" ? "nvinfo" : null, + ); + + const onCopyInfo = async () => { + copy( + JSON.stringify(gpuType == "vainfo" ? vainfo : nvinfo).replace( + /[\\\s]+/gi, + "", + ), + ); + setShowGpuInfo(false); + }; + + if (gpuType == "vainfo") { + return ( + + + + Vainfo Output + + {vainfo ? ( +
+
Return Code: {vainfo.return_code}
+
+
Process {vainfo.return_code == 0 ? "Output" : "Error"}:
+
+
+ {vainfo.return_code == 0 ? vainfo.stdout : vainfo.stderr} +
+
+ ) : ( + + )} + + + + +
+
+ ); + } else { + return ( + + + + Nvidia SMI Output + + {nvinfo ? ( +
+
Name: {nvinfo["0"].name}
+
+
Driver: {nvinfo["0"].driver}
+
+
Cuda Compute Capability: {nvinfo["0"].cuda_compute}
+
+
VBios Info: {nvinfo["0"].vbios}
+
+ ) : ( + + )} + + + + +
+
+ ); + } +} diff --git a/web/src/components/overlay/VainfoDialog.tsx b/web/src/components/overlay/VainfoDialog.tsx deleted file mode 100644 index 74dec5ae3..000000000 --- a/web/src/components/overlay/VainfoDialog.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import useSWR from "swr"; -import { - Dialog, - DialogContent, - DialogFooter, - DialogHeader, - DialogTitle, -} from "../ui/dialog"; -import ActivityIndicator from "../indicators/activity-indicator"; -import { Vainfo } from "@/types/stats"; -import { Button } from "../ui/button"; -import copy from "copy-to-clipboard"; - -type VainfoDialogProps = { - showVainfo: boolean; - setShowVainfo: (show: boolean) => void; -}; -export default function VainfoDialog({ - showVainfo, - setShowVainfo, -}: VainfoDialogProps) { - const { data: vainfo } = useSWR(showVainfo ? "vainfo" : null); - - const onCopyVainfo = async () => { - copy(JSON.stringify(vainfo).replace(/[\\\s]+/gi, "")); - setShowVainfo(false); - }; - - return ( - - - - Vainfo Output - - {vainfo ? ( -
-
Return Code: {vainfo.return_code}
-
-
Process {vainfo.return_code == 0 ? "Output" : "Error"}:
-
-
{vainfo.return_code == 0 ? vainfo.stdout : vainfo.stderr}
-
- ) : ( - - )} - - - - -
-
- ); -} diff --git a/web/src/types/stats.ts b/web/src/types/stats.ts index 2affdc1e8..026cf0536 100644 --- a/web/src/types/stats.ts +++ b/web/src/types/stats.ts @@ -46,6 +46,8 @@ export type GpuStats = { pstate?: string; }; +export type GpuInfo = "vainfo" | "nvinfo"; + export type ServiceStats = { last_updated: number; storage: { [path: string]: StorageStats }; @@ -74,6 +76,15 @@ export type Vainfo = { stderr: string; }; +export type Nvinfo = { + [key: string]: { + name: string; + driver: string; + cuda_compute: string; + vbios: string; + }; +}; + export type Ffprobe = { return_code: number; stderr: string; diff --git a/web/src/views/system/GeneralMetrics.tsx b/web/src/views/system/GeneralMetrics.tsx index 2d63d9a83..87c979b36 100644 --- a/web/src/views/system/GeneralMetrics.tsx +++ b/web/src/views/system/GeneralMetrics.tsx @@ -1,5 +1,5 @@ import useSWR from "swr"; -import { FrigateStats } from "@/types/stats"; +import { FrigateStats, GpuInfo } from "@/types/stats"; import { useEffect, useMemo, useState } from "react"; import { useFrigateStats } from "@/api/ws"; import { @@ -11,7 +11,7 @@ import { InferenceThreshold, } from "@/types/graph"; import { Button } from "@/components/ui/button"; -import VainfoDialog from "@/components/overlay/VainfoDialog"; +import GPUInfoDialog from "@/components/overlay/GPUInfoDialog"; import { Skeleton } from "@/components/ui/skeleton"; import { ThresholdBarGraph } from "@/components/graph/SystemGraph"; import { cn } from "@/lib/utils"; @@ -63,15 +63,23 @@ export default function GeneralMetrics({ } }, [initialStats, updatedStats, statsHistory, lastUpdated, setLastUpdated]); - const canGetGpuInfo = useMemo( - () => - statsHistory.length > 0 && - Object.keys(statsHistory[0]?.gpu_usages ?? {}).filter( - (key) => - key == "amd-vaapi" || key == "intel-vaapi" || key == "intel-qsv", - ).length > 0, - [statsHistory], - ); + const [canGetGpuInfo, gpuType] = useMemo<[boolean, GpuInfo]>(() => { + let vaCount = 0; + let nvCount = 0; + + statsHistory.length > 0 && + Object.keys(statsHistory[0]?.gpu_usages ?? {}).forEach((key) => { + if (key == "amd-vaapi" || key == "intel-vaapi" || key == "intel-qsv") { + vaCount += 1; + } + + if (key.includes("NVIDIA")) { + nvCount += 1; + } + }); + + return [vaCount > 0 || nvCount > 0, nvCount > 0 ? "nvinfo" : "vainfo"]; + }, [statsHistory]); // timestamps @@ -432,7 +440,11 @@ export default function GeneralMetrics({ return ( <> - +