Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a2a4b00
Add DeepEP v2 (ElasticBuffer) all2all backend for MoE EP
tlrmchlsmth Apr 30, 2026
515e36d
Fix FP8 dispatch test to match production behavior
tlrmchlsmth Apr 30, 2026
019a41f
Add DeepEP v2 lifecycle test to test_mnnvl_alltoall
tlrmchlsmth Apr 30, 2026
67d26f7
Fix NCCL version check: 2.30.4, not 4.30.4
tlrmchlsmth Apr 30, 2026
75149ae
Check runtime NCCL version instead of PyTorch compile-time constant
tlrmchlsmth Apr 30, 2026
5a766bf
Refactor DeepEP v2 for cudagraph compatibility and simplified DBO
tlrmchlsmth May 1, 2026
56a8767
Update DeepEP v2 docstring with cudagraph design rationale
tlrmchlsmth May 1, 2026
ed29278
Split DeepEP v2 into prefill/decode modes for memory vs cudagraph
tlrmchlsmth May 1, 2026
0f94cbe
Fix FP8 padding: use torch.where instead of masked_fill_
tlrmchlsmth May 1, 2026
45a0b6d
Fix local→global expert ID conversion in DeepEP v2 decode path
tlrmchlsmth May 2, 2026
ae8c445
Use -1 expert ID for padding and non-local tokens in DeepEP v2
tlrmchlsmth May 2, 2026
1e11436
Add TrtLLM FP8 support for DeepEP v2 + modular kernel test framework
tlrmchlsmth May 3, 2026
9a65580
Add is_moe to test VllmConfig model_config
tlrmchlsmth May 3, 2026
6a2d75c
Wrap MK test worker in set_current_vllm_config context
tlrmchlsmth May 3, 2026
6e94d6f
Use enforce_eager=True for MK tests (do_expand=True for DeepEP v2)
tlrmchlsmth May 3, 2026
7053a17
Add barrier before mk.apply in MK test to sync ranks
tlrmchlsmth May 4, 2026
6d7a3fa
Pass NCCL device group to DeepEP v2 ElasticBuffer
tlrmchlsmth May 4, 2026
790164e
Merge upstream main into deepep-v2-integration
tlrmchlsmth May 14, 2026
f723e07
Expand CUDA_VISIBLE_DEVICES for MegaMoE symmetric memory
tlrmchlsmth May 14, 2026
f368ee5
Fix dtype mismatch in topk_softplus_sqrt for DeepEP backends
tlrmchlsmth May 11, 2026
e98051e
Fix is_nvfp4_scale_swizzled -> is_scale_swizzled rename
tlrmchlsmth May 15, 2026
152289e
Merge remote-tracking branch 'origin/main' into deepep-v2-integration
tlrmchlsmth Jun 3, 2026
29d1e50
ditch mega moe external dp hack
tlrmchlsmth Jun 3, 2026
a6df5ae
fix eplb
tlrmchlsmth Jun 4, 2026
52cd7cb
review comments
tlrmchlsmth Jun 4, 2026
5fe9756
register test
tlrmchlsmth Jun 4, 2026
5512502
eplb fix
tlrmchlsmth Jun 4, 2026
e86660c
Fix EPLB
tlrmchlsmth Jun 4, 2026
3e40020
update
tlrmchlsmth Jun 4, 2026
5aca03a
Updates
tlrmchlsmth Jun 4, 2026
9ec7e47
Merge remote-tracking branch 'origin/main' into deepep-v2-integration
tlrmchlsmth Jun 8, 2026
8ac84e2
Move index dtype cast into fused_topk_bias for all callers
tlrmchlsmth Jun 8, 2026
c2ed9f8
Fix pre-commit: mypy errors and formatting
tlrmchlsmth Jun 8, 2026
d4a84fb
Merge remote-tracking branch 'origin/main' into deepep-v2-integration
tlrmchlsmth Jun 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions tests/distributed/test_mnnvl_alltoall.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
has_flashinfer_nvlink_one_sided,
has_flashinfer_nvlink_two_sided,
)
from vllm.utils.import_utils import has_deep_ep_v2
from vllm.utils.network_utils import get_open_port

from ..utils import init_test_distributed_environment
Expand Down Expand Up @@ -194,6 +195,10 @@ class _AttnMeta:
not _has_sys_ptrace(),
reason="SYS_PTRACE required (docker run --cap-add=SYS_PTRACE)",
)
requires_deep_ep_v2 = pytest.mark.skipif(
not has_deep_ep_v2(),
reason="DeepEP v2 (ElasticBuffer) not available or NCCL < 2.30.4",
)

# NOTE: No module-level pytestmark here. The FlashInfer lifecycle tests have
# their own @requires_two_sided / @requires_one_sided decorators, and
Expand Down Expand Up @@ -772,3 +777,76 @@ def _one_sided_data_worker(rank, world_size):
def test_one_sided_dispatch_combine(world_size):
"""Test FlashInfer one-sided dispatch/combine with actual data flow."""
_spawn_workers(_one_sided_data_worker, world_size, dp_size=world_size)


