[CUDA Graph] Size-specific ~2.1× slowdown for contiguous CUDA `Tensor.copy_` on GB200
- Dominant language
- Python
- Stars
- 103k
- Forks
- 29.5k
- PR merge metrics
- PR metrics pending
Description
### 🐛 Describe the bug
> **AI-assistance disclosure:** I used codex
A contiguous, same-dtype CUDA-to-CUDA `Tensor.copy_` normally sustains about
6.5–6.8 TB/s in both eager execution and CUDA Graph replay. However, **graph
replay falls to approximately 3.1 TB/s at exactly 512 MiB and for the tested
1 GiB and 2 GiB memcpy nodes**, while the adjacent 508 MiB and 516 MiB cases
remain near full bandwidth. Splitting the 1 GiB and 2 GiB transfers into
256 MiB graph nodes also restores full bandwidth. Rates count one source read
plus one destination write: `2 × bytes / complete CUDA-event time`, in decimal
TB/s.
## Measurements
A contiguous CUDA-to-CUDA `Tensor.copy_` slows down only at specific CUDA
Graph memcpy-node sizes. Rates count one source read plus one destination
write: `2 × bytes / complete CUDA-event time`, in decimal TB/s.
| Total copy | Nodes | MiB/node | Eager time | Graph time | Eager TB/s | Graph TB/s |
| ---: | ---: | ---: | ---: | ---: | ---: | ---: |
| 508 MiB | 1 | 508 | 0.158183 ms | 0.158042 ms | 6.735 | 6.741 |
| 512 MiB | 1 | 512 | 0.165612 ms | 0.347006 ms | 6.483 | **3.094** |
| 516 MiB | 1 | 516 | 0.160397 ms | 0.160734 ms | 6.747 | 6.732 |
| 1 GiB | 1 | 1,024 | 0.319806 ms | 0.689774 ms | 6.715 | **3.113** |
| 1 GiB | 4 | 256 | 0.328524 ms | 0.323698 ms | 6.537 | 6.634 |
| 2 GiB | 1 | 2,048 | 0.630680 ms | 1.375304 ms | 6.810 | **3.123** |
| 2 GiB | 8 | 256 | 0.656700 ms | 0.641940 ms | 6.540 | 6.691 |
## Reproduction
```python
import statistics
import torch
MIB = 1 << 20
def timed_ms(issue, iterations):
for _ in range(3):
issue()
torch.cuda.synchronize()
samples = []
for _ in range(7):
start = torch.cuda.Event(enable_timing=True)
stop = torch.cuda.Event(enable_timing=True)
start.record()
for _ in range(iterations):
issue()
stop.record()
stop.synchronize()
samples.append(start.elapsed_time(stop) / iterations)
return statistics.median(samples)
def benchmark(mib):
size = mib * MIB
source = torch.full((size,), 0xA5, dtype=torch.uint8, device="cuda")
destination = torch.empty_like(source)
def copy():
destination.copy_(source)
iterations = (16 << 30) // size
eager_ms = timed_ms(copy, iterations)
stream = torch.cuda.Stream()
stream.wait_stream(torch.cuda.current_stream())
with torch.cuda.stream(stream):
copy()
torch.cuda.current_stream().wait_stream(stream)
torch.cuda.synchronize()
graph = torch.cuda.CUDAGraph()
with torch.cuda.graph(graph, stream=stream):
copy()
graph_ms = timed_ms(graph.replay, iterations)
assert destination[0].item() == 0xA5
rate = lambda ms: 2 * size / (ms / 1000) / 1e12
return eager_ms, graph_ms, rate(eager_ms), rate(graph_ms)
print(torch.__version__, torch.version.cuda, torch.cuda.get_device_name(0))
print("MiB eager_ms graph_ms eager_TB/s graph_TB/s")
for mib in (508, 512, 516):
print(mib, *benchmark(mib))
```
### Versions
| Component | Value |
| --- | --- |
| GPU | NVIDIA GB200, compute capability 10.0, 152 SMs |
| GPU memory / L2 | 197,897,748,480 / 135,528,448 bytes |
| PyTorch | 2.13.0+cu132, git `cf30153c4c131c8164ee7798e5022d810682e2cb` |
| CUDA used to build PyTorch | 13.2 |
| Packaged CUDA runtime | 13.2.75 |
| NVIDIA driver / VBIOS | 580.82.07 / 97.00.B9.00.6B |
| Python / Triton | 3.12.13 / 3.7.1 |
| OS | CentOS Stream 9, aarch64, Linux 6.13.2, glibc 2.34 |
cc @ezyang @gchanan @kadeng @msaroufim @ptrblck @eqy @tinglvv @nWEIdia @mcarilli @eellison @penguinwu @BoyuanFeng
Contributor guide
Research direction
Start by running the Python reproduction on the specified GB200, PyTorch 2.13.0+cu132, and CUDA 13.2 environment, comparing the 508, 512, and 516 MiB cases and the split-node cases. Investigate the CUDA Graph replay path for contiguous CUDA-to-CUDA Tensor.copy_ operations. Done means the size-specific slowdown is explained and the affected graph copies no longer show the reported bandwidth drop.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100