Skip to content

Commit 2041f34

Browse files
committed
docs(gb10): memory reclaim recipe — fuser /dev/nvidia-uvm + SIGTERM frees orphan GPU mem without reboot; drop_caches is cache-only
Captures the incident: kill -9 of a batch=4 m04 mid-CUDA-alloc left ~100GB device-mapped (AnonPages tiny, ps/pgrep/nvidia-smi blind). fuser -v /dev/nvidia-uvm finds the orphan; SIGTERM releases it. drop_caches freed only ~0.5G (cache-only). Plus the 70GB benchmark memory cap.
1 parent 4a62306 commit 2041f34

1 file changed

Lines changed: 58 additions & 0 deletions

File tree

docs/GB10-MEMORY-RECLAIM.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# gb10 — reclaiming "stuck" memory WITHOUT a reboot
2+
3+
On the GB10 (Grace‑Blackwell, unified LPDDR5X), GPU allocations are carved out of
4+
system RAM. When a CUDA process is `kill -9`'d **mid‑allocation**, the runtime
5+
never releases the device memory, so `free` keeps showing it as **used** even
6+
though no process appears to own it. This looks like a 100 GB leak and a near‑frozen
7+
box (`avail` collapses to single‑digit GB).
8+
9+
## Why `ps`/`pgrep`/`nvidia-smi` don't find it
10+
11+
- The leaked memory is **device‑mapped**, not anonymous: `grep AnonPages /proc/meminfo`
12+
stays tiny (e.g. 495 MB) while `free` shows ~100 GB used. `ps --sort=-rss` shows
13+
nothing large (top process ~0.2 GB).
14+
- `nvidia-smi --query-compute-apps` / FB memory report **N/A** on GB10 (unified mem).
15+
- A pattern `pkill -f m04_train_step` can **miss** the holder: a `timeout 1800 python …`
16+
wrapper or a re‑exec'd child has a different cmdline, so the orphan survives.
17+
18+
## The reclaim recipe (no reboot, no `--gpu-reset`)
19+
20+
1. Find the real holder of CUDA managed memory — it lives on **`/dev/nvidia-uvm`**,
21+
not `/dev/nvidia0`:
22+
```sh
23+
ssh gb10 'fuser -v /dev/nvidia-uvm /dev/nvidia-uvm-tools'
24+
```
25+
This lists PIDs that `ps`/`pgrep`‑by‑name do not. The anomalous `python` entry
26+
(next to legit Xorg/gnome/firefox display holders) is the orphan.
27+
2. Kill it **cleanly** so the CUDA runtime releases the allocation:
28+
```sh
29+
ssh gb10 'kill -TERM <pid>' # SIGTERM first — lets CUDA free device mem
30+
# only escalate to kill -9 if TERM fails; a -9 mid-alloc is what leaks in the first place
31+
```
32+
Memory returns to `free` within a few seconds once the true holder dies.
33+
3. (Optional, cache pressure only) drop the page cache — reclaims **buff/cache**,
34+
NOT process/GPU memory:
35+
```sh
36+
ssh gb10 "sudo sh -c 'sync; echo 3 > /proc/sys/vm/drop_caches'"
37+
```
38+
In the leak case above this freed ~0.5 GB (cache was only ~1.3 GB) — it is the
39+
right tool for cache pressure, but it does **not** fix a GPU‑orphan leak. Use the
40+
`fuser` step for that.
41+
42+
## Verify
43+
44+
```sh
45+
ssh gb10 'free -g | awk "/^Mem:/{print \"used=\"\$3\"G avail=\"\$7\"G\"}"'
46+
# healthy gb10 idle baseline: used≈5-6G, avail≈115-119G of 121G
47+
```
48+
49+
## Prevention
50+
51+
- Never `kill -9` a CUDA process unless `kill -TERM` failed. SIGTERM lets MLX/torch
52+
tear down the context and release device memory; SIGKILL mid‑alloc leaks it.
53+
- After any kill, confirm with `fuser -v /dev/nvidia-uvm` that no orphan remains,
54+
then re‑check `free`.
55+
- Memory discipline for benchmarks on this box: ramp slowly (start bs=1 seq=512),
56+
sample `free -g` live, and abort if used grows past **70 GB**`bs=4 × seq=4096`
57+
(= 16,384 tok/step, 32× the bs=1/seq=512 footprint) does not fit this config in
58+
MLX‑eager and must not be forced.

0 commit comments

Comments
 (0)