Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const CpuUsageProgress = () => {
<div className="flex items-center justify-between">
<ProgressLabel>
<span className="flex items-center gap-2">
<Cpu className="h-4 w-4" />
<Cpu className="h-4 w-4 shrink-0" />
CPU: {deviceName?.full_device_name}
</span>
</ProgressLabel>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,51 @@ import {
} from "@/components/ui/progress";
import { Gpu } from "lucide-react";
import { useAppSelector } from "@/store/hooks.ts";
import { selectDeviceByFamily } from "@/store/reducers/devices.ts";
import { selectGpuDevices } from "@/store/reducers/devices.ts";

export const GpuUsageProgress = () => {
const { gpu } = useMetrics();
const deviceName = useAppSelector((state) =>
selectDeviceByFamily(state, "GPU"),
const { gpus } = useMetrics();
const gpuDevices = useAppSelector(selectGpuDevices);

const deviceMap = new Map(
gpuDevices.map((device) => {
// Handle both single card "GPU" and multiple cards "GPU.0", "GPU.1"
const id =
device.device_name === "GPU"
? "0"
: device.device_name.replace("GPU.", "");
return [id, device];
}),
);

return (
<Progress value={gpu} max={100}>
<>
<div className="flex items-center justify-between">
<ProgressLabel>
<span className="flex items-center gap-2">
<Gpu className="h-4 w-4" />
GPU: {deviceName?.full_device_name}
</span>
</ProgressLabel>
<ProgressValue>
{(_, value) => `${value?.toFixed(2) ?? 0}%`}
</ProgressValue>
</div>
<ProgressTrack>
<ProgressIndicator />
</ProgressTrack>
</>
</Progress>
<>
{gpus.map((gpu) => {
const device = deviceMap.get(gpu.id);
const deviceLabel = device?.device_name || `GPU.${gpu.id}`;
const deviceFullName = device?.full_device_name || "Unknown GPU";

return (
<Progress key={gpu.id} value={gpu.usage} max={100}>
<>
<div className="flex items-center justify-between">
<ProgressLabel>
<span className="flex items-center gap-2">
<Gpu className="h-4 w-4 shrink-0" />
{deviceLabel}: {deviceFullName}
</span>
</ProgressLabel>
<ProgressValue>
{(_, value) => `${value?.toFixed(2) ?? 0}%`}
</ProgressValue>
</div>
<ProgressTrack>
<ProgressIndicator />
</ProgressTrack>
</>
</Progress>
);
})}
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ import { useAppSelector } from "@/store/hooks.ts";
import {
selectCpuMetric,
selectFpsMetric,
selectGpu1Metric,
selectGpuMetric,
selectAllGpuMetrics,
} from "@/store/reducers/metrics.ts";

export const useMetrics = () => {
const fps = useAppSelector(selectFpsMetric);
const cpu = useAppSelector(selectCpuMetric);
const gpu = useAppSelector(selectGpuMetric);
const gpu1 = useAppSelector(selectGpu1Metric);
const gpus = useAppSelector(selectAllGpuMetrics);

return {
fps: fps ?? 0,
cpu: cpu ?? 0,
gpu: gpu ?? 0,
gpu1: gpu1 ?? 0,
gpus: gpus ?? [],
npu: 0,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,14 @@ import pipeline0 from "@/assets/pipeline_0.png";
import pipeline1 from "@/assets/pipeline_1.png";
import pipeline2 from "@/assets/pipeline_2.png";
import type { Pipeline } from "@/api/api.generated";
import { selectHasGPU1, selectHasNPU } from "@/store/reducers/devices.ts";
import { selectHasNPU } from "@/store/reducers/devices.ts";
import { NpuUsageProgress } from "@/features/metrics/NpuUsageProgress.tsx";
import { Gpu1UsageProgress } from "@/features/metrics/Gpu1UsageProgress.tsx";

const pipelineImages = [pipeline0, pipeline1, pipeline2];

const Home = () => {
const pipelines = useAppSelector(selectPipelines);

const hasGpu1 = useAppSelector(selectHasGPU1);
const hasNpu = useAppSelector(selectHasNPU);

const predefinedPipelines =
Expand Down Expand Up @@ -143,7 +141,6 @@ const Home = () => {
<h1 className="font-medium text-2xl">Resource utilization</h1>
<CpuUsageProgress />
<GpuUsageProgress />
{hasGpu1 && <Gpu1UsageProgress />}
{hasNpu && <NpuUsageProgress />}

<h1 className="font-medium text-2xl mt-4">Learning and support</h1>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ const devicesSlice = createSlice({
state.items = action.payload;
state.lastFetched = Date.now();
},
setTestDevices: (state, action: { payload: Device[] }) => {
state.items = action.payload;
state.lastFetched = Date.now();
},
},
});

export const { setDevices } = devicesSlice.actions;
export const { setDevices, setTestDevices } = devicesSlice.actions;

// Base selector
export const selectDevices = (state: RootState) => state.devices.items;
Expand All @@ -41,12 +45,14 @@ export const selectDeviceByName = (state: RootState, deviceName: string) =>
export const selectDeviceByFamily = (state: RootState, deviceFamily: string) =>
selectDevices(state).find((device) => device.device_family === deviceFamily);

export const selectHasGPU1 = createSelector([selectDevices], (devices) =>
devices.some((device) => device.device_name === "GPU.1"),
);

export const selectHasNPU = createSelector([selectDevices], (devices) =>
devices.some((device) => device.device_family === "NPU"),
);

export const selectGpuDevices = createSelector([selectDevices], (devices) =>
devices
.filter((device) => device.device_family === "GPU")
.sort((d1, d2) => d1.device_name.localeCompare(d2.device_name)),
);

export default devicesSlice.reducer;
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,31 @@ export const selectGpuMetric = (state: RootState) =>
(m) =>
m.name === "gpu_engine_usage" &&
["compute", "render", "ccs"].includes(m.tags?.engine ?? "") &&
m.tags?.gpu_id === "0" &&
(m.fields.usage as number) > 0,
m.tags?.gpu_id === "0",
)?.fields?.usage as number | undefined;

export const selectGpu1Metric = (state: RootState) =>
state.metrics.metrics.find(
export const selectAllGpuMetrics = (state: RootState) => {
const gpuMetrics = state.metrics.metrics.filter(
(m) =>
m.name === "gpu_engine_usage" &&
["compute", "render", "ccs"].includes(m.tags?.engine ?? "") &&
m.tags?.gpu_id === "1" &&
(m.fields.usage as number) > 0,
)?.fields?.usage as number | undefined;
["compute", "render", "ccs"].includes(m.tags?.engine ?? ""),
);

// group by gpu_id and return the first metric for each GPU
const gpuMap = new Map<string, { id: string; usage: number }>();
gpuMetrics.forEach((metric) => {
const gpuId = metric.tags?.gpu_id;
if (gpuId && !gpuMap.has(gpuId)) {
gpuMap.set(gpuId, {
id: gpuId,
usage: metric.fields.usage as number,
});
}
});

return Array.from(gpuMap.values()).sort((gpu1, gpu2) =>
gpu1.id.localeCompare(gpu2.id),
);
};

export default metrics.reducer;
Loading