Fix: Add GPU synchronization for cached tensor transfers#666
Conversation
- Add torch.cuda.synchronize() after non-blocking tensor transfers to GPU to ensure cached tensors are fully transferred before use - Prevents stale data issues where async transfers haven't completed - Only synchronizes on CUDA devices (no overhead on CPU) - Add comprehensive test_cache_gpu_synchronization() test to verify fix Fixes issue where cache.add() with device=cuda could return tensors that are still mid-transfer, causing stale data to be read by subsequent forward passes.
|
Thanks for the PR! Before we merge I want to make sure we're solving a real problem, because the fix as written has a significant performance cost and I'm not sure the bug it's describing can actually occur on the current code path. On
The two ways
Do you have a repro that fails on On the cost of the current fix
The test also doesn't quite exercise the claimed failure mode: Again — appreciate the contribution. Happy to dig in further if you can share a repro. |
|
I share @JadenFiotto-Kaufman's concern. We explicitly propagate the caller's CUDA stream into the mediator's worker thread, so ordering between the .to(cuda, non_blocking=True) and any consumer on that stream is already guaranteed — I don't think this race applies to the current codebase. I ran this PR's test_cache_gpu_synchronization without the sync and it still passes, which is expected: the gpt2 fixture is already on CUDA, so .to(cuda, non_blocking=True) on the layer output is a same-device identity op (same data_ptr). There's no transfer for non_blocking to affect, so the test isn't actually exercising the path it claims to. I also tried scenarios that do involve a real transfer (H2D and D2H) and all of them pass without the sync patch as well. The performance concern is also real — this PR adds ~40% end-to-end latency on a minimal gpt2 forward pass. @Pritiks23 we'd appreciate the contribution if you can share a reproducible failure case on main. |
|
Thank you both for the detailed review the stream ordering explanation and the performance concerns make sense @JadenFiotto-Kaufman @khaiwang To investigate further, I added a focused repro harness to this branch to check whether there’s an actual stream-ordering divergence on main without the synchronization change, and if so, where it occurs. Repro script: repro_cache_stream_ordering.py What it checks: Logs the CUDA stream pointer at each Cache.add call. Given the points raised about stream propagation and the cost of full-device synchronization, I agree we should avoid the current fix unless there’s a reproducible correctness issue on main. If you get a chance to run the repro on a CUDA machine, I’d appreciate any feedback on whether it exposes a real divergence case. |
Fixes issue where cache.add() with device=cuda could return tensors that are still mid-transfer, causing stale data to be read by subsequent forward passes.