A compact, always-on-top desktop widget for real-time monitoring of NVIDIA GPUs. Built for a multi-GPU workstation with 8 Tesla V100 cards (6 SXM2 + 2 PCIe). Zero external dependencies — uses only Python's standard library (tkinter and subprocess) and NVIDIA's nvidia-smi command-line tool.
[flame] Fart Machine GPU Meter [flame]
─────────────────────────────────────
0 PCIe 35°C ████░░░░░░░░ 26/200W 0%
1 SXM2 73°C █████████░░░ 52/225W 0%
2 SXM2 64°C ████████░░░░ 52/225W 0%
3 SXM2 52°C ██████░░░░░░ 225/225W 100%
4 SXM2 52°C ██████░░░░░░ 224/225W 100%
5 SXM2 62°C ███████░░░░░ 47/225W 0%
6 SXM2 76°C █████████░░░ 55/225W 0%
7 PCIe 37°C ████░░░░░░░░ 27/200W 0%
The widget queries nvidia-smi every 5 seconds using the following command:
nvidia-smi --query-gpu=index,name,temperature.gpu,power.draw,power.limit,utilization.gpu --format=csv,noheader,nounits
This returns a CSV row per GPU with six fields: device index, full GPU name, temperature in Celsius, current power draw in watts, power limit in watts, and compute utilization percentage. The subprocess call has a 5-second timeout to prevent the widget from hanging if the NVIDIA driver becomes unresponsive.
Each GPU row in the widget displays:
| Column | Description | Example |
|---|---|---|
| Index | nvidia-smi device index | 0 |
| Type | Detected from GPU name string — SXM2, PCIe, or GPU |
SXM2 |
| Temperature | Current die temperature in Celsius | 73°C |
| Temp Bar | 80-pixel wide color-coded bar (see below) | visual bar |
| Power | Current draw / power limit in watts | 52/225W |
| Utilization | GPU compute utilization percentage | 100% |
The horizontal temperature bar beside each GPU's temp reading is color-coded in three tiers:
- Green (
#4ec94e) — below 60°C. Normal idle or light-load temperatures. - Yellow (
#e6c84c) — 60°C to 79°C. Moderate load; within safe operating range but worth watching. - Red (
#e64c4c) — 80°C and above. Approaching thermal limits. V100 SXM2 cards throttle at 84°C.
The bar width is proportional to temperature on a 0–100°C scale, so a GPU at 75°C fills 75% of the bar.
SXM2 cards run hotter than PCIe cards due to higher power limits (225W vs 200W) and denser packing on the NVLink baseboard. The widget has a dedicated alert system specifically for SXM2 overheating:
Trigger condition: Any GPU tagged SXM2 reaches 79°C or higher.
When triggered:
-
Row highlighting — The overheating GPU's entire row switches to a dark red background (
#4a1010). All text in that row turns bright red (#ff6666/#ff4444) and the temperature bar background changes to#552222. This makes the offending GPU immediately obvious at a glance. -
"BONER ZONE" banner — A large bold red label reading
BONER ZONEappears below the GPU list, separated by a horizontal rule. This label flashes on and off every 500 milliseconds by toggling the text color between red (#e64c4c) and the background color (#1e1e1e), creating a blinking effect.
Recovery: When all SXM2 GPUs drop back below 79°C, the row highlighting reverts to normal colors and the "BONER ZONE" banner disappears entirely (removed from the layout, not just hidden).
PCIe GPUs are excluded from this alert because they have lower power limits and better airflow in standard PCIe slots, so they rarely reach concerning temperatures.
The top of the widget displays the program name "Fart Machine GPU Meter" in bold red Consolas font, flanked on both sides by hand-drawn flame icons. The flames are rendered as three layered tkinter.Canvas polygons:
- Outer layer — Red (
#e63e3e) - Middle layer — Orange (
#f5943d) - Inner core — Yellow (
#f5d43d)
A thin gray separator line (#444) divides the title from the GPU rows.
- Borderless —
overrideredirect(True)removes the OS title bar, window borders, and system buttons. This gives the widget a clean, minimal appearance. - Always on top —
attributes('-topmost', True)keeps the widget above all other windows at all times, including fullscreen applications. - Draggable — Click anywhere on the widget and drag to reposition. The widget tracks the initial click offset and updates its position on every mouse-move event, preventing the jarring "snap to cursor" behavior of naive drag implementations.
- Right-click to close — Right-clicking anywhere on the widget opens a context menu with a single "Close" option that calls
self.destroy()to cleanly exit the application. - Initial position — The widget starts 16 pixels from the top-right corner of the primary display. It calculates this from
winfo_screenwidth()minus the widget's own width after the first layout pass. - Stateless — The widget does not save or restore window position, settings, or any other state between runs.
The widget uses tkinter.after(5000, callback) to schedule the next nvidia-smi poll. This is a non-blocking timer built into tkinter's event loop — no background threads are needed. The typical nvidia-smi call takes ~180ms on this system, which is fast enough to run synchronously without causing UI freezes.
The "BONER ZONE" flash runs on a separate after(500, ...) timer that toggles the label color every half second, independent of the data refresh cycle.
- Python 3.8+ with
tkinter(included in standard Windows Python installs) - NVIDIA GPU(s) with the NVIDIA driver installed (
nvidia-smimust be on PATH) - Windows (tested on Windows 11; tkinter's
overrideredirectand-topmostbehave differently on Linux/macOS window managers)
python C:/gpu-pulse/gpu_pulse.pyThe widget appears in the top-right corner. Drag to reposition. Right-click to close.
All constants are at the top of gpu_pulse.py:
| Constant | Default | Description |
|---|---|---|
BG |
#1e1e1e |
Window and row background color |
FG |
#cccccc |
Primary text color |
FG_DIM |
#888888 |
Secondary text color (GPU index/tag) |
BAR_W |
80 |
Temperature bar width in pixels |
BAR_H |
10 |
Temperature bar height in pixels |
REFRESH_MS |
5000 |
Polling interval in milliseconds |
The SXM2 overheat threshold (79°C) is hardcoded in _refresh(). The "BONER Zone" flash interval (500ms) is hardcoded in _flash_boner().
The entire application is a single file with no classes beyond the main GpuMonitor(tk.Tk) window:
query_gpus()— Callsnvidia-smi, parses CSV output, returns a list of dicts with keysidx,tag,temp,power,power_limit,util.temp_color(t)— Returns a hex color string for the three temperature tiers.GpuMonitor— The tkinter root window. Builds the UI once in_build_ui(), then updates it in-place every 5 seconds via_refresh(). The "BONER ZONE" flash is driven by_flash_boner()on its own 500ms timer.
Benchmarked on AMD Threadripper PRO 3945WX (24 cores / 48 threads):
| Interval | Per-core CPU | System-wide |
|---|---|---|
| 3s | ~6% | ~0.25% |
| 5s (default) | ~3.6% | ~0.15% |
| 10s | ~1.8% | ~0.08% |
The overhead is entirely from the nvidia-smi subprocess (~180ms per call). The tkinter UI update itself is negligible.
MIT License. See LICENSE.