cxgpu
August 22, 2026 · View on GitHub
A multi-vendor GPU monitor for the terminal, built on SharpConsoleUI.
⭐ If you find cxgpu useful, please consider giving it a star! ⭐
It helps others discover the project and motivates continued development.
Live gauges and braille sparkline history for utilization, memory, temperature, power and fan; per-process GPU usage with signal actions; a fleet dashboard for multi-GPU boxes; and full device details — for NVIDIA and AMD, side by side in the same view.
Monitor your GPUs. Right in the terminal.

Quick Start
Option 1: One-line install (Linux, no .NET required)
curl -fsSL https://raw.githubusercontent.com/nickprotop/cxgpu/main/install.sh | bash
cxgpu
Windows (PowerShell)
irm https://raw.githubusercontent.com/nickprotop/cxgpu/main/install.ps1 | iex
Option 2: Build from source (requires .NET 10)
git clone https://github.com/nickprotop/cxgpu.git
cd cxgpu
./build-and-install.sh
cxgpu
No GPU to hand? cxgpu --demo runs against simulated GPUs — useful for trying the multi-GPU
views on a single-GPU machine, or with no GPU driver at all.
Supported hardware
cxgpu probes for each vendor at startup and shows whichever it finds — including both at once on a hybrid machine. A vendor that isn't present is simply absent; nothing errors.
| Vendor | Source | Platform |
|---|---|---|
| NVIDIA | nvidia-smi | Linux, Windows |
| AMD | sysfs + hwmon + /proc/*/fdinfo | Linux |
| AMD | amd-smi / rocm-smi | Windows, or Linux without sysfs |
The AMD backend needs no extra tooling and no root on Linux — it reads the kernel directly, which is both faster than a CLI and the only source that can attribute memory to individual processes.
Metrics differ by vendor, and cxgpu says so rather than guessing. Each backend declares what it can measure, and anything it can't is omitted — never shown as a zero. An APU with no fan sensor shows no fan gauge; a source that can't attribute per-process usage says "not available" instead of "no processes".
Views
Overview — one GPU in depth
Gauges plus braille sparkline history for utilization, memory, temperature, power and fan, a one-line vitals summary, encode/decode readouts, and a spec-sheet of the device: driver, PCIe link, CUDA version, clocks, VRAM, limits, VBIOS, and which data source is live.
A throttle chip appears only when the GPU is genuinely throttling (⚠ thermal, ⚠ power cap,
⚠ hw slowdown) — the benign "idle" bits every card reports are filtered out, so the chip means
something when you see it.
Dashboard — the whole fleet at once
On a multi-GPU machine the summary strip gains a ‹DASH› chip. Select it and the Overview
becomes a fleet view: aggregate totals on the left (combined VRAM, combined draw, hottest card,
total processes, anything throttling) and a hero panel per GPU on the right. Double-click a panel to
jump into that GPU's detail.

Processes — who is using the GPU
An expandable tree of GPU processes with a toolbar to filter by GPU (or show all GPUs at once) and sort by memory, SM%, PID or name. Expand a row for the full command path and live per-process detail; from there you can send SIGTERM or SIGKILL, with a confirmation on the latter.

Outcomes are reported honestly: "permission denied — it belongs to another user" and "already exited" are distinct messages, not a generic failure.
Features
| 🖥️ Multi-Vendor | NVIDIA and AMD in one view, each through its own backend |
| 📊 Overview | Live gauges with braille sparkline history, vitals line, and a full device spec-sheet |
| 🧩 Fleet Dashboard | Per-GPU hero panels plus aggregate totals, on the ‹DASH› chip |
| 📋 Processes | Expandable tree with GPU filter, sorting, per-process engine usage, and signal actions |
| ⚠️ Throttle Detection | Named throttle reasons surfaced only when a real throttle is active |
| 🔔 Alerts | Threshold and throttle events with toasts, a status-bar badge, and a history flyout |
| 📈 Session Stats | Peak temperature, peak power and throttle time per GPU, in-app and on exit |
| 📡 Prometheus | --prometheus serves /metrics; --no-ui runs it headless |
| 🎬 Encode / Decode | NVENC/NVDEC utilization where the hardware reports it |
| 🎯 Capability-Aware | Unsupported metrics are omitted, never faked as zero |
| 🎛️ Settings | A paged settings dialog (F9) — refresh, graphs, tabs, alerts, and per-backend options |
| ❓ Help Overlay | ? or F1 lists every binding, marking those that don't apply on this machine |
| 📐 Responsive | Adapts to terminal width — side-by-side or stacked, wrapping panel grids |
| 🧪 Demo Mode | --demo[=N] simulates up to 9 GPUs for states real hardware won't produce on demand |
Keyboard Shortcuts
| Key | Action |
|---|---|
| F2 / F3 | Overview / Processes tab |
[ ] | Previous / next GPU tile (multi-GPU) |
| 1–9 | Select a GPU directly (multi-GPU) |
| → / Enter | Expand a process row (Processes) |
| ← | Collapse |
k | Signal the selected process (Processes) |
| ? / F1 | Keyboard shortcuts |
| F9 | Settings |
| F10 / Esc | Exit |
Status-bar hints and GPU tiles are clickable; double-clicking a dashboard panel opens that GPU. The alert badge at the right of the status bar opens the event history.
Command Line
cxgpu [options]
--demo[=N] Run against N simulated GPUs (default 4, max 9) instead of
real hardware. Also settable via CXGPU_FAKE_GPUS=N.
--prometheus Serve Prometheus metrics at /metrics.
--port PORT Port for the exporter (default 9835).
--bind ADDRESS Interface to bind (default localhost). Use 0.0.0.0 for all.
--no-ui Run the exporter without the TUI. Requires --prometheus.
--log-level LEVEL Log panel verbosity, TUI mode only: error, warn (default), info, debug.
--log-file PATH Write logs to a file as well as the TUI log panel.
-h, --help Show help and exit.
-v, --version Show the version and exit.
Alerts
cxgpu raises an event when a GPU crosses a threshold, and when the driver itself reports a throttle. Both land in one list, so the chips on screen and the alert history can never disagree.
- Warnings raise a toast that dismisses itself; criticals raise one that stays until you dismiss it. At most one toast per GPU per metric, so a card oscillating around a threshold cannot bury the screen.
- A badge appears at the right of the status bar once anything has fired. Click it for the history — active events in colour, resolved ones dimmed with how long they lasted. That is the point of keeping them: the throttle chips vanish when a condition clears, so "did it throttle while I was at lunch?" is otherwise unanswerable.
- Events are edge-triggered with hysteresis: one entry per episode, not one per refresh, and a value resting on the threshold does not flap.
Thresholds are per vendor and editable under F9 → Alerts. The defaults differ by part because the hardware does — a GeForce warns at 83 °C where a Radeon warns at 90 °C, and temperature colouring everywhere in the UI follows the same numbers, so what you see and what fires always agree.
Throttle events come from the driver's own reason flags, never inferred. A backend that cannot read them contributes nothing rather than reporting "not throttling".
Prometheus
cxgpu --prometheus --no-ui & # headless exporter
cxgpu --prometheus # alongside the UI
cxgpu --prometheus --port 9100 --bind 0.0.0.0 # on every interface
Metrics are served at /metrics and read through the same provider the UI uses, so a scrape and the
screen cannot drift. Series carry a stable card label (the PCI address) as well as gpu, name
and backend — an index-labelled series silently re-points at different hardware when a backend
fails to probe, which is invisible in the UI but permanent in a time-series database.
cxgpu_temperature_celsius{gpu="0",name="NVIDIA GeForce RTX 3090",backend="NVIDIA",card="0000:01:00.0"} 44
cxgpu_throttled{gpu="0",...,reason="thermal"} 0
Unsupported metrics are absent, not zero. On a mixed box the NVIDIA card exports fan, power and throttle series while the AMD card does not, because that backend genuinely cannot read them — a fabricated zero would be averaged into a dashboard forever with nobody noticing.
The exporter binds localhost unless --bind says otherwise, warns on startup when it is
listening publicly, and fails rather than quietly choosing another port if the one you asked for is
taken.
Configuration
Settings live as JSON at the platform config location:
- Linux:
~/.config/cxgpu/config.json(honoursXDG_CONFIG_HOME) - Windows:
%APPDATA%\cxgpu\config.json
Edit them in-app with F9. The dialog is paged: refresh interval, graph options, tab visibility, and a page per GPU backend where you can enable or disable that vendor and change its options — for example which mechanism the AMD backend reads through. A disabled backend is never probed at all.
A missing or invalid file falls back to defaults, so the app always starts. Unrecognised keys are preserved on save, so a config written by a newer build survives a downgrade.
Architecture
GPU access sits behind one seam. Each vendor is a backend that declares its own capabilities and settings, so adding a vendor doesn't touch the UI.
cxgpu/
├── Program.cs # Entry point, CLI parsing
├── Configuration/ # CxgpuConfig (JSON load/save)
├── Gpu/
│ ├── Abstractions/ # Models, IGpuBackend, capabilities, identity, fleet summary
│ ├── Alerts/ # Threshold engine, events, session stats
│ ├── GpuBackendRegistry.cs # Probes backends, aggregates, assigns global GPU indices
│ ├── GpuBackendPlugin.cs # Backends as SharpConsoleUI plugin services
│ ├── GpuStatsFactory.cs # Backend selection and configuration
│ ├── ProcessSignals.cs # SIGTERM/SIGKILL delivery
│ └── Backends/
│ ├── Nvidia/ # nvidia-smi
│ ├── Amd/ # sysfs + hwmon + fdinfo, or amd-smi/rocm-smi
│ └── Demo/ # Synthetic GPUs for --demo
├── Export/ # Prometheus formatter, HTTP exporter, CLI options
├── Dashboard/ # Main window, settings, help, busy indicator
├── Helpers/ # UI constants, shared metric formatting, history
├── Widgets/ # Reusable controls (hero panel, strip, alert portal)
└── Tabs/ # Overview (+ fleet dashboard), Processes
Adding a vendor means writing one backend — the UI, alerts and exporter all adapt to what it declares it can read. See Writing a GPU backend.
Backends implement SharpConsoleUI's IPluginService, so they are already valid plugins — the day the
framework gains runtime assembly loading, they become drop-in without a refactor. That agnostic
surface is not merely latent: cxgpu reaches backends exclusively through Execute, the
once-a-second sample read included, and process signalling resolves its backend by service name
(Gpu.NVIDIA, Gpu.AMD) exactly as an external DLL would. Vendor authors still implement the typed
IGpuBackend; the agnostic surface is derived from it once, in GpuBackendPlugin.
Building from Source
cxgpu uses a conditional project reference for SharpConsoleUI:
- Local development: if ConsoleEx is cloned as a sibling directory (
../ConsoleEx), the project reference is used automatically - CI/Release builds: falls back to the SharpConsoleUI NuGet package
# Clone both repos as siblings
git clone https://github.com/nickprotop/ConsoleEx.git
git clone https://github.com/nickprotop/cxgpu.git
cd cxgpu
dotnet build cxgpu.csproj
Key Technologies: .NET 10, SharpConsoleUI, nvidia-smi,
Linux sysfs/hwmon, amd-smi/rocm-smi
Uninstall
Linux:
cxgpu-uninstall.sh
Windows (PowerShell):
& "$env:LOCALAPPDATA\cxgpu\cxgpu-uninstall.ps1"
Contributing
Bug reports, hardware reports and pull requests are welcome — see CONTRIBUTING.md. Adding a vendor is one self-contained backend: Writing a GPU backend.
License
MIT License. See LICENSE for details.