Skip to content

fix(concurrency): isolate capture channels and barrier-free NVFP4 decode#47

Closed
voipmonitor wants to merge 7 commits into
local-inference-lab:masterfrom
voipmonitor:fix/pcie-moe-concurrency-20260719
Closed

fix(concurrency): isolate capture channels and barrier-free NVFP4 decode#47
voipmonitor wants to merge 7 commits into
local-inference-lab:masterfrom
voipmonitor:fix/pcie-moe-concurrency-20260719

Conversation

@voipmonitor

@voipmonitor voipmonitor commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • key recycled CUDA graph stream channels by capture ownership instead of a reused stream handle
  • apply the same ownership rule to PCIe oneshot all-reduce and DCP A2A pools
  • checkpoint disposable graph channels and roll them back after profiling captures
  • coordinate rollback across ranks: synchronize, unmap every imported IPC handle, then free exported allocations only after a process-group barrier
  • run native NVFP4 A4 micro decode as separate FC1/FC2 launches for M<=8, removing its resident-grid software barrier
  • expose a plan capability telling vLLM when B12X MoE can safely overlap unrelated auxiliary-stream CUDA work
  • retain B12X_NVFP4_SPLIT_DECODE=0 as a diagnostic fallback

Root causes

Two independent concurrency hazards surfaced under target/draft CUDA graphs and GLM shared-expert overlap. Recycled capture streams could inherit a channel selected for a prior capture owner. Separately, the fused B12X micro MoE launch uses a resident-grid software barrier; co-scheduling unrelated work can prevent every barrier participant from becoming resident.

Disposable profiling graphs add a lifetime constraint: all ranks must destroy graph users and unmap imported CUDA IPC allocations before any rank frees the corresponding exported slab. Rank-local close/free could otherwise leave a peer with a stale mapping. The rollback path now uses a three-barrier teardown protocol and restores only the pre-profile channel map.

The existing W4A8-on-NVFP4 two-phase launch already removed the micro barrier. This PR applies the same split to native NVFP4 A4 and exports the selected launch-plan capability. Dynamic and W4A16 resident launches remain correctly marked unsafe for external overlap.

Validation

  • 40 targeted B12X PCIe channel/lifecycle tests passed
  • teardown tests assert the cross-rank barrier -> close imports -> barrier -> free exports -> barrier order for both pools
  • native A4 fused versus split on the GLM TP8 expert shape: bit-identical, max/mean absolute difference 0
  • native A4 CUDA graph replay with changed input and routing: bit-identical on two replays
  • exact TP8/DCP2/MTP3 GLM reproducer passed short and 300k-token requests with the vLLM integration and native allocator
  • Ruff and git diff --check passed

Integration

Pair with local-inference-lab/vllm#131 for disposable profiling-graph cleanup and local-inference-lab/vllm#132 for stream/workspace isolation and MoE scheduling.

Summary by CodeRabbit

  • New Features
    • Exposed a new integration API to indicate when micro MoE plans can overlap auxiliary CUDA work.
    • Added opt-in native NVFP4 “split decode” support (eligibility rules + environment flag).
    • Added channel pool checkpoint/rollback for both PCIe DCP A2A and PCIe oneshot flows.
  • Bug Fixes
    • Improved idempotent, ordered IPC import/export teardown and safer channel close behavior.
    • Tightened CUDA-graph capture handling and channel isolation during reused capture keys.
  • Tests
    • Added/expanded distributed and CUDA-graph replay coverage, including rollback safety during capture and teardown resilience.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@voipmonitor, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 31 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e210bdd2-32e3-42fb-8181-c429a068e9a5

📥 Commits

Reviewing files that changed from the base of the PR and between dee3b5e and 427b3ab.

📒 Files selected for processing (2)
  • b12x/integration/tp_moe.py
  • tests/test_moe_execution_model.py

Walkthrough

