Metadata-Version: 2.5
Name: gpu-scope
Version: 0.2.0
Summary: A modern, extensible TUI for monitoring GPU engagement (nvtop-inspired, built on Textual)
Project-URL: Homepage, https://github.com/matplo/gpu-scope
Author: gpu-scope contributors
License: MIT
License-File: LICENSE
Keywords: gpu,gpu-top,monitoring,nvidia,nvtop,rich,textual,tui
Classifier: Environment :: Console
Classifier: Environment :: Console :: Curses
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Hardware
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.9
Requires-Dist: nvidia-ml-py>=12.560.30
Requires-Dist: psutil>=5.9.0
Requires-Dist: rich>=13.7.0
Requires-Dist: textual>=0.58.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: textual-dev>=1.5.0; extra == 'dev'
Provides-Extra: nvidia
Description-Content-Type: text/markdown

# gpu-scope

A modern, [Textual](https://textual.textualize.io/)-based TUI for watching GPU
engagement on a node — in the spirit of `nvtop`, built on Rich/Textual, and
covering NVIDIA, AMD, and Apple Silicon.

![status](https://img.shields.io/badge/status-early-orange)

## Features

- Live per-GPU panels: utilization, memory, temperature, power, fan, clocks,
  encoder/decoder engagement, and a rolling utilization sparkline.
- Per-GPU process table (PID, name, device memory) — NVIDIA only for now.
- Adjustable refresh rate (`+` / `-` at runtime).
- Backend-pluggable, three vendors today:
  - **NVIDIA** — via NVML (`nvidia-ml-py`). Full field coverage, including
    per-process memory.
  - **AMD** — via the `rocm-smi` CLI (ROCm must be installed). Utilization,
    memory, temperature, power, fan, clocks; no per-process view yet.
    Parses `rocm-smi`'s JSON defensively (case-insensitive key matching) to
    tolerate key-name drift across ROCm versions, but hasn't been run
    against real ROCm hardware — if a field looks off, please open an issue
    with your `rocm-smi -a --json` output.
  - **Apple Silicon** — via `ioreg`'s `IOAccelerator` registry (no sudo
    required, macOS only). Utilization and a GPU-attributed memory figure
    (against total unified memory, there's no separate VRAM pool). Apple
    doesn't expose temperature/power/fan/clocks/per-process GPU stats
    without `powermetrics`, which requires root — those fields show as `—`.
- A `demo` backend with synthetic data, so you can preview the UI on a
  machine with no GPU at all.

Adding a vendor means writing one `GpuBackend` subclass that returns
`HostSnapshot`/`GpuSnapshot` objects — the app and widgets are backend-agnostic.

## Install

```bash
pip install gpu-scope
```

The project is `gpu-scope` end to end — `gpu-top` was blocked by PyPI's
typosquat-similarity check against an unrelated existing package
(`gputop`). The `gpu-top` name lives on as a second command, installed
alongside `gpu-scope` and pointing at the exact same program, for anyone
used to typing it.

One install gets every backend — there's nothing to opt into. NVIDIA support
(`nvidia-ml-py`) ships as a core dependency: it's a small, pure-Python
ctypes wrapper with no platform-specific build, so it installs cleanly
everywhere and simply reports "unavailable" at runtime on a machine with no
NVIDIA driver. AMD and Apple need no extra pip packages at all — they shell
out to system tools (`rocm-smi`, `ioreg`) instead. The one thing `pip`
can't do for you: AMD support only *activates* if ROCm's `rocm-smi` is on
your `PATH` (a system package, install it via your distro/ROCm docs).

`pip install gpu-scope[nvidia]` is still accepted (as a no-op) if you're
used to typing an extra — it doesn't install anything beyond the plain
command above.

Installing from source instead: `pip install "git+https://github.com/matplo/gpu-scope.git"`.

## Usage

```bash
gpu-scope                  # auto-detects the first available backend (gpu-top works identically)
gpu-scope --backend demo   # synthetic data, no GPU required
gpu-scope --list-backends  # show what's available on this host
gpu-scope --interval 0.5   # poll twice a second
```

Running with no GPU present, or forcing `--backend nvidia`/`--backend amd` on a
host without that vendor's tooling, exits with a short explanation and a
`--backend demo` suggestion instead of a driver-library stack trace.

Keys: `q` quit · `+` / `-` refresh rate · `d` toggle light/dark theme.

## Architecture

```
gpu_scope/
├── models.py          # GpuSnapshot / GpuProcess / HostSnapshot dataclasses
├── backends/
│   ├── base.py         # GpuBackend ABC — open() / poll() / close()
│   ├── nvidia.py        # NVML-backed implementation
│   ├── amd.py             # rocm-smi (CLI + JSON) implementation
│   ├── apple.py            # ioreg IOAccelerator implementation
│   └── demo.py               # synthetic backend for development/preview
├── widgets/
│   ├── meters.py         # Rich-renderable bars/sparklines (no extra deps)
│   └── gpu_panel.py       # the per-GPU card widget
├── app.py               # Textual App: layout + polling loop
└── cli.py                # argparse entry point (`gpu-scope` / `gpu-top`)
```

## Development

```bash
pip install -e ".[dev]"
pytest
gpu-scope --backend demo   # preview the UI with synthetic data, no GPU required
```

For live Textual devtools (a separate log console while the TUI runs), see
[the Textual docs](https://textual.textualize.io/guide/devtools/) — in short,
run `textual console` in one terminal and `textual run --dev "gpu_scope.cli:main"`
in another.

## License

MIT
