Repository navigation
Fix exit segfault from KV caches shared over CUDA IPC - #975
Conversation
…worker reads it A KV cache on a LocalTransferEngine was shared with storage._share_cuda_() whatever the deployment. torch counts a shared block as held by a reader until a reader releases it, so a cache no other process ever opened went to torch's CUDA IPC limbo when its engine was dropped: its pool stayed allocated until the process exited, and at exit the limbo's destructor (CudaIPCGlobalEntities -> ~CudaIPCSentData -> CUDAGuard -> c10_cuda_check_implementation) ran after c10's CUDAKernelLaunchRegistry singleton was destroyed, reading freed memory. Under glibc's MALLOC_PERTURB_ that is a segfault at exit (the draft-verify plan-ahead GPU tests, every toy engine test); the "Producer process has been terminated before all shared CUDA tensors released" warning at exit is the same limbo. A cache whose resource spans one worker instance (needs_remote_transfer False) now gets the LocalOnlyKVTransferEngine that CPU caches already got; a shared one still goes over CUDA IPC.
No behaviour change. The freed-with-its-manager test asserts the memory comes back rather than which engine class was picked for it.
Live test: Fix exit segfault from KV caches shared over CUDA IPCWorks. A cache no other worker reads no longer goes through CUDA IPC, so the "shared CUDA tensors" warning at exit goes away on every single-worker config. Caches another worker reads (P/D) still use IPC and still transfer correctly. One limit: the exit crash itself remains for caches that really are shared (below). H200, SHM, Served configs, 2 restarts per arm, SIGINT stop
Tests
Not tested
Commands
|
There was a problem hiding this comment.
LGTM, note that this doesn't fix the issue for KV caches that actually have to be shared: (according to claude), torch expects each IPC-shared tensor to be shared once, and the current code in the case of PD disaggregation / CFG parallel end up sharing it multiple times, so the tensor will still remain in limbo.
Brings in main through #975 (#955's one pick for a capped step) and 4a's continuing rows, step-carried loop strides and default mixing. The TP-follow path replays the leader's chunks and never goes through the chain pick, so it needs no change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every KV cache is shared over CUDA IPC, even when no other worker reads it. Once its manager is dropped, the cache sits in torch's IPC limbo: it stays allocated until exit, and at exit torch's cleanup reads freed memory and segfaults.
This uses the local-only transfer engine when the cache spans one worker (
needs_remote_transferFalse). Caches another instance reads (P/D) still go over IPC.MALLOC_PERTURB_=165)Tests:
test_kv_ipc_transfer.py::test_a_cache_no_other_worker_reads_is_freed_with_its_managerfails on main and passes here. GPU KV modules (1×H100) and CPU Core fail the same tests as main, by name. ruff clean.The mid-run heap corruption seen in the same runs is a separate bug, fixed in #976.
AI assistance (Claude) was used for this PR.