Repository navigation
libfabric: serialize all endpoint/CQ/AV calls with the rail EP lock - #2308
Conversation
Hold the rail's ep_mutex_ around every libfabric call on its endpoint, CQ and AV, including the progress-thread (PT) paths drainPostQueue() and pollForCompletions(), which bypassed it. Also lock AV insert/remove and endpoint-bound MR bind/enable/close. Rails use FI_THREAD_COMPLETION, so the application must serialize endpoint and CQ access. With the PT enabled, the PT posts transfers and reads the CQ while the caller's thread posts control messages on rail 0 (postSend(), which took the lock). On libfabric 2.7.x (EFA RDM path) this race corrupts provider state and hangs nixlbench --enable-pt VRAM-initiator WRITE. Lock only the fi_* call itself, never an FI_EAGAIN retry loop, and run completion handling and callbacks outside the lock. Signed-off-by: Rongbing Zhou <rongbiz@amazon.com>
|
👋 Hi rongbingzhou! Thank you for contributing to ai-dynamo/nixl. Your PR reviewers will review your contribution then trigger the CI to test your changes. 🚀 |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: ai-dynamo/nixl/.coderabbit.yaml Review profile: ASSERTIVE Plan: Enterprise Run ID: 📒 Files selected for processing (2)
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 11 remain after this review. 📝 WalkthroughWalkthroughThe Libfabric rail now uses the endpoint mutex around CQ reads, batched RMA posts, address-vector updates, and endpoint-bound memory-registration operations. Completion handling and callbacks remain outside the lock. ChangesLibfabric call serialization
Priority: ➖ Normal Estimated code review effort: 2 (Simple) | ~15 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to The serialization changes appear mergeable after normal checks. Runtime reproduction of the reported provider hang remains unverified. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
/ok to test dbbedae |
|
/build |
|
🤖 CI Triage Agent — TL;DR: The Full analysisSummary: Root cause: That RUN step resolves the vLLM version dynamically when The call is unauthenticated, so it is subject to GitHub's 60-requests/hour/IP anonymous limit. The build log shows the traceback ending in Implicated commit: c984ce6 — lishapira, "CI: add vLLM + NIXL EP test to the EP CI job (#2154)" — introduced the unauthenticated File: Suggested fix: Stop resolving the vLLM release from the GitHub API at image-build time. Concretely, in order of preference:
Re-running #1399 will likely pass once the hourly quota resets, but the class of failure will recur until Related: PR #2292 "CI: pin the vLLM release for the elastic EP test" (direct fix, still open); PR #2300 "nixl_ep: Test vLLM Elastic EP without patching vLLH" (touches the same block); PR #2291 "CI: retry git fetches and trim gRPC submodules in dependency builds" (same retry-hardening theme); PR #2154 (origin of the lookup). |
akkart-aws
left a comment
There was a problem hiding this comment.
LGTM — correct fix for the hang, and the rules in the header comment (lock only the fi_* call, never a retry loop, keep it innermost) are the right ones.
One question: do you have a before/after throughput number on nixlbench --enable-pt? The PT's fi_cq_read and the app thread's postSend / drainPostQueue now all serialize on one mutex per rail at completion rate, and the fix is motivated by a hang rather than a measurement. Fine either way, just want to know what it cost.
Longer term I think the real answer is proper FI_THREAD_COMPLETION usage : dedicated CQ and tx/rx contexts per thread, but that's a rail-architecture change and well out of scope here.
…ation-cache Conflicts resolved by keeping upstream's changes and the MR registration changes together: - libfabric_rail.h: keep the MR cache accessors and upstream's kUnknownAgentIdx sentinel; drop the old insertAddress(addr, fi_addr_out) declaration that upstream replaced (ai-dynamo#2294). - libfabric_rail.cpp: keep upstream's canRegisterWithDmabuf() (ai-dynamo#2287) next to getMRCacheSize(). In deregisterMemory() keep the ref-counted lookup and close the MR through upstream's EP-locked fi_close (ai-dynamo#2308), on both the last-reference and the uncached path. - libfabric_rail.cpp, no textual conflict: the late-race close of a redundant MR in registerMemory() now follows the same FI_MR_ENDPOINT EP-lock rule. Signed-off-by: Anton Alexander <dmvevents@gmail.com>
What?
Hold the rail's
ep_mutex_around every libfabric call on its endpoint, CQ and AV, including the progress-thread (PT) pathsdrainPostQueue()andpollForCompletions(), which bypassed it. Also lock AV insert/remove and endpoint-bound MR bind/enable/close.Why?
Rails use
FI_THREAD_COMPLETION, so the application must serialize endpoint and CQ access. With the PT enabled, the PT posts transfers and reads the CQ while the caller's thread posts control messages on rail 0 (postSend(), which took the lock). On libfabric 2.7.x (EFA RDM path) this race corrupts provider state and hangs nixlbench --enable-pt VRAM-initiator WRITE.How?
Lock only the
fi_*call itself, never anFI_EAGAINretry loop, and run completion handling and callbacks outside the lock.Summary by CodeRabbit
Bug Fixes
Documentation