mirror of
https://github.com/deepseek-ai/DeepEP.git
synced 2026-11-05 00:47:32 +00:00
[GH-ISSUE #799] [HybridEP] Fabric (MNNVL) allocator leaks device memory on every buffer reallocation #484
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
deepseek-ai/DeepEP#484
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @jerryhong21 on GitHub (Oct 26, 2026).
Original GitHub issue: https://github.com/deepseek-ai/DeepEP/issues/799
Summary
On systems where HybridEP uses the fabric (MNNVL) allocator (for example GB200/GB300 NVL72), physical device memory is never returned when a HybridEP buffer is freed. Each time
HybridEPBuffer::update_buffergrows the buffer, the entire previous buffer set leaks. With variable-length batches, the leaks keep adding up untilcuMemCreatefails.Symptom
We hit this in MoE training with variable-length, long-context batches on GB300 NVL72, using HybridEP through Megatron-LM's flex dispatcher:
Root cause
In
csrc/hybrid_ep/allocator/allocator.cu, the fabric path never releases three handle references:allocatenever releases the handle fromcuMemCreate(:91).get_handlenever releases the reference taken bycuMemRetainAllocationHandlebefore export (:124).open_handlenever releases the handle fromcuMemImportFromShareableHandle(:139).freeretains and releases once, so its net effect on the count is zero.close_handleonly unmaps. The CUDA driver frees physical memory only after every mapping is unmapped and every handle reference is released, so this memory stays allocated. Peers' imports also keep each exporter's memory pinned.update_buffercallsrelease_buffer()and thenallocate_buffer()whenever a call needs more capacity than the current reservation (hybrid_ep.cu,grow_buffer_config). With variable-length inputs, every new tokens-per-rank high (in alignment steps) therefore leaks a whole buffer set. Workloads where every step has the same shape allocate once and are not affected.The
cudaMalloc/IPC path, used when fabric is unavailable, is not affected. The legacySharedMemoryAllocatorincsrc/deep_ep.cpphas the same three sites.Workarounds
max_num_of_tokens_per_rank, so it never reallocates.USE_MNNVL=0when the EP group fits within one NVLink node, so thecudaMalloc/IPC path is used.Fix
PR #798 adds the missing
cuMemReleasecalls after map, export and import.