GPU Monitoring Client
Project description
GPUFlight Client Library (gpufl)
The Flight Recorder for GPU Production Workloads.
gpufl is a low-overhead, always-on C++ observability library for GPU applications. Built on CUPTI (NVIDIA) and rocprofiler-sdk (AMD), it captures kernel telemetry, SASS-level profiling, and system metrics with under 2% overhead in monitoring mode.
Unlike traditional profilers (Nsight) that stop the world with 20-200x slowdown, GPUFlight is designed to run continuously in production — capturing kernel telemetry and logical scopes into structured logs.
Project Status: Beta (Pre-1.0)
GPUFlight is usable today and published to PyPI, but it's pre-1.0 — current releases are 0.1.0.devN dev builds. The public API and the on-the-wire log format may still change between releases; the first stable contract is v1.0.0. Pin an exact version if you depend on it.
To keep the initial design coherent, we are not currently accepting major feature Pull Requests. However, we welcome:
- Bug reports and local build issues.
- Documentation improvements and typo fixes.
- Feature requests and architectural suggestions via GitHub Issues.
Live Demo
Try the portal with real session data — no sign-up required:
Key Features
- Kernel Monitoring: Automatically intercepts all CUDA kernel launches via CUPTI.
- Production Grade: Uses a Lock-Free Ring Buffer and a Background Collector Thread to decouple logging from your hot path.
- Logical Scoping: Group thousands of micro-kernels into meaningful phases (e.g., "Inference", "PhysicsStep") using
GFL_SCOPEorgpufl.Scope. - Rich Metadata: Captures kernel names, grid/block dimensions, register counts, shared memory usage, occupancy with per-resource breakdown, and CPU stack traces.
- Profiling Engines: Choose from PC Sampling (stall analysis), SASS Metrics (instruction-level divergence), or Range Profiler (hardware counters) — one engine per session.
- System Monitoring: Collects GPU utilization, VRAM, temperature, power, and clock speeds via NVML.
- Sidecar Ready: Outputs structured NDJSON logs with automatic rotation and gzip compression.
- Direct Upload: Opt-in
remote_upload=Truemode POSTs telemetry straight to the GPUFlight backend — ideal for local dev, SSH, and Jupyter workflows where running the sidecar agent is overkill. - Vendor Agnostic Design: Architecture ready for AMD (ROCm) support.
Installation
Python (PyPI)
pip install "gpufl[analyzer,viz]"
For full NVML support (GPU utilization/VRAM monitoring), build from source inside a CUDA devel container:
git clone https://github.com/gpu-flight/gpufl-client.git
CMAKE_ARGS="-DBUILD_TESTING=OFF" pip install "./gpufl-client[analyzer,viz]"
C++ (CMake FetchContent)
cmake_minimum_required(VERSION 3.31)
project(my_app LANGUAGES CXX CUDA)
include(FetchContent)
FetchContent_Declare(
gpufl
GIT_REPOSITORY https://github.com/gpu-flight/gpufl-client.git
GIT_TAG v0.1.0.dev7 # pin a release tag — see the Releases page for the latest
)
FetchContent_MakeAvailable(gpufl)
add_executable(my_app main.cu)
target_link_libraries(my_app PRIVATE gpufl::gpufl CUDA::cudart CUDA::cupti)
Quick Start (Python + Docker)
The recommended way to get started is with a Docker container. See example/python/docker/Dockerfile for a ready-to-use setup with PyTorch and Jupyter Lab.
cd example/python/docker
docker build -t gpufl-python .
docker run --gpus all -p 8888:8888 -v $(pwd)/notebooks:/workspace gpufl-python
import torch
import gpufl
gpufl.init("my-app",
log_path="./my_logs",
sampling_auto_start=True,
enable_kernel_details=True,
enable_stack_trace=True)
a = torch.randn(1024, 1024, device="cuda")
b = torch.randn(1024, 1024, device="cuda")
c = a @ b
torch.cuda.synchronize()
gpufl.shutdown()
Profiling Engines
CUPTI only allows one profiling mode per CUDA context at a time. Choose an engine at init:
from gpufl import ProfilingEngine
gpufl.init("my-app",
log_path="./logs",
profiling_engine=ProfilingEngine.PcSampling,
enable_kernel_details=True)
| Engine | What it collects | Analyzer method | Best for |
|---|---|---|---|
PcSampling |
Warp stall reasons (statistical sampling) | session.inspect_stalls() |
Finding why warps are stalling |
SassMetrics |
Per-instruction execution counts (binary instrumentation) | session.inspect_profile_samples() |
Thread divergence detection |
RangeProfiler |
SM throughput, L1/L2 hit rates, DRAM bandwidth, tensor core % | session.inspect_perf_metrics() |
Hardware counter deep-dives |
None |
Kernel metadata only (names, timing, occupancy) | session.inspect_hotspots() |
Production monitoring with minimal overhead |
C++ Usage
gpufl::InitOptions opts;
opts.app_name = "my_app";
opts.log_path = "my_logs";
opts.enable_kernel_details = true;
opts.enable_stack_trace = true;
opts.sampling_auto_start = true;
opts.profiling_engine = gpufl::ProfilingEngine::SassMetrics;
gpufl::init(opts);
GFL_SCOPE("training_step") {
// your CUDA code here
}
gpufl::shutdown();
Talking to the Backend
gpufl can optionally interact with the GPUFlight backend in two
independent ways, both opt-in:
| Capability | Opt in via | What happens |
|---|---|---|
| Fetch remote named config | config_name="..." |
gpufl.init() does a one-off GET /api/v1/config?config=<name> before monitoring starts and applies the returned fields to your InitOptions. |
| Direct log upload | remote_upload=True |
A background thread POSTs every NDJSON line to /api/v1/events/<type> in parallel with the on-disk write. Intended for local / SSH / Jupyter workflows. |
Both require backend_url + api_key to be set. Setting those two
fields alone does nothing — you must opt into at least one of the
two capabilities above.
Configuration precedence
When multiple sources set the same field, higher beats lower:
5. The kwargs you pass to gpufl.init() ← highest
4. Env vars (GPUFL_BACKEND_URL, GPUFL_API_KEY, ...)
3. Local config file (config_file=...)
2. Remote named config (when config_name is set)
1. Built-in defaults ← lowest
Quick start
import gpufl
# Just live upload — no remote config fetch
gpufl.init("my_app",
log_path="./logs",
backend_url="https://api.gpuflight.com",
api_key="gpfl_xxxxxxxxxxxx",
remote_upload=True)
# Just remote config fetch — no upload (production uses the sidecar)
gpufl.init("my_app",
backend_url="https://api.gpuflight.com",
api_key="gpfl_xxxxxxxxxxxx",
config_name="production")
# Both
gpufl.init("my_app",
backend_url="https://api.gpuflight.com",
api_key="gpfl_xxxxxxxxxxxx",
config_name="production",
remote_upload=True)
Or via environment:
export GPUFL_BACKEND_URL=https://api.gpuflight.com
export GPUFL_API_KEY=gpfl_xxxxxxxxxxxx
export GPUFL_CONFIG_NAME=production # opt into remote config
export GPUFL_REMOTE_UPLOAD=1 # opt into live upload
python my_training_script.py
Upload mechanics
- The client writes NDJSON to disk as usual AND POSTs each line in parallel via a dedicated background thread — no added latency on the measurement hot path.
- Best-effort delivery: 3 retries with exponential backoff per line, then drop. The on-disk NDJSON is still there, so a monitor daemon (or manual re-upload) can always back-fill.
- An invalid or unauthorized API key disables live upload for the session; the file sink keeps working.
For production workloads with guaranteed delivery, pipe delivery, or
cross-process fan-in, keep using the gpufl-monitor sidecar agent —
it's the same NDJSON on the wire, just decoupled from the measurement
process.
Python Analysis
The gpufl.analyzer module loads NDJSON logs and provides Rich-formatted terminal dashboards.
from gpufl.analyzer import GpuFlightSession
session = GpuFlightSession("./logs", log_prefix="my_logs")
# Executive Summary: session duration, kernel count, GPU utilization, VRAM
session.print_summary()
# Top kernels by GPU time with occupancy breakdown and stack traces
session.inspect_hotspots(top_n=5)
# Time breakdown by user-defined Scope regions
session.inspect_scopes()
# PC Sampling: per-kernel stall reason distribution
session.inspect_stalls(top_n=10)
# SASS Metrics: instruction-level execution counts and divergence
session.inspect_profile_samples(top_n=10)
# Range Profiler: SM throughput, cache hit rates, DRAM bandwidth
session.inspect_perf_metrics(top_n=10)
Visualization (Timeline)
The viz module provides interactive matplotlib plots to correlate kernel execution with system metrics.
import gpufl.viz as viz
viz.init("./logs/*.log")
viz.show()
Testing
C++ Tests
The C++ tests use GoogleTest and are hardware-aware — NVIDIA-specific tests skip automatically if no compatible GPU is detected.
cmake --build cmake-build-debug --target gpufl_tests
ctest --test-dir cmake-build-debug --output-on-failure
Python Tests
pip install pytest
pytest tests/python/
Linux Configuration (Required for CUPTI)
To allow non-root users to profile GPU kernels (using CUPTI/PC Sampling) on Linux, you must relax the NVIDIA driver security restrictions. Without this, gpufl may fail to capture kernel activity.
-
Create a configuration file:
sudo nano /etc/modprobe.d/nvidia-profiler.conf
-
Add the following line:
options nvidia NVreg_RestrictProfilingToAdminUsers=0 -
Apply changes and reboot:
sudo update-initramfs -u sudo reboot
GPU Flight is open source: github.com/gpu-flight Python package: pypi.org/project/gpufl
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gpufl-1.0.0rc1.tar.gz.
File metadata
- Download URL: gpufl-1.0.0rc1.tar.gz
- Upload date:
- Size: 417.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a5341792aaad67ec285242300957d73ed1923dd4688fe31a3468959902b2ab5
|
|
| MD5 |
7fdd92ab4c93ceb47245ad9b5a5fdaaf
|
|
| BLAKE2b-256 |
383ce73779ffa18fd5e905c773c56f681ef298b8e14ed03b8868d8d1b7720543
|
File details
Details for the file gpufl-1.0.0rc1-cp313-cp313-win_amd64.whl.
File metadata
- Download URL: gpufl-1.0.0rc1-cp313-cp313-win_amd64.whl
- Upload date:
- Size: 8.4 MB
- Tags: CPython 3.13, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ccd6623a1b2013b3db7c58694b03b7417417b0a688f1b194d66b5045e7954e48
|
|
| MD5 |
64e088b3146b645406185dd1a7cf1f8d
|
|
| BLAKE2b-256 |
1c8a253c2329245a958a405254da2c9dbf885dd5ac8f11b33bf92167c13ff2e1
|
File details
Details for the file gpufl-1.0.0rc1-cp313-cp313-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: gpufl-1.0.0rc1-cp313-cp313-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 4.6 MB
- Tags: CPython 3.13, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98e1fc0109a1a05aabd11c36b47aabe8dbb56a66ce2c3d1bf4367a414a9b8f6d
|
|
| MD5 |
749c453df75b7a278cac821065d03bea
|
|
| BLAKE2b-256 |
929a586f6ce67dc7cb0392d4a9d60ae3d581cbc2704f0fb6613dda155319844b
|
File details
Details for the file gpufl-1.0.0rc1-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: gpufl-1.0.0rc1-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 8.4 MB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16c3a6bdc3e53d8632619af985a6e2306439d7a2de6713d26ee535b575e18923
|
|
| MD5 |
c6576530b800c353214e02cd726d79ab
|
|
| BLAKE2b-256 |
869d1df4f6915ac16357fe6262f32f9a5a7f603db1d59711975e524c14a9d3db
|
File details
Details for the file gpufl-1.0.0rc1-cp312-cp312-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: gpufl-1.0.0rc1-cp312-cp312-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 4.6 MB
- Tags: CPython 3.12, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc0dc24952bccf7cec9b44dab6d137fa7039e2fa1b5a630a725fa09fa67887ec
|
|
| MD5 |
8dbc8e2bda9a090015998bcff6663231
|
|
| BLAKE2b-256 |
ec19a264f4665bbf86bdf3f6d860a7cb212801b3287b3f743ed98f7de83cfd0e
|