Skip to content

Commit 64ea9ad

Browse files
committed
Guard NCCL EP lazy init during graph capture
Fail fast if the lazy NCCL EP context or dispatch handle would be initialized while CUDA graph capture is active, and cover those guard paths in the communication factory tests. Signed-off-by: Ludwig Schneider <lschneider@nvidia.com>
1 parent b1884b4 commit 64ea9ad

2 files changed

Lines changed: 43 additions & 0 deletions

File tree

tensorrt_llm/_torch/modules/fused_moe/communication/nccl_ep.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ def supports_post_quant_dispatch(self) -> bool:
112112

113113
def _get_context(self):
114114
if self._ctx is None:
115+
if torch.cuda.is_current_stream_capturing():
116+
raise RuntimeError(
117+
"NcclEP context must be initialized before CUDA graph capture. "
118+
"Run an eager warmup forward before enabling or capturing CUDA graphs."
119+
)
115120
from nccl.ep import Layout
116121

117122
from tensorrt_llm._torch.modules.fused_moe.nccl_ep_utils import get_nccl_ep_context
@@ -130,6 +135,11 @@ def _get_context(self):
130135
def _setup_handle(self, ctx, topk_nd, stream):
131136
"""Ensure self._handle exists; rebind topk via handle.update on subsequent calls."""
132137
if self._handle is None:
138+
if torch.cuda.is_current_stream_capturing():
139+
raise RuntimeError(
140+
"NcclEP dispatch handle must be initialized before CUDA graph capture. "
141+
"Run an eager warmup forward before enabling or capturing CUDA graphs."
142+
)
133143
self._handle = ctx.ep_group.create_handle(
134144
ctx.layout,
135145
topk_nd,

tests/unittest/_torch/modules/moe/test_communication_factory.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from tensorrt_llm._torch.modules.fused_moe.communication.allgather_reducescatter import (
2525
AllGatherReduceScatter,
2626
)
27+
from tensorrt_llm._torch.modules.fused_moe.communication.nccl_ep import NcclEP
2728

2829

2930
def _make_model_config(
@@ -180,3 +181,35 @@ def fail_if_called(*args, **kwargs):
180181
)
181182

182183
assert isinstance(strategy, AllGatherReduceScatter)
184+
185+
186+
def test_nccl_ep_context_init_rejects_cuda_graph_capture(
187+
monkeypatch: pytest.MonkeyPatch,
188+
):
189+
strategy = object.__new__(NcclEP)
190+
strategy._ctx = None
191+
monkeypatch.setattr(torch.cuda, "is_current_stream_capturing", lambda: True)
192+
193+
with pytest.raises(RuntimeError, match="context must be initialized before CUDA graph capture"):
194+
strategy._get_context()
195+
196+
197+
def test_nccl_ep_handle_init_rejects_cuda_graph_capture(
198+
monkeypatch: pytest.MonkeyPatch,
199+
):
200+
strategy = object.__new__(NcclEP)
201+
strategy._handle = None
202+
monkeypatch.setattr(torch.cuda, "is_current_stream_capturing", lambda: True)
203+
204+
def fail_create_handle(*args, **kwargs):
205+
raise AssertionError("create_handle should not run during CUDA graph capture")
206+
207+
ctx = SimpleNamespace(
208+
ep_group=SimpleNamespace(create_handle=fail_create_handle),
209+
layout=object(),
210+
)
211+
212+
with pytest.raises(
213+
RuntimeError, match="dispatch handle must be initialized before CUDA graph capture"
214+
):
215+
strategy._setup_handle(ctx, object(), 0)

0 commit comments

Comments
 (0)