feat: GPU process list with per-process VRAM/utilization and kill

Add a GPU process table to the Performance tab showing which processes
use the selected GPU, with per-process VRAM, GPU utilization, CPU, host
memory, and command. Includes a kill endpoint (SIGTERM/SIGKILL, with
optional parent kill) behind a confirm dialog.

- nvcurve/hal/processes.py: NVML + /proc process enumeration
- server.py: GET /api/processes, POST /api/processes/kill (refuses to
  signal init/kthreadd)
- frontend: ProcessList component, API client, types
- tests: test_processes.py
- docs: API reference for the new endpoints
This commit is contained in:
ARIA committed 2026-10-03 20:25:33 +02:00
1 parent b75b9d43e9
commit c11ea73ead
10 files changed
+1008 -23

No files matched your search

@@ -1,10 +1,20 @@
export interface DialogAction {
label: string;
onClick: () => void;
className?: string;
disabled?: boolean;
}
interface Props {
message: string;
detail?: string;
confirmLabel?: string;
isDestructive?: boolean;
onConfirm: () => void;
/** Required unless `actions` is provided (which replaces the single confirm button). */
onConfirm?: () => void;
onCancel: () => void;
/** When provided, rendered after Cancel instead of the single confirm button. */
actions?: DialogAction[];
}
export function ConfirmDialog({
@@ -14,6 +24,7 @@ export function ConfirmDialog({
isDestructive = false,
onConfirm,
onCancel,
actions,
}: Props) {
return (
<div
@@ -33,17 +44,34 @@ export function ConfirmDialog({
>
Cancel
</button>
<button
onClick={onConfirm}
className={[
"px-3 py-1.5 rounded text-xs font-semibold transition-colors",
isDestructive
? "bg-red-600 hover:bg-red-500 text-white"
: "bg-emerald-600 hover:bg-emerald-500 text-white",
].join(" ")}
>
{confirmLabel}
</button>
{actions ? (
actions.map((a) => (
<button
key={a.label}
onClick={a.onClick}
disabled={a.disabled}
className={[
a.className ??
"px-3 py-1.5 rounded bg-zinc-800 hover:bg-zinc-700 text-zinc-200 text-xs font-semibold transition-colors",
a.disabled ? "opacity-40 cursor-not-allowed" : "",
].join(" ")}
>
{a.label}
</button>
))
) : (
<button
onClick={() => onConfirm?.()}
className={[
"px-3 py-1.5 rounded text-xs font-semibold transition-colors",
isDestructive
? "bg-red-600 hover:bg-red-500 text-white"
: "bg-emerald-600 hover:bg-emerald-500 text-white",
].join(" ")}
>
{confirmLabel}
</button>
)}
</div>
</div>
</div>