Hardware-free static analyzer for CUDA kernel binaries: source-attributed register pressure, spills, occupancy, diffs, and CI gates. No GPU required.
Project description
cuxray
Static analysis and optimization for CUDA kernel binaries (register pressure, spills, occupancy, bank conflicts) without a GPU.
cuxray reads what the compiler froze into your cubin and combines it with
NVIDIA's exact architecture tables, so it goes past reporting problems to
synthesizing and verifying fixes (swizzles, register caps, tile configs).
Measured facts are ground truth; estimates are labeled est. and validated
against hardware; anything unknowable is reported as such, with the reason.
Point it at any cubin and get a ranked, confidence-tagged list of what's slow and how to fix it, with no GPU touched:
$ pip install cuxray
$ cuxray advise w4a8_gemv.sm_80.cubin --threads 256
gemv_w4a8<__half, 1, 1, 1>(uint4 const*, signed char const*, ...) (w4a8_gemv.sm_80.cubin)
1. cut registers to 40 (-4) · high confidence · impact 50
unlocks 6 blocks/SM (62.5% → 75.0%); current limiter is registers
evidence: occupancy model (validated vs cuda_occupancy.h + runtime API)
2. SIMT datapath caps this loop: tensor cores scale past it · medium confidence · impact 40
MACs run on the SIMT int8 datapath (dp4a/FMA). On sm_80 the tensor cores do ~8x more
int8 MACs/clock. This is fine while memory-bound (low arithmetic-per-byte / batch 1),
but as arithmetic-per-byte grows the loop becomes SIMT-compute-bound and a tensor-core
implementation would be up to ~8x faster. Measure across your batch sizes to find the
crossover.
evidence: static op-mix + per-arch MAC-rate model (approximate)
Quick start
pip install cuxray # CPU-only (no CUDA, no GPU)
cuxray advise mykernels.so --threads 256 # ranked fixes for every kernel
cuxray solve mykernels.so --threads 256 # verified swizzle for any bank conflict
cuxray gate mykernels.so "spill_instrs==0" # exit 1 in CI on a regression
Point it at anything holding cubins: a .cubin, a host .so, a directory of
Triton caches, a .ptx, even a wheel you pip downloaded. On first run it
fetches pinned, sha256-verified NVIDIA binary utilities; nothing else to install.
What it does
| command | what you get |
|---|---|
advise · survey |
ranked, impact-weighted fixes for one kernel · for a whole library |
report · ls |
spills, register-pressure curve, occupancy + cliffs, access patterns · fast listing |
solve |
a verified conflict-free swizzle (Swizzle<B,M,S> plus ready-to-paste CUDA) |
tune-regs · tune |
Pareto occupancy/spill frontier over -maxrregcount · over -D tile matrices |
sched |
per-loop issue+stall cycle estimate from the compiler's own schedule |
roofline |
the memory/compute floor for a launch and which resource binds |
why |
dataflow slice: where a divergent or uncoalesced address came from |
compare · diff |
per-kernel A/B across two builds · CI regression detection |
gate |
CI exit codes, per-kernel budgets, SARIF annotations, a reusable Action |
occupancy |
what-if occupancy sweeps, no binary needed |
Every command takes --json / -o (schema: cuxray schema); cuxray doctor
shows toolchain and cache state. The datapath-crossover check (SIMT dp4a/FMA vs
tensor-core headroom) is surfaced by advise and report.
solve is the one thing nothing else does: it finds a bank conflict and hands
back the proven fix, with no GPU:
$ cuxray solve bank_conflict.cubin --threads 256
_Z12col_conflictPKfPfi
224 conflicted of 256 shared accesses
solution (all accesses): Swizzle<5,2,5> (zero smem cost, verified)
apply to byte offsets: addr ^ ((addr >> 5) & 0x7c)
e.g. bank_conflict.cu:19 LDS: 32-way → clean
// + a ready-to-paste __device__ swizzle() and the cute::Swizzle<5,2,5> layout
Validation
- Occupancy: 4,344/4,344 configs match NVIDIA's
cuda_occupancy.h; 54/54 match the CUDA runtime on real hardware. - Spill bytes byte-exact vs
ptxas -v; cycle estimate within 0.7% ofclock64();solvere-derives the canonical CUTLASSSwizzle<3,4,3>and its fix is hardware-timed within 2% of the padded twin. - ~161k production kernels (vLLM, PyTorch wheels) analyzed with zero crashes and zero false-positive conflict flags.
Notes
- Inputs:
.cubin, host ELF (.so/.o/exe, cubins extracted), directories (Triton caches),.ptx. Compute capability 7.5–12.x (Turing → Blackwell, incl.sm_120a). - Static facts only: cache behavior and achieved bandwidth need a profiler; those accesses are reported as unanalyzable, not guessed.
- Pass
--threads/--smem-dynamicwhen the binary carries no launch metadata (cuxray warns when it matters). Linux only; build with-lineinfofor source attribution.
License
Apache-2.0. Not affiliated with NVIDIA; CUDA binary utilities are downloaded from NVIDIA's redistributable archive under the CUDA Toolkit EULA.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 cuxray-0.3.0.tar.gz.
File metadata
- Download URL: cuxray-0.3.0.tar.gz
- Upload date:
- Size: 506.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af3b1b93d28cdb6fb2ebc0a94fb53f6c67d03703a53df0b6cfef52065ee497e1
|
|
| MD5 |
9cbda48a8ee20859ad5a389fb224bcd8
|
|
| BLAKE2b-256 |
e66ccbb05a21dcf705e2f66bede10f2ab8d84704143f41d7eda5f435a1ddb0cd
|
File details
Details for the file cuxray-0.3.0-py3-none-any.whl.
File metadata
- Download URL: cuxray-0.3.0-py3-none-any.whl
- Upload date:
- Size: 96.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
04b074418bdbd0d57a9ea9f4e45114bcdba8c1e5ce495ac81e2ea19eacbc5e47
|
|
| MD5 |
9bf0fa9197e597dbc4d1f521b23d5b7f
|
|
| BLAKE2b-256 |
b96e420af264ce30e1e8d49ac346dc7c0c0142e3e786e2f9c6105d60e327d778
|