# ---------------------------------------------------------------------------
# Test 6: DeepEP v2 (ElasticBuffer) manager lifecycle
# ---------------------------------------------------------------------------
#
# Tests DeepEPV2All2AllManager which wraps DeepEP's ElasticBuffer API using
# the NCCL GIN backend. Requires DeepEP >= 2.0 and NCCL >= 2.30.4.
#
# Uses EP group because the DeepEP v2 manager is constructed with an
# EP-scoped communicator in production. With tp=world_size the EP group
# spans all ranks.
# ---------------------------------------------------------------------------


def _deepep_v2_lifecycle_worker(rank, world_size):
from vllm.distributed.device_communicators.all2all import (
DeepEPV2All2AllManager,
)

cpu_group = get_ep_group().cpu_group
manager = DeepEPV2All2AllManager(cpu_group)

assert manager.rank == rank
assert manager.world_size == world_size
assert manager._num_sms is None

hidden_size = 7168
num_experts = world_size * 32
num_topk = 8
max_tokens = 256

handle_kwargs = dict(
num_max_tokens_per_rank=max_tokens,
hidden=hidden_size,
num_topk=num_topk,
num_experts=num_experts,
use_fp8_dispatch=False,
)

handle = manager.get_handle(handle_kwargs)
assert handle is not None
assert manager._num_sms is not None
assert manager._num_sms > 0

torch.distributed.barrier()

# get_handle again with same args should return cached handle
handle2 = manager.get_handle(dict(handle_kwargs))
assert handle2 is handle

torch.distributed.barrier()

# Destroy clears the cache
manager.destroy()
assert len(manager.handle_cache._cache) == 0

torch.distributed.barrier()

# Re-create after destroy
handle3 = manager.get_handle(dict(handle_kwargs))
assert handle3 is not None

torch.distributed.barrier()
manager.destroy()


@requires_multi_gpu
@requires_deep_ep_v2
@pytest.mark.parametrize("world_size", [2])
def test_deepep_v2_manager_lifecycle(world_size):
"""Test DeepEP v2 ElasticBuffer manager init, caching, and destroy."""
_spawn_workers(_deepep_v2_lifecycle_worker, world_size)
47 changes: 44 additions & 3 deletions tests/kernels/moe/parallel_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from torch.multiprocessing import spawn # pyright: ignore[reportPrivateImportUsage]
from typing_extensions import ParamSpec

from vllm.utils.import_utils import has_deep_ep
from vllm.utils.import_utils import has_deep_ep, has_deep_ep_v2
from vllm.utils.network_utils import get_open_port

if has_deep_ep():
Expand All @@ -26,6 +26,11 @@
DeepEPLLPrepareAndFinalize,
)

if has_deep_ep_v2():
from vllm.model_executor.layers.fused_moe.prepare_finalize.deepep_v2 import (
DeepEPV2PrepareAndFinalize,
)

## Parallel Processes Utils

P = ParamSpec("P")
Expand Down Expand Up @@ -55,11 +60,10 @@ def _worker_parallel_launch(
torch.accelerator.set_device_index(local_rank)
device = torch.device("cuda", local_rank)
torch.distributed.init_process_group(
backend="cpu:gloo,cuda:nccl",
backend="nccl",
init_method=init_method,
rank=rank,
world_size=world_size,
device_id=device,
)
barrier = torch.tensor([rank], device=device)
torch.distributed.all_reduce(barrier)
Expand Down Expand Up @@ -200,3 +204,40 @@ def make_deepep_a2a(

assert deepep_ll_args is not None
return make_deepep_ll_a2a(pg, pgi, deepep_ll_args, q_dtype, block_shape)


@dataclasses.dataclass
class DeepEPV2Args:
num_local_experts: int
num_experts: int
num_topk: int
hidden_size: int
max_tokens_per_rank: int
use_fp8_dispatch: bool


def make_deepep_v2_a2a(
pg: ProcessGroup,
pgi: ProcessGroupInfo,
dp_size: int,
v2_args: DeepEPV2Args,
):
import deep_ep

buffer = deep_ep.ElasticBuffer(
group=pg,
num_max_tokens_per_rank=v2_args.max_tokens_per_rank,
hidden=v2_args.hidden_size,
num_topk=v2_args.num_topk,
use_fp8_dispatch=v2_args.use_fp8_dispatch,
explicitly_destroy=True,
)
return DeepEPV2PrepareAndFinalize(
buffer=buffer,
num_dispatchers=pgi.world_size,
dp_size=dp_size,
rank_expert_offset=pgi.rank * v2_args.num_local_experts,
num_experts=v2_args.num_experts,
num_topk=v2_args.num_topk,
use_fp8_dispatch=v2_args.use_fp8_dispatch,
)
Loading
Loading