feat: display peak GPU usage in dashboard

This commit is contained in:
henrygd
2025-02-08 19:22:00 -05:00
parent e6054058b9
commit 3afab00937
4 changed files with 42 additions and 19 deletions

View File

@@ -185,8 +185,12 @@ func (a *Agent) getSystemStats() system.Stats {
// GPU data
if a.gpuManager != nil {
// reset high gpu percent
a.systemInfo.GpuPct = 0
// get current GPU data
if gpuData := a.gpuManager.GetCurrentData(); len(gpuData) > 0 {
systemStats.GPUData = gpuData
// add temperatures
if systemStats.Temperatures == nil {
systemStats.Temperatures = make(map[string]float64, len(gpuData))
@@ -195,6 +199,8 @@ func (a *Agent) getSystemStats() system.Stats {
if gpu.Temperature > 0 {
systemStats.Temperatures[gpu.Name] = gpu.Temperature
}
// update high gpu percent for dashboard
a.systemInfo.GpuPct = max(a.systemInfo.GpuPct, gpu.Usage)
}
}
}
@@ -249,10 +255,7 @@ func (a *Agent) updateTemperatures(systemStats *system.Stats) error {
continue
}
}
// assign high temperature if sensor temp is higher than a.systemInfo.HighTemp
if sensor.Temperature > a.systemInfo.HighTemp {
a.systemInfo.HighTemp = sensor.Temperature
}
a.systemInfo.HighTemp = max(a.systemInfo.HighTemp, sensor.Temperature)
systemStats.Temperatures[sensorName] = twoDecimals(sensor.Temperature)
}
return nil

View File

@@ -75,7 +75,7 @@ type Info struct {
Bandwidth float64 `json:"b"`
AgentVersion string `json:"v"`
Podman bool `json:"p,omitempty"`
Gpu float64 `json:"g,omitempty"`
GpuPct float64 `json:"g,omitempty"`
HighTemp float64 `json:"ht,omitempty"`
}

View File

@@ -9,7 +9,7 @@ import {
VisibilityState,
getCoreRowModel,
useReactTable,
Column,
HeaderContext,
} from "@tanstack/react-table"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
@@ -66,7 +66,7 @@ import { useStore } from "@nanostores/react"
import { cn, copyToClipboard, decimalString, isReadOnlyUser, useLocalStorage } from "@/lib/utils"
import AlertsButton from "../alerts/alert-button"
import { $router, Link, navigate } from "../router"
import { EthernetIcon, ThermometerIcon } from "../ui/icons"
import { EthernetIcon, GpuIcon, ThermometerIcon } from "../ui/icons"
import { Trans, t } from "@lingui/macro"
import { useLingui } from "@lingui/react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"
@@ -77,10 +77,10 @@ import { getPagePath } from "@nanostores/router"
type ViewMode = "table" | "grid"
function CellFormatter(info: CellContext<SystemRecord, unknown>) {
const val = info.getValue() as number
const val = (info.getValue() as number) || 0
return (
<div className="flex gap-2 items-center tabular-nums tracking-tight">
<span className="min-w-[3.5em]">{decimalString(val, 1)}%</span>
<span className="min-w-[3.3em]">{decimalString(val, 1)}%</span>
<span className="grow min-w-10 block bg-muted h-[1em] relative rounded-sm overflow-hidden">
<span
className={cn(
@@ -99,7 +99,8 @@ function CellFormatter(info: CellContext<SystemRecord, unknown>) {
)
}
function sortableHeader(column: Column<SystemRecord, unknown>, hideSortIcon = false) {
function sortableHeader(context: HeaderContext<SystemRecord, unknown>, hideSortIcon = false) {
const { column } = context
return (
<Button
variant="ghost"
@@ -154,7 +155,7 @@ export default function SystemsTable() {
</Button>
</span>
),
header: ({ column }) => sortableHeader(column),
header: sortableHeader,
},
{
accessorKey: "info.cpu",
@@ -162,7 +163,7 @@ export default function SystemsTable() {
invertSorting: true,
cell: CellFormatter,
icon: CpuIcon,
header: ({ column }) => sortableHeader(column),
header: sortableHeader,
},
{
accessorKey: "info.mp",
@@ -170,7 +171,7 @@ export default function SystemsTable() {
invertSorting: true,
cell: CellFormatter,
icon: MemoryStickIcon,
header: ({ column }) => sortableHeader(column),
header: sortableHeader,
},
{
accessorKey: "info.dp",
@@ -178,16 +179,25 @@ export default function SystemsTable() {
invertSorting: true,
cell: CellFormatter,
icon: HardDriveIcon,
header: ({ column }) => sortableHeader(column),
header: sortableHeader,
},
{
accessorKey: "info.g",
id: "GPU",
invertSorting: true,
sortUndefined: -1,
cell: CellFormatter,
icon: GpuIcon,
header: sortableHeader,
},
{
accessorKey: "info.ht",
id: t`Temp`,
invertSorting: true,
sortUndefined: 0,
sortUndefined: -1,
size: 50,
icon: ThermometerIcon,
header: ({ column }) => sortableHeader(column),
header: sortableHeader,
cell(info) {
const val = info.getValue() as number
if (!val) {
@@ -208,9 +218,9 @@ export default function SystemsTable() {
accessorFn: (originalRow) => originalRow.info.b || 0,
id: t`Net`,
invertSorting: true,
size: 115,
size: 100,
icon: EthernetIcon,
header: ({ column }) => sortableHeader(column),
header: sortableHeader,
cell(info) {
const val = info.getValue() as number
return (
@@ -230,7 +240,7 @@ export default function SystemsTable() {
invertSorting: true,
size: 50,
icon: WifiIcon,
header: ({ column }) => sortableHeader(column, true),
header: sortableHeader,
cell(info) {
const version = info.getValue() as string
if (!version || !hubVersion) {

View File

@@ -63,3 +63,13 @@ export function ThermometerIcon(props: SVGProps<SVGSVGElement>) {
</svg>
)
}
// Huge icons (MIT)
export function GpuIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg viewBox="0 0 24 24" {...props} stroke="currentColor" fill="none" strokeWidth="2">
<path d="M4 21V4.1a1.5 1.5 0 0 0-1.1-1L2 3m2 2h13c2.4 0 3.5 0 4.3.7s.7 2 .7 4.3v4.5c0 2.4 0 3.5-.7 4.3-.8.7-2 .7-4.3.7h-4.9a1.8 1.8 0 0 1-1.6-1c-.3-.6-1-1-1.6-1H4" />
<path d="M19 11.5a3 3 0 1 1-6 0 3 3 0 0 1 6 0m-11.5-3h2m-2 3h2m-2 3h2" />
</svg>
)
}