The changes add phased PCIe IPC cleanup, channel checkpoint/rollback, capture-channel reuse handling, and unique pool shutdown. They also add bounded NVFP4 auxiliary-stream overlap planning, opt-in split-decode gating, public exports, and CUDA execution coverage.

Changes

PCIe capture channel lifecycle

Layer / File(s) Summary
DCP A2A capture channel lifecycle
b12x/distributed/pcie_dcp_a2a.py, tests/distributed/test_pcie_dcp_a2a.py
PCIeDCPA2APool retains created channels, isolates reused capture keys, supports rollback, reuses capture-stack channels, and closes unique instances with phased IPC cleanup.
One-shot capture channel lifecycle
b12x/distributed/pcie_oneshot.py, tests/distributed/test_pcie_oneshot.py
PCIeOneshotAllReducePool allocates fresh capture channels, restores checkpointed mappings, coordinates transient IPC teardown, and closes all unique channels.

NVFP4 overlap planning

Layer / File(s) Summary
NVFP4 overlap predicate and launch integration
b12x/integration/tp_moe.py, b12x/integration/__init__.py
Adds bounded NVFP4 eligibility predicates, environment-gated barrier-free split selection, and the exported tp_moe_plan_supports_aux_stream_overlap helper.
NVFP4 execution validation
tests/test_moe_execution_model.py, tests/test_w4a8_tp_moe.py
Tests overlap eligibility, opt-in split behavior, split/fused numerical equality, and CUDA graph replay with auxiliary stream work; existing assertions are reformatted without semantic changes.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CaptureContext
  participant PCIeOneshotAllReducePool
  participant PCIeOneshotAllReduce
  CaptureContext->>PCIeOneshotAllReducePool: checkpoint channel state
  CaptureContext->>PCIeOneshotAllReducePool: capture(stream_key)
  PCIeOneshotAllReducePool->>PCIeOneshotAllReduce: allocate and register channel
  CaptureContext->>PCIeOneshotAllReducePool: rollback channel state
  PCIeOneshotAllReducePool->>PCIeOneshotAllReduce: close transient IPC resources
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.19% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately captures the two main themes: capture-channel isolation and NVFP4 barrier-free decode.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
b12x/distributed/pcie_oneshot.py (1)

871-897: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Missing exception suppression in _close_ipc_imports/_free_ipc_exports — can deadlock the coordinated rollback and enable double-free on retry.

The sibling implementation in b12x/distributed/pcie_dcp_a2a.py (_close_ipc_imports/_free_ipc_exports, lines 466-494) wraps every dispose/cudaIpcCloseMemHandle/cudaFree call in with suppress(Exception). This file's equivalents do not:

  • If cudaIpcCloseMemHandle/cudaFree raises partway through the loop, self._ipc_exports_freed/self._ipc_imports_closed never get set and _owned_buffers is never cleared, so a later retry would attempt to free already-freed pointers (double free/UB).
  • Worse, _coordinated_close_channels() (Lines 150-173) calls channel._close_ipc_imports()/channel._free_ipc_exports() in a loop with no per-channel try/except. An exception on one channel aborts the loop before this rank reaches the next dist.barrier(), while peer ranks that succeeded will block on that barrier forever — a distributed hang.
🐛 Suggested fix (mirrors pcie_dcp_a2a.py)
     def _close_ipc_imports(self) -> None:
         if self._ipc_imports_closed:
             return
         self._closed = True
         if getattr(self, "_ptr", 0):
-            self._ext.dispose(self._ptr)
+            with suppress(Exception):
+                self._ext.dispose(self._ptr)
             self._ptr = 0
-        for shared in self._owned_buffers:
-            for ptr in shared.remote_ptrs:
-                if self._ipc is not None:
-                    self._ipc.cudaIpcCloseMemHandle(ptr)
+        if self._ipc is not None:
+            for shared in self._owned_buffers:
+                for ptr in shared.remote_ptrs:
+                    with suppress(Exception):
+                        self._ipc.cudaIpcCloseMemHandle(ptr)
         self._ipc_imports_closed = True

     def _free_ipc_exports(self) -> None:
         if self._ipc_exports_freed:
             return
         self._close_ipc_imports()
