mirror of
https://github.com/deepseek-ai/DeepEP.git
synced 2026-11-05 00:47:32 +00:00
[PR #677] Fix the CPU-assisted (GDRCopy) IBGDA path in the legacy kernels #697
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#697
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?
📋 Pull Request Information
Original PR: https://github.com/deepseek-ai/DeepEP/pull/677
Author: @tommy85
Created: 7/8/2026
Status: 🔄 Open
Base:
main← Head:fix-cpu-assisted-ibgda📝 Commits (2)
91848edFix the CPU-assisted (GDRCopy) IBGDA path in the legacy kernels5c4f2b8Read ready_head in the quiet drain so it survives the async submit change📊 Changes
1 file changed (+24 additions, -6 deletions)
View changed files
📝
csrc/kernels/legacy/ibgda_device.cuh(+24 -6)📄 Description
docs/nvshmem.md (§ "Install GDRCopy and load the gdrdrv kernel module") documents the CPU-assisted IBGDA mode as the supported alternative "when modifying the driver regkeys is not an option". In practice that mode (
NVSHMEM_IBGDA_NIC_HANDLER=cpu) has never worked with DeepEP: the async post-send branch inibgda_submit_requests(csrc/kernels/legacy/ibgda_device.cuh) has two independent defects, either of which is fatal.Bug 1 — submissions are invisible to the CPU proxy (first dispatch hangs).
The async branch CASes on
qp->tx_wq.prod_idx. NVSHMEM's host code wires that pointer to a device-side management counter (ibgda_setup_gpu_state:rc_h[i].tx_wq.prod_idx = base_mvars_d_addr + prod_idx_offset), but the proxy thread polls a separate producer-slot array (nvshmemt_ibgda_progressreadsqp_shared_object.prod_idx_mobject). The value DeepEP publishes is therefore never observed, no doorbell is ever rung, and the very first dispatch spins forever waiting for data (surfacing as the NCCL watchdog SIGABRT after 600 s).Bug 2 — teardown deadlock on shared QPs.
The async branch also skips the
ready_headCAS queue. NVSHMEM's own submit path orders every submission throughmvars->tx_wq.ready_head, and DeepEP shares the same QP management memory with NVSHMEM. After a DeepEP workload,resv_headis far ahead whileready_headis still 0; the first NVSHMEM-side submission on a shared QP — thenvshmem_barrier_all()insideBuffer::destroy()— reserves a slot and then spins forever onatomicCAS(ready_head==0, expect resv_head). That spin has no timeout, so the process hangs incuStreamSynchronizewith the GPU at 100%.Fix. Always order submissions through
ready_head(matching NVSHMEM's protocol), and in the async mode publish the new producer index with a system-scopeatomicMaxonqp->tx_wq.bf— in the CPU-assisted modes NVSHMEM wiresbfto the proxy-polled producer slot (seeibgda_get_device_qp), so this mirrors NVSHMEM's ownibgda_proxy_post_sendexactly and needs no NVSHMEM-side change. System scope keeps the publish visible to the CPU observer also forNVSHMEM_IBGDA_NIC_HANDLER=cpu_host_memory, where the slot lives in host memory.Validation. On our rig (NVSHMEM 3.4.5, 2 nodes, 4 RC QPs per rank,
NVSHMEM_IBGDA_NIC_HANDLER=cpuwith GDRCopy)tests/test_low_latency.pypreviously hung at the first dispatch; with only the pointer rewired it then deadlocked inBuffer::destroy(). With this patch the full run — benchmark plus teardown (barrier → free → finalize) — completes and exits 0, with benchmark numbers unchanged. The defect is pure protocol logic, independent of the NIC; on ConnectX it should reproduce by simply exportingNVSHMEM_IBGDA_NIC_HANDLER=cpu(NVSHMEM built with GDRCopy) and runningtests/test_low_latency.py.The GPU-direct doorbell path (
NVSHMEM_IBGDA_NIC_HANDLER=gpu, the default) is unaffected: its submit branch already ordered throughready_headand does not take the async path.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.