A light, fast terminal dashboard for AMD GPUs on Linux.
GPUFlo reads Linux amdgpu kernel interfaces directly — sysfs, hwmon, versioned gpu_metrics, DRM fdinfo — and answers immediately:
One small static binary, strictly read-only. No ROCm userspace, no root, no daemon, no database, no network. Optional sources only ever add information.
First reading in under a second. Telemetry samples on a dedicated 250 ms kernel lane that rendering, overlays, and process scans can never block.
Socket-scoped temperature and power kept separate from partition-scoped activity, memory, and clocks. Missing telemetry is an explicit state — stale, asleep, permission_denied — never a made-up zero.
Stream --json / --json-stream NDJSON (optionally --for <duration>) into scripts. Every GPU carries additive gpus[].platform within schema_version 1. Or embed the semver-supported Rust Monitor API — the same canonical model that drives the TUI.
Full mode, compact, mini, and one-line tiny views auto-select by terminal size. Works as a floating desktop widget.
Press p: PID, name, GPU/XCP, VRAM, GTT, KFD memory, and container identity — permission failures shown explicitly rather than hidden.
Optional local daily.json keeps peaks, energy when available, and source-reported throttle episodes — never raw samples, never uploaded. Pin machine output on schema_version, not the binary version.
The same canonical telemetry model drives the TUI, a stable JSON/NDJSON contract (schema_version 1 — pin on it; additive fields like gpus[].platform stay compatible), and a semver-supported Rust library for embedding.
# one snapshot, a stream, or a bounded capture gpuflo --json | jq '.gpus[].platform' gpuflo --json-stream | jq .gpus[0].activity gpuflo --json-stream --for 30s > capture.ndjson # schema_version 1 · each gpus[] has platform · never null/NaN/fake zero { "schema_version": 1, "gpuflo_version": "0.2.0", ... } # gpus[].platform (additive within schema 1): { "id": "generic_discrete", "memory_pool": "vram" } { "value": 97.0, "observed_at": "2026-08-21T23:45:12Z" } { "state": "permission_denied" }
use gpuflo::{Monitor, MonitorEvent, MonitorOptions}; let monitor = Monitor::start(MonitorOptions::new())?; match monitor.receive()? { MonitorEvent::Snapshot(s) => println!("{} GPU(s)", s.gpus.len()), MonitorEvent::Fatal(e) => return Err(e.into()), _ => {} }
An interactive isometric map of the whole codebase: every module as a building sized by real line counts, every control and data path cited to the file that implements it. Three styles, zoom + pan, click to inspect.
How gpuflo maintains itself: a label-driven pipeline that triages GitHub issues, dispatches coding agents into git worktrees, gates their work with six deterministic checks, and publishes reviewed PRs. Humans keep the merge button.