-        for shared in self._owned_buffers:
-            if self._ipc is not None:
-                self._ipc.cudaFree(shared.local_ptr)
+        if self._ipc is not None:
+            for shared in self._owned_buffers:
+                with suppress(Exception):
+                    self._ipc.cudaFree(shared.local_ptr)
         self._owned_buffers.clear()
         self._registered_input_ptrs.clear()
         self._ipc_exports_freed = True
🧹 Nitpick comments (2)
b12x/distributed/pcie_dcp_a2a.py (1)

774-785: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

close() skips the coordinated IPC teardown used elsewhere in this PR.

rollback_channels() correctly routes through _coordinated_close_channels() (barriers + phased close-imports/free-exports) to avoid a rank freeing its exported buffer before peers unmap it. PCIeDCPA2APool.close() still closes every channel directly via channel.close() with no barriers, so full-pool shutdown across ranks can hit the exact same cross-rank use-after-free race this PR fixes for capture rollback.

♻️ Suggested fix
     def close(self) -> None:
         if self._closed:
             return
         self._closed = True
-        seen: set[int] = set()
-        for channel in (*self._all_channels, *self._channels.values()):
-            if id(channel) not in seen:
-                seen.add(id(channel))
-                channel.close()
-        self._all_channels.clear()
+        channels = tuple(dict.fromkeys((*self._all_channels, *self._channels.values())))
+        _coordinated_close_channels(
+            channels, exchange_group=self.exchange_group, device=self.device
+        )
+        self._all_channels.clear()
         self._channels.clear()

See consolidated comment for the matching issue in pcie_oneshot.py.

b12x/distributed/pcie_oneshot.py (1)

1241-1252: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

close() skips the coordinated IPC teardown used by rollback_channels.

Same root cause as the equivalent gap in pcie_dcp_a2a.py: PCIeOneshotAllReducePool.close() closes each channel directly (channel.close()) with no barriers, whereas rollback_channels() uses _coordinated_close_channels() specifically to avoid one rank freeing its exported buffer before peers unmap it. Full-pool shutdown reintroduces that same cross-rank race.

See consolidated comment for the shared fix across both files.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 58027cac-5e97-4dea-85ce-20ad280ec245

📥 Commits

Reviewing files that changed from the base of the PR and between a274dd7 and dc7faa3.

📒 Files selected for processing (8)
  • b12x/distributed/pcie_dcp_a2a.py
  • b12x/distributed/pcie_oneshot.py
  • b12x/integration/__init__.py
  • b12x/integration/tp_moe.py
  • tests/distributed/test_pcie_dcp_a2a.py
  • tests/distributed/test_pcie_oneshot.py
  • tests/test_moe_execution_model.py
  • tests/test_w4a8_tp_moe.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • b12x/integration/init.py
  • tests/test_w4a8_tp_moe.py
  • b12x/integration/tp_moe.py
  • tests/distributed/test_pcie_dcp_a2a.py
  • tests/test_moe_execution_model.py

@voipmonitor

Copy link
Copy Markdown
Contributor Author

Addressed the coordinated-teardown review finding in dee3b5e: every dispose/close/free is exception-isolated, terminal state is always recorded, cleanup remains idempotent, and a regression test verifies all resources are attempted even when every CUDA IPC operation raises. Validation: 32/32 pcie_oneshot tests passed.

@voipmonitor

Copy link
Copy Markdown
Contributor Author

Superseded by #58, rebuilt directly on current master with the namespaced sparkinfer APIs, coordinated graph-channel teardown, regression tests, and the corrected W4A16 pre-resident overlap contract.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant