cuda-doctor 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cuda_doctor-0.1.2/LICENSE +21 -0
- cuda_doctor-0.1.2/PKG-INFO +276 -0
- cuda_doctor-0.1.2/README.md +241 -0
- cuda_doctor-0.1.2/pyproject.toml +99 -0
- cuda_doctor-0.1.2/setup.cfg +4 -0
- cuda_doctor-0.1.2/src/cuda_doctor/__init__.py +5 -0
- cuda_doctor-0.1.2/src/cuda_doctor/__main__.py +6 -0
- cuda_doctor-0.1.2/src/cuda_doctor/checks/__init__.py +71 -0
- cuda_doctor-0.1.2/src/cuda_doctor/checks/base.py +44 -0
- cuda_doctor-0.1.2/src/cuda_doctor/checks/compiler_checks.py +123 -0
- cuda_doctor-0.1.2/src/cuda_doctor/checks/cuda_checks.py +193 -0
- cuda_doctor-0.1.2/src/cuda_doctor/checks/driver_checks.py +158 -0
- cuda_doctor-0.1.2/src/cuda_doctor/checks/environment_checks.py +141 -0
- cuda_doctor-0.1.2/src/cuda_doctor/checks/gpu_checks.py +94 -0
- cuda_doctor-0.1.2/src/cuda_doctor/checks/pytorch_checks.py +340 -0
- cuda_doctor-0.1.2/src/cuda_doctor/cli.py +134 -0
- cuda_doctor-0.1.2/src/cuda_doctor/collectors/__init__.py +37 -0
- cuda_doctor-0.1.2/src/cuda_doctor/collectors/cmake.py +17 -0
- cuda_doctor-0.1.2/src/cuda_doctor/collectors/compiler.py +71 -0
- cuda_doctor-0.1.2/src/cuda_doctor/collectors/cuda.py +78 -0
- cuda_doctor-0.1.2/src/cuda_doctor/collectors/environment.py +71 -0
- cuda_doctor-0.1.2/src/cuda_doctor/collectors/gpu.py +20 -0
- cuda_doctor-0.1.2/src/cuda_doctor/collectors/ninja.py +17 -0
- cuda_doctor-0.1.2/src/cuda_doctor/collectors/nvidia_smi.py +99 -0
- cuda_doctor-0.1.2/src/cuda_doctor/collectors/python_env.py +37 -0
- cuda_doctor-0.1.2/src/cuda_doctor/collectors/pytorch.py +75 -0
- cuda_doctor-0.1.2/src/cuda_doctor/collectors/system.py +60 -0
- cuda_doctor-0.1.2/src/cuda_doctor/compatibility/__init__.py +68 -0
- cuda_doctor-0.1.2/src/cuda_doctor/compatibility/compiler_cuda.py +129 -0
- cuda_doctor-0.1.2/src/cuda_doctor/compatibility/cuda_driver.py +120 -0
- cuda_doctor-0.1.2/src/cuda_doctor/compatibility/pytorch_cuda.py +102 -0
- cuda_doctor-0.1.2/src/cuda_doctor/core/__init__.py +1 -0
- cuda_doctor-0.1.2/src/cuda_doctor/core/context.py +25 -0
- cuda_doctor-0.1.2/src/cuda_doctor/core/enums.py +40 -0
- cuda_doctor-0.1.2/src/cuda_doctor/core/exceptions.py +24 -0
- cuda_doctor-0.1.2/src/cuda_doctor/core/models.py +230 -0
- cuda_doctor-0.1.2/src/cuda_doctor/core/runner.py +126 -0
- cuda_doctor-0.1.2/src/cuda_doctor/data/cuda_compiler_compatibility.json +69 -0
- cuda_doctor-0.1.2/src/cuda_doctor/data/cuda_driver_compatibility.json +17 -0
- cuda_doctor-0.1.2/src/cuda_doctor/data/known_issues.json +23 -0
- cuda_doctor-0.1.2/src/cuda_doctor/diagnosis/__init__.py +1 -0
- cuda_doctor-0.1.2/src/cuda_doctor/diagnosis/engine.py +69 -0
- cuda_doctor-0.1.2/src/cuda_doctor/diagnosis/issue.py +69 -0
- cuda_doctor-0.1.2/src/cuda_doctor/diagnosis/recommendations.py +133 -0
- cuda_doctor-0.1.2/src/cuda_doctor/py.typed +0 -0
- cuda_doctor-0.1.2/src/cuda_doctor/reporters/__init__.py +17 -0
- cuda_doctor-0.1.2/src/cuda_doctor/reporters/base.py +36 -0
- cuda_doctor-0.1.2/src/cuda_doctor/reporters/json_report.py +35 -0
- cuda_doctor-0.1.2/src/cuda_doctor/reporters/markdown.py +151 -0
- cuda_doctor-0.1.2/src/cuda_doctor/reporters/terminal.py +364 -0
- cuda_doctor-0.1.2/src/cuda_doctor/utils/__init__.py +1 -0
- cuda_doctor-0.1.2/src/cuda_doctor/utils/commands.py +99 -0
- cuda_doctor-0.1.2/src/cuda_doctor/utils/parsing.py +107 -0
- cuda_doctor-0.1.2/src/cuda_doctor/utils/paths.py +99 -0
- cuda_doctor-0.1.2/src/cuda_doctor/utils/platform.py +18 -0
- cuda_doctor-0.1.2/src/cuda_doctor/utils/redact.py +58 -0
- cuda_doctor-0.1.2/src/cuda_doctor/utils/versions.py +88 -0
- cuda_doctor-0.1.2/src/cuda_doctor/version.py +3 -0
- cuda_doctor-0.1.2/src/cuda_doctor.egg-info/PKG-INFO +276 -0
- cuda_doctor-0.1.2/src/cuda_doctor.egg-info/SOURCES.txt +62 -0
- cuda_doctor-0.1.2/src/cuda_doctor.egg-info/dependency_links.txt +1 -0
- cuda_doctor-0.1.2/src/cuda_doctor.egg-info/entry_points.txt +2 -0
- cuda_doctor-0.1.2/src/cuda_doctor.egg-info/requires.txt +9 -0
- cuda_doctor-0.1.2/src/cuda_doctor.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 cuda-doctor contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cuda-doctor
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Local CUDA / PyTorch development environment diagnostic tool
|
|
5
|
+
Author: cuda-doctor contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/TheManWhoIsStupid/cuda-doctor
|
|
8
|
+
Project-URL: Issues, https://github.com/TheManWhoIsStupid/cuda-doctor/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/TheManWhoIsStupid/cuda-doctor/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: cuda,pytorch,nvidia,gpu,diagnostics,developer-tools
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
22
|
+
Classifier: Topic :: System :: Systems Administration
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: typer>=0.9
|
|
27
|
+
Requires-Dist: rich>=13.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
32
|
+
Requires-Dist: mypy>=1.8; extra == "dev"
|
|
33
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# cuda-doctor
|
|
37
|
+
|
|
38
|
+
[](https://github.com/TheManWhoIsStupid/cuda-doctor/actions/workflows/ci.yml)
|
|
39
|
+
|
|
40
|
+
> Read-only local diagnostics for CUDA / PyTorch development environments.
|
|
41
|
+
>
|
|
42
|
+
> Detect → Analyze → Explain → Recommend. Never modifies your system.
|
|
43
|
+
|
|
44
|
+
`cuda-doctor` inspects your machine the way a colleague would before helping you
|
|
45
|
+
debug a CUDA problem: it looks at the GPUs, the NVIDIA driver, the CUDA toolkit(s)
|
|
46
|
+
on disk and on `PATH`, the host compiler, and your PyTorch install — then tells
|
|
47
|
+
you what looks wrong, why, and what to do about it.
|
|
48
|
+
|
|
49
|
+
It is inspired by `flutter doctor`: findings are explained in plain language,
|
|
50
|
+
and a completed run always exits `0` (only internal tool failures exit non-zero).
|
|
51
|
+
|
|
52
|
+
## Quick start
|
|
53
|
+
|
|
54
|
+
Install from PyPI (Python 3.10+):
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Linux / macOS
|
|
58
|
+
python -m pip install cuda-doctor
|
|
59
|
+
|
|
60
|
+
# Windows
|
|
61
|
+
py -m pip install cuda-doctor
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Then run it:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
cuda-doctor # full diagnosis, terminal report
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
> **Install it where your PyTorch lives.** cuda-doctor imports PyTorch
|
|
71
|
+
> in-process from the Python environment it runs in. To diagnose the PyTorch
|
|
72
|
+
> in one of your conda/venv environments, install and run it *inside* that
|
|
73
|
+
> environment:
|
|
74
|
+
>
|
|
75
|
+
> ```bash
|
|
76
|
+
> conda activate my-torch-env
|
|
77
|
+
> python -m pip install cuda-doctor
|
|
78
|
+
> cuda-doctor
|
|
79
|
+
> ```
|
|
80
|
+
>
|
|
81
|
+
> For the same reason, prefer `pip install` over [pipx](https://pipx.pypa.io):
|
|
82
|
+
> a pipx install runs in its own isolated environment and cannot see the
|
|
83
|
+
> PyTorch installed in your conda/venv environment — it would report
|
|
84
|
+
> "torch not installed" even when it is.
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
CUDA Doctor v0.1.2
|
|
88
|
+
|
|
89
|
+
System
|
|
90
|
+
OS Linux Ubuntu 22.04.5 LTS (kernel 5.15.0-91-generic)
|
|
91
|
+
...
|
|
92
|
+
NVIDIA Driver
|
|
93
|
+
Version 580.126.09
|
|
94
|
+
Reported CUDA 13.0
|
|
95
|
+
...
|
|
96
|
+
Summary
|
|
97
|
+
Status: HEALTHY (2 info)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Commands
|
|
101
|
+
|
|
102
|
+
| Command | What it does |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| `cuda-doctor` | Same as `cuda-doctor diagnose` |
|
|
105
|
+
| `cuda-doctor diagnose` | Full diagnosis, terminal report |
|
|
106
|
+
| `cuda-doctor diagnose --verbose` | Also show info-level notes and probe errors |
|
|
107
|
+
| `cuda-doctor diagnose --format json` | Machine-readable report (schema v1) |
|
|
108
|
+
| `cuda-doctor diagnose --format markdown --output report.md` | Write a shareable report |
|
|
109
|
+
| `cuda-doctor info` | Tool metadata: version, checks, issue codes |
|
|
110
|
+
| `cuda-doctor --version` | Version |
|
|
111
|
+
|
|
112
|
+
`python -m cuda_doctor …` works identically to the `cuda-doctor` entry point.
|
|
113
|
+
|
|
114
|
+
**Exit codes:** `0` the diagnosis ran (regardless of findings) · `2` internal
|
|
115
|
+
fatal error. Findings never change the exit code — this is a diagnostician, not
|
|
116
|
+
a CI gate.
|
|
117
|
+
|
|
118
|
+
## What it checks (v0.1)
|
|
119
|
+
|
|
120
|
+
| Area | Codes | Highlights |
|
|
121
|
+
| --- | --- | --- |
|
|
122
|
+
| GPU | `GPU001`–`GPU003` | nvidia-smi missing, no GPUs, smi execution failure |
|
|
123
|
+
| Driver | `DRV001`–`DRV002` | unknown driver version; driver below the documented minimum for the toolkit's CUDA generation |
|
|
124
|
+
| CUDA | `CUDA001`–`CUDA006` | no nvcc; CUDA_HOME unset/invalid; multiple toolkits; multiple CUDA bins in PATH; nvcc ≠ CUDA_HOME |
|
|
125
|
+
| PyTorch | `TORCH001`–`TORCH006` | not installed; import failures (with known-signature advice); `is_available()` False; CPU-only wheel; runtime vs toolkit; runtime from a newer CUDA generation than the driver |
|
|
126
|
+
| Compiler | `CMP001`–`CMP002` | no host compiler; gcc/Visual Studio outside the toolkit's supported range |
|
|
127
|
+
| Environment | `ENV001`–`ENV004` | stale CUDA paths; duplicates; conflicting `LD_LIBRARY_PATH`; older CUDA shadowing newer in PATH |
|
|
128
|
+
|
|
129
|
+
Every finding carries a stable issue code, evidence, and concrete
|
|
130
|
+
recommendations. Example reports: [`examples/sample_report.md`](examples/sample_report.md)
|
|
131
|
+
· [`examples/sample_report.json`](examples/sample_report.json).
|
|
132
|
+
|
|
133
|
+
### The nuance that matters: three different "CUDA versions"
|
|
134
|
+
|
|
135
|
+
A machine reports three unrelated CUDA versions, and most false alarms in CUDA
|
|
136
|
+
debugging tools come from comparing the wrong pair:
|
|
137
|
+
|
|
138
|
+
1. **The local toolkit** (`nvcc --version`) — what you *compile* with.
|
|
139
|
+
2. **PyTorch's bundled runtime** (`torch.version.cuda`) — the CUDA libraries
|
|
140
|
+
shipped inside the wheel; official wheels bundle their own runtime, so it
|
|
141
|
+
does not have to match the local toolkit (`TORCH004` stays INFO).
|
|
142
|
+
3. **The driver's CUDA UMD version** (the `CUDA Version:` line in
|
|
143
|
+
`nvidia-smi`) — the toolkit generation the driver was *validated with*.
|
|
144
|
+
It is **not a hard ceiling**.
|
|
145
|
+
|
|
146
|
+
That third point is the one most tools get wrong. Since CUDA 11, NVIDIA
|
|
147
|
+
supports **CUDA minor-version compatibility**: within a CUDA major family
|
|
148
|
+
(e.g. any CUDA 12.x), applications built with a newer minor release run on
|
|
149
|
+
older drivers of the same generation, as long as the driver meets the
|
|
150
|
+
documented family minimum (Linux 525.60.13 / Windows 528.33 for CUDA 12.x;
|
|
151
|
+
for CUDA 13.x the documented rule is the R580 driver branch, i.e. >= 580).
|
|
152
|
+
So "toolkit 12.6, nvidia-smi says 12.2" is at most an informational note
|
|
153
|
+
(`DRV002` INFO), not an error — with the caveats that newer
|
|
154
|
+
driver-dependent features and newer PTX may still need a driver update.
|
|
155
|
+
|
|
156
|
+
What *is* a genuine error is a **generation gap** — a CUDA 13 toolkit or
|
|
157
|
+
PyTorch runtime on a CUDA 12-generation driver (`DRV002`/`TORCH006`) — and
|
|
158
|
+
even then only when CUDA is not observed working: if
|
|
159
|
+
`torch.cuda.is_available()` is `True`, observed runtime success always
|
|
160
|
+
overrides the static version comparison.
|
|
161
|
+
|
|
162
|
+
## Platforms
|
|
163
|
+
|
|
164
|
+
- **Linux** — first-class; developed and continuously smoke-tested on Ubuntu
|
|
165
|
+
22.04 with NVIDIA H20 GPUs and 4 parallel CUDA toolkit installations.
|
|
166
|
+
- **Windows** — supported (separate code paths for `CUDA_PATH*` variables,
|
|
167
|
+
Visual Studio detection via vswhere, `CREATE_NO_WINDOW` on subprocesses).
|
|
168
|
+
Automated tests cover the Windows code paths with simulated environments;
|
|
169
|
+
real-hardware validation is ongoing.
|
|
170
|
+
- **macOS** — runs and reports "no NVIDIA driver" as informational (Apple
|
|
171
|
+
Silicon is out of scope for v0.1).
|
|
172
|
+
|
|
173
|
+
## Privacy
|
|
174
|
+
|
|
175
|
+
Reports are designed to be shareable:
|
|
176
|
+
|
|
177
|
+
- your home directory is rewritten to `~`, leftover usernames to `<user>`;
|
|
178
|
+
- hostname and username are never collected in the first place;
|
|
179
|
+
- `PATH`/`LD_LIBRARY_PATH` are shown only as the CUDA-relevant subset, never
|
|
180
|
+
dumped in full;
|
|
181
|
+
- nvidia-smi output excerpts are truncated.
|
|
182
|
+
|
|
183
|
+
Still, a JSON report describes your hardware and software stack — read it
|
|
184
|
+
before posting publicly.
|
|
185
|
+
|
|
186
|
+
## Architecture
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
CLI (Typer) ─ CollectionRunner ─▶ Collectors (facts only)
|
|
190
|
+
│ subprocess (no shell, timeouts),
|
|
191
|
+
│ filesystem, env, torch import
|
|
192
|
+
▼
|
|
193
|
+
EnvironmentSnapshot
|
|
194
|
+
(dataclasses; absence = None)
|
|
195
|
+
│
|
|
196
|
+
DiagnosisEngine (24 checks)
|
|
197
|
+
+ bundled compatibility JSON
|
|
198
|
+
▼
|
|
199
|
+
Issues + Summary
|
|
200
|
+
▼
|
|
201
|
+
Reporters: terminal / JSON / Markdown
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Key invariants (see `AGENTS.md`):
|
|
205
|
+
|
|
206
|
+
- **Collectors never judge; checks never collect.** Rules are pure functions of
|
|
207
|
+
the snapshot (+ compatibility data), which makes them unit-testable without
|
|
208
|
+
hardware.
|
|
209
|
+
- **Safe failure over crashes.** Every external probe is guarded; a failing
|
|
210
|
+
collector surfaces as data, not an exception.
|
|
211
|
+
- **Compatibility knowledge is data**, versioned JSON inside the package
|
|
212
|
+
(`src/cuda_doctor/data/`), updatable without touching logic.
|
|
213
|
+
- **Read-only, always.** v0.1 executes no command that modifies the system.
|
|
214
|
+
|
|
215
|
+
## Limitations (v0.1)
|
|
216
|
+
|
|
217
|
+
- Single-user, single-machine scope; no container/WSL-specific detection.
|
|
218
|
+
- Compatibility decisions are deliberately **conservative**: driver minimums
|
|
219
|
+
follow NVIDIA's documented CUDA minor-version-compatibility baselines per
|
|
220
|
+
major family, and anything the bundled knowledge does not cover — a future
|
|
221
|
+
CUDA major (e.g. CUDA 14 before the data ships), an unlisted toolkit minor
|
|
222
|
+
for compiler rules, or an unreported driver version — is reported as
|
|
223
|
+
**unknown**, never guessed from older versions.
|
|
224
|
+
- Compiler compatibility tables are coarse and worded as *potential* issues;
|
|
225
|
+
the definitive source is always the CUDA Installation Guide for your
|
|
226
|
+
toolkit version.
|
|
227
|
+
- No conda-environment awareness beyond what `PATH`/env vars imply.
|
|
228
|
+
- nvidia-smi is the only GPU source; `NVML`/`lspci` fallbacks are future work.
|
|
229
|
+
- Chinese localization is planned (the maintainers are bilingual); v0.1 output
|
|
230
|
+
is English.
|
|
231
|
+
|
|
232
|
+
## Development
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
bash scripts/dev_install.sh # Linux/macOS (pip install -e ".[dev]")
|
|
236
|
+
# or: pwsh scripts/dev_install.ps1 (Windows)
|
|
237
|
+
|
|
238
|
+
pytest # 310 tests: unit + integration (hermetic)
|
|
239
|
+
ruff check src tests # lint
|
|
240
|
+
mypy # types (strict-ish: disallow_untyped_defs)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
CI runs the same commands on Ubuntu and Windows across Python 3.10–3.13
|
|
244
|
+
(`.github/workflows/ci.yml`) — no GPU, driver, CUDA, or PyTorch required.
|
|
245
|
+
|
|
246
|
+
The test suite needs **no GPU and no CUDA**: collectors run against an injected
|
|
247
|
+
fake command runner, and real parser fixtures captured from actual H20 /
|
|
248
|
+
RTX 4090 machines live under `tests/fixtures/`.
|
|
249
|
+
|
|
250
|
+
### Repository layout
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
src/cuda_doctor/
|
|
254
|
+
├── cli.py # Typer app: diagnose / info / --version
|
|
255
|
+
├── core/ # models, enums, CollectionRunner, exceptions
|
|
256
|
+
├── collectors/ # one module per fact source
|
|
257
|
+
├── checks/ # 24 diagnostic rules (pure)
|
|
258
|
+
├── diagnosis/ # engine, Issue/Summary, recommendations
|
|
259
|
+
├── compatibility/ # driver/compiler/torch knowledge + JSON loading
|
|
260
|
+
├── reporters/ # terminal (Rich), JSON, Markdown
|
|
261
|
+
├── data/ # bundled compatibility tables
|
|
262
|
+
└── utils/ # commands, parsing, paths, redaction, versions
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Roadmap (v0.2+)
|
|
266
|
+
|
|
267
|
+
- NVML and `lspci` fallbacks when nvidia-smi is absent or broken.
|
|
268
|
+
- Conda-aware environment inspection.
|
|
269
|
+
- `--json-schema` self-description and a stable JSON schema contract test.
|
|
270
|
+
- WSL detection and WSL-specific driver mismatch explanations.
|
|
271
|
+
- Chinese output (`--lang zh`).
|
|
272
|
+
- `cuda-doctor fix --dry-run` advisory mode (still no modifications in v0.2).
|
|
273
|
+
|
|
274
|
+
## License
|
|
275
|
+
|
|
276
|
+
MIT — see `LICENSE`.
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# cuda-doctor
|
|
2
|
+
|
|
3
|
+
[](https://github.com/TheManWhoIsStupid/cuda-doctor/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
> Read-only local diagnostics for CUDA / PyTorch development environments.
|
|
6
|
+
>
|
|
7
|
+
> Detect → Analyze → Explain → Recommend. Never modifies your system.
|
|
8
|
+
|
|
9
|
+
`cuda-doctor` inspects your machine the way a colleague would before helping you
|
|
10
|
+
debug a CUDA problem: it looks at the GPUs, the NVIDIA driver, the CUDA toolkit(s)
|
|
11
|
+
on disk and on `PATH`, the host compiler, and your PyTorch install — then tells
|
|
12
|
+
you what looks wrong, why, and what to do about it.
|
|
13
|
+
|
|
14
|
+
It is inspired by `flutter doctor`: findings are explained in plain language,
|
|
15
|
+
and a completed run always exits `0` (only internal tool failures exit non-zero).
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
Install from PyPI (Python 3.10+):
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Linux / macOS
|
|
23
|
+
python -m pip install cuda-doctor
|
|
24
|
+
|
|
25
|
+
# Windows
|
|
26
|
+
py -m pip install cuda-doctor
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Then run it:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
cuda-doctor # full diagnosis, terminal report
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
> **Install it where your PyTorch lives.** cuda-doctor imports PyTorch
|
|
36
|
+
> in-process from the Python environment it runs in. To diagnose the PyTorch
|
|
37
|
+
> in one of your conda/venv environments, install and run it *inside* that
|
|
38
|
+
> environment:
|
|
39
|
+
>
|
|
40
|
+
> ```bash
|
|
41
|
+
> conda activate my-torch-env
|
|
42
|
+
> python -m pip install cuda-doctor
|
|
43
|
+
> cuda-doctor
|
|
44
|
+
> ```
|
|
45
|
+
>
|
|
46
|
+
> For the same reason, prefer `pip install` over [pipx](https://pipx.pypa.io):
|
|
47
|
+
> a pipx install runs in its own isolated environment and cannot see the
|
|
48
|
+
> PyTorch installed in your conda/venv environment — it would report
|
|
49
|
+
> "torch not installed" even when it is.
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
CUDA Doctor v0.1.2
|
|
53
|
+
|
|
54
|
+
System
|
|
55
|
+
OS Linux Ubuntu 22.04.5 LTS (kernel 5.15.0-91-generic)
|
|
56
|
+
...
|
|
57
|
+
NVIDIA Driver
|
|
58
|
+
Version 580.126.09
|
|
59
|
+
Reported CUDA 13.0
|
|
60
|
+
...
|
|
61
|
+
Summary
|
|
62
|
+
Status: HEALTHY (2 info)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Commands
|
|
66
|
+
|
|
67
|
+
| Command | What it does |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `cuda-doctor` | Same as `cuda-doctor diagnose` |
|
|
70
|
+
| `cuda-doctor diagnose` | Full diagnosis, terminal report |
|
|
71
|
+
| `cuda-doctor diagnose --verbose` | Also show info-level notes and probe errors |
|
|
72
|
+
| `cuda-doctor diagnose --format json` | Machine-readable report (schema v1) |
|
|
73
|
+
| `cuda-doctor diagnose --format markdown --output report.md` | Write a shareable report |
|
|
74
|
+
| `cuda-doctor info` | Tool metadata: version, checks, issue codes |
|
|
75
|
+
| `cuda-doctor --version` | Version |
|
|
76
|
+
|
|
77
|
+
`python -m cuda_doctor …` works identically to the `cuda-doctor` entry point.
|
|
78
|
+
|
|
79
|
+
**Exit codes:** `0` the diagnosis ran (regardless of findings) · `2` internal
|
|
80
|
+
fatal error. Findings never change the exit code — this is a diagnostician, not
|
|
81
|
+
a CI gate.
|
|
82
|
+
|
|
83
|
+
## What it checks (v0.1)
|
|
84
|
+
|
|
85
|
+
| Area | Codes | Highlights |
|
|
86
|
+
| --- | --- | --- |
|
|
87
|
+
| GPU | `GPU001`–`GPU003` | nvidia-smi missing, no GPUs, smi execution failure |
|
|
88
|
+
| Driver | `DRV001`–`DRV002` | unknown driver version; driver below the documented minimum for the toolkit's CUDA generation |
|
|
89
|
+
| CUDA | `CUDA001`–`CUDA006` | no nvcc; CUDA_HOME unset/invalid; multiple toolkits; multiple CUDA bins in PATH; nvcc ≠ CUDA_HOME |
|
|
90
|
+
| PyTorch | `TORCH001`–`TORCH006` | not installed; import failures (with known-signature advice); `is_available()` False; CPU-only wheel; runtime vs toolkit; runtime from a newer CUDA generation than the driver |
|
|
91
|
+
| Compiler | `CMP001`–`CMP002` | no host compiler; gcc/Visual Studio outside the toolkit's supported range |
|
|
92
|
+
| Environment | `ENV001`–`ENV004` | stale CUDA paths; duplicates; conflicting `LD_LIBRARY_PATH`; older CUDA shadowing newer in PATH |
|
|
93
|
+
|
|
94
|
+
Every finding carries a stable issue code, evidence, and concrete
|
|
95
|
+
recommendations. Example reports: [`examples/sample_report.md`](examples/sample_report.md)
|
|
96
|
+
· [`examples/sample_report.json`](examples/sample_report.json).
|
|
97
|
+
|
|
98
|
+
### The nuance that matters: three different "CUDA versions"
|
|
99
|
+
|
|
100
|
+
A machine reports three unrelated CUDA versions, and most false alarms in CUDA
|
|
101
|
+
debugging tools come from comparing the wrong pair:
|
|
102
|
+
|
|
103
|
+
1. **The local toolkit** (`nvcc --version`) — what you *compile* with.
|
|
104
|
+
2. **PyTorch's bundled runtime** (`torch.version.cuda`) — the CUDA libraries
|
|
105
|
+
shipped inside the wheel; official wheels bundle their own runtime, so it
|
|
106
|
+
does not have to match the local toolkit (`TORCH004` stays INFO).
|
|
107
|
+
3. **The driver's CUDA UMD version** (the `CUDA Version:` line in
|
|
108
|
+
`nvidia-smi`) — the toolkit generation the driver was *validated with*.
|
|
109
|
+
It is **not a hard ceiling**.
|
|
110
|
+
|
|
111
|
+
That third point is the one most tools get wrong. Since CUDA 11, NVIDIA
|
|
112
|
+
supports **CUDA minor-version compatibility**: within a CUDA major family
|
|
113
|
+
(e.g. any CUDA 12.x), applications built with a newer minor release run on
|
|
114
|
+
older drivers of the same generation, as long as the driver meets the
|
|
115
|
+
documented family minimum (Linux 525.60.13 / Windows 528.33 for CUDA 12.x;
|
|
116
|
+
for CUDA 13.x the documented rule is the R580 driver branch, i.e. >= 580).
|
|
117
|
+
So "toolkit 12.6, nvidia-smi says 12.2" is at most an informational note
|
|
118
|
+
(`DRV002` INFO), not an error — with the caveats that newer
|
|
119
|
+
driver-dependent features and newer PTX may still need a driver update.
|
|
120
|
+
|
|
121
|
+
What *is* a genuine error is a **generation gap** — a CUDA 13 toolkit or
|
|
122
|
+
PyTorch runtime on a CUDA 12-generation driver (`DRV002`/`TORCH006`) — and
|
|
123
|
+
even then only when CUDA is not observed working: if
|
|
124
|
+
`torch.cuda.is_available()` is `True`, observed runtime success always
|
|
125
|
+
overrides the static version comparison.
|
|
126
|
+
|
|
127
|
+
## Platforms
|
|
128
|
+
|
|
129
|
+
- **Linux** — first-class; developed and continuously smoke-tested on Ubuntu
|
|
130
|
+
22.04 with NVIDIA H20 GPUs and 4 parallel CUDA toolkit installations.
|
|
131
|
+
- **Windows** — supported (separate code paths for `CUDA_PATH*` variables,
|
|
132
|
+
Visual Studio detection via vswhere, `CREATE_NO_WINDOW` on subprocesses).
|
|
133
|
+
Automated tests cover the Windows code paths with simulated environments;
|
|
134
|
+
real-hardware validation is ongoing.
|
|
135
|
+
- **macOS** — runs and reports "no NVIDIA driver" as informational (Apple
|
|
136
|
+
Silicon is out of scope for v0.1).
|
|
137
|
+
|
|
138
|
+
## Privacy
|
|
139
|
+
|
|
140
|
+
Reports are designed to be shareable:
|
|
141
|
+
|
|
142
|
+
- your home directory is rewritten to `~`, leftover usernames to `<user>`;
|
|
143
|
+
- hostname and username are never collected in the first place;
|
|
144
|
+
- `PATH`/`LD_LIBRARY_PATH` are shown only as the CUDA-relevant subset, never
|
|
145
|
+
dumped in full;
|
|
146
|
+
- nvidia-smi output excerpts are truncated.
|
|
147
|
+
|
|
148
|
+
Still, a JSON report describes your hardware and software stack — read it
|
|
149
|
+
before posting publicly.
|
|
150
|
+
|
|
151
|
+
## Architecture
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
CLI (Typer) ─ CollectionRunner ─▶ Collectors (facts only)
|
|
155
|
+
│ subprocess (no shell, timeouts),
|
|
156
|
+
│ filesystem, env, torch import
|
|
157
|
+
▼
|
|
158
|
+
EnvironmentSnapshot
|
|
159
|
+
(dataclasses; absence = None)
|
|
160
|
+
│
|
|
161
|
+
DiagnosisEngine (24 checks)
|
|
162
|
+
+ bundled compatibility JSON
|
|
163
|
+
▼
|
|
164
|
+
Issues + Summary
|
|
165
|
+
▼
|
|
166
|
+
Reporters: terminal / JSON / Markdown
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Key invariants (see `AGENTS.md`):
|
|
170
|
+
|
|
171
|
+
- **Collectors never judge; checks never collect.** Rules are pure functions of
|
|
172
|
+
the snapshot (+ compatibility data), which makes them unit-testable without
|
|
173
|
+
hardware.
|
|
174
|
+
- **Safe failure over crashes.** Every external probe is guarded; a failing
|
|
175
|
+
collector surfaces as data, not an exception.
|
|
176
|
+
- **Compatibility knowledge is data**, versioned JSON inside the package
|
|
177
|
+
(`src/cuda_doctor/data/`), updatable without touching logic.
|
|
178
|
+
- **Read-only, always.** v0.1 executes no command that modifies the system.
|
|
179
|
+
|
|
180
|
+
## Limitations (v0.1)
|
|
181
|
+
|
|
182
|
+
- Single-user, single-machine scope; no container/WSL-specific detection.
|
|
183
|
+
- Compatibility decisions are deliberately **conservative**: driver minimums
|
|
184
|
+
follow NVIDIA's documented CUDA minor-version-compatibility baselines per
|
|
185
|
+
major family, and anything the bundled knowledge does not cover — a future
|
|
186
|
+
CUDA major (e.g. CUDA 14 before the data ships), an unlisted toolkit minor
|
|
187
|
+
for compiler rules, or an unreported driver version — is reported as
|
|
188
|
+
**unknown**, never guessed from older versions.
|
|
189
|
+
- Compiler compatibility tables are coarse and worded as *potential* issues;
|
|
190
|
+
the definitive source is always the CUDA Installation Guide for your
|
|
191
|
+
toolkit version.
|
|
192
|
+
- No conda-environment awareness beyond what `PATH`/env vars imply.
|
|
193
|
+
- nvidia-smi is the only GPU source; `NVML`/`lspci` fallbacks are future work.
|
|
194
|
+
- Chinese localization is planned (the maintainers are bilingual); v0.1 output
|
|
195
|
+
is English.
|
|
196
|
+
|
|
197
|
+
## Development
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
bash scripts/dev_install.sh # Linux/macOS (pip install -e ".[dev]")
|
|
201
|
+
# or: pwsh scripts/dev_install.ps1 (Windows)
|
|
202
|
+
|
|
203
|
+
pytest # 310 tests: unit + integration (hermetic)
|
|
204
|
+
ruff check src tests # lint
|
|
205
|
+
mypy # types (strict-ish: disallow_untyped_defs)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
CI runs the same commands on Ubuntu and Windows across Python 3.10–3.13
|
|
209
|
+
(`.github/workflows/ci.yml`) — no GPU, driver, CUDA, or PyTorch required.
|
|
210
|
+
|
|
211
|
+
The test suite needs **no GPU and no CUDA**: collectors run against an injected
|
|
212
|
+
fake command runner, and real parser fixtures captured from actual H20 /
|
|
213
|
+
RTX 4090 machines live under `tests/fixtures/`.
|
|
214
|
+
|
|
215
|
+
### Repository layout
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
src/cuda_doctor/
|
|
219
|
+
├── cli.py # Typer app: diagnose / info / --version
|
|
220
|
+
├── core/ # models, enums, CollectionRunner, exceptions
|
|
221
|
+
├── collectors/ # one module per fact source
|
|
222
|
+
├── checks/ # 24 diagnostic rules (pure)
|
|
223
|
+
├── diagnosis/ # engine, Issue/Summary, recommendations
|
|
224
|
+
├── compatibility/ # driver/compiler/torch knowledge + JSON loading
|
|
225
|
+
├── reporters/ # terminal (Rich), JSON, Markdown
|
|
226
|
+
├── data/ # bundled compatibility tables
|
|
227
|
+
└── utils/ # commands, parsing, paths, redaction, versions
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Roadmap (v0.2+)
|
|
231
|
+
|
|
232
|
+
- NVML and `lspci` fallbacks when nvidia-smi is absent or broken.
|
|
233
|
+
- Conda-aware environment inspection.
|
|
234
|
+
- `--json-schema` self-description and a stable JSON schema contract test.
|
|
235
|
+
- WSL detection and WSL-specific driver mismatch explanations.
|
|
236
|
+
- Chinese output (`--lang zh`).
|
|
237
|
+
- `cuda-doctor fix --dry-run` advisory mode (still no modifications in v0.2).
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
MIT — see `LICENSE`.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77.0.3"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cuda-doctor"
|
|
7
|
+
description = "Local CUDA / PyTorch development environment diagnostic tool"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
authors = [{ name = "cuda-doctor contributors" }]
|
|
13
|
+
keywords = ["cuda", "pytorch", "nvidia", "gpu", "diagnostics", "developer-tools"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Environment :: Console",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Operating System :: Microsoft :: Windows",
|
|
19
|
+
"Operating System :: POSIX :: Linux",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Topic :: Software Development :: Debuggers",
|
|
26
|
+
"Topic :: System :: Systems Administration",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"typer>=0.9",
|
|
30
|
+
"rich>=13.0",
|
|
31
|
+
]
|
|
32
|
+
dynamic = ["version"]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://github.com/TheManWhoIsStupid/cuda-doctor"
|
|
36
|
+
Issues = "https://github.com/TheManWhoIsStupid/cuda-doctor/issues"
|
|
37
|
+
Changelog = "https://github.com/TheManWhoIsStupid/cuda-doctor/blob/main/CHANGELOG.md"
|
|
38
|
+
|
|
39
|
+
[project.optional-dependencies]
|
|
40
|
+
dev = [
|
|
41
|
+
"pytest>=7.0",
|
|
42
|
+
"pytest-cov",
|
|
43
|
+
"ruff>=0.4",
|
|
44
|
+
"mypy>=1.8",
|
|
45
|
+
"pre-commit",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[project.scripts]
|
|
49
|
+
cuda-doctor = "cuda_doctor.cli:main"
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.dynamic]
|
|
52
|
+
version = { attr = "cuda_doctor.version.__version__" }
|
|
53
|
+
|
|
54
|
+
[tool.setuptools.packages.find]
|
|
55
|
+
where = ["src"]
|
|
56
|
+
|
|
57
|
+
[tool.setuptools.package-data]
|
|
58
|
+
cuda_doctor = ["py.typed", "data/*.json"]
|
|
59
|
+
|
|
60
|
+
[tool.pytest.ini_options]
|
|
61
|
+
testpaths = ["tests"]
|
|
62
|
+
addopts = "-q"
|
|
63
|
+
# Tests import each other as `tests.*` (namespace package); bare `pytest`
|
|
64
|
+
# does not put the repo root on sys.path the way `python -m pytest` does.
|
|
65
|
+
pythonpath = ["."]
|
|
66
|
+
|
|
67
|
+
[tool.coverage.run]
|
|
68
|
+
source = ["cuda_doctor"]
|
|
69
|
+
|
|
70
|
+
[tool.ruff]
|
|
71
|
+
line-length = 100
|
|
72
|
+
src = ["src", "tests"]
|
|
73
|
+
|
|
74
|
+
[tool.ruff.lint]
|
|
75
|
+
select = [
|
|
76
|
+
"E", # pycodestyle errors
|
|
77
|
+
"W", # pycodestyle warnings
|
|
78
|
+
"F", # pyflakes
|
|
79
|
+
"I", # isort
|
|
80
|
+
"UP", # pyupgrade
|
|
81
|
+
"B", # bugbear
|
|
82
|
+
"C4", # comprehensions
|
|
83
|
+
"SIM", # simplify
|
|
84
|
+
"RUF", # ruff-specific
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
[tool.ruff.lint.per-file-ignores]
|
|
88
|
+
# typer.Option() in parameter defaults is the framework's intended idiom.
|
|
89
|
+
"src/cuda_doctor/cli.py" = ["B008"]
|
|
90
|
+
|
|
91
|
+
[tool.mypy]
|
|
92
|
+
python_version = "3.10"
|
|
93
|
+
mypy_path = "src"
|
|
94
|
+
files = ["src"]
|
|
95
|
+
warn_unused_ignores = true
|
|
96
|
+
warn_redundant_casts = true
|
|
97
|
+
no_implicit_optional = true
|
|
98
|
+
disallow_untyped_defs = true
|
|
99
|
+
check_untyped_defs = true
|