A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 5, 04:45 UTC
[MoE Refactor] Remove MoE DP chunking (#39107)
Signed-off-by: Bill Nell <bnell@redhat.com> Co-authored-by: Robert Shaw <114415538+robertgshaw2-redhat@users.noreply.github.com>
bnellnm committed
Apr 14, 2026 at 09:48 UTC
e1e318af010b4f92d39324d03231cfd409766bf9
20 files changed
+76
-389
.buildkite/test_areas/kernels.yaml
+16
-2
@@ -200,7 +200,14 @@ steps:
200
timeout_in_minutes: 90
201
device: h100
202
num_devices: 2
203
- optional: true
203
+ source_file_dependencies:
204
+ - csrc/quantization/cutlass_w8a8/moe/
205
+ - csrc/moe/
206
+ - tests/kernels/moe
207
+ - vllm/model_executor/layers/fused_moe/
208
+ - vllm/model_executor/layers/quantization/
209
+ - vllm/distributed/device_communicators/
210
+ - vllm/config
211
commands:
212
- pytest -v -s kernels/moe/test_moe_layer.py
213
@@ -209,6 +216,13 @@ steps:
216
timeout_in_minutes: 90
217
device: b200
218
num_devices: 2
212
- optional: true
219
+ source_file_dependencies:
220
+ - csrc/quantization/cutlass_w8a8/moe/
221
+ - csrc/moe/
222
+ - tests/kernels/moe
223
+ - vllm/model_executor/layers/fused_moe/
224
+ - vllm/model_executor/layers/quantization/
225
+ - vllm/distributed/device_communicators/
226
+ - vllm/config
227
commands:
228
- pytest -v -s kernels/moe/test_moe_layer.py
tests/kernels/moe/modular_kernel_tools/common.py
+1
-7
@@ -46,6 +46,7 @@ from vllm.utils.import_utils import (
46
has_deep_gemm,
47
has_mori,
48
)
49
+from vllm.utils.math_utils import next_power_of_2
50
51
from .mk_objects import (
52
TestMoEQuantConfig,
@@ -604,13 +605,6 @@ def make_modular_kernel(
605
vllm_config: VllmConfig,
606
quant_config: FusedMoEQuantConfig,
607
) -> mk.FusedMoEKernel:
607
- def next_power_of_2(x):
608
- import math
609
-
610
- if x == 0:
611
- return 1
612
- return 2 ** math.ceil(math.log2(x))
613
-
608
# make moe config
609
moe_parallel_config: FusedMoEParallelConfig = FusedMoEParallelConfig.make(
610
tp_size_=get_tensor_model_parallel_world_size(),
tests/kernels/moe/modular_kernel_tools/parallel_utils.py
+1
-1
@@ -126,7 +126,7 @@ def parallel_launch_with_config(
126
world_size: int,
127
worker: Callable[Concatenate[ProcessGroupInfo, VllmConfig, Any, P], None],
128
vllm_config: VllmConfig,
129
- env_dict: dict[Any, Any],
129
+ env_dict: dict[Any, Any] | None,
130
*args: P.args,
131
**kwargs: P.kwargs,
132
) -> None:
tests/kernels/moe/test_deepep_deepgemm_moe.py
+1
-8
@@ -29,6 +29,7 @@ from vllm.utils.deep_gemm import (
29
is_deep_gemm_supported,
30
)
31
from vllm.utils.import_utils import has_deep_ep, has_deep_gemm
32
+from vllm.utils.math_utils import next_power_of_2
33
from vllm.utils.torch_utils import set_random_seed
34
from vllm.v1.worker.workspace import init_workspace_manager
35
@@ -84,14 +85,6 @@ def with_dp_metadata(M: int, world_size: int):
85
yield
86
87
87
-def next_power_of_2(x):
88
- import math
89
-
90
- if x == 0:
91
- return 1
92
- return 2 ** math.ceil(math.log2(x))
93
-
94
-
88
def make_block_quant_fp8_weights(
89
e: int,
90
n: int,
tests/kernels/moe/test_flashinfer.py
+3
@@ -32,6 +32,7 @@ from vllm.model_executor.layers.quantization.utils.flashinfer_utils import (
32
from vllm.model_executor.layers.quantization.utils.fp8_utils import input_to_float8
33
from vllm.model_executor.models.llama4 import Llama4MoE
34
from vllm.platforms import current_platform
35
+from vllm.utils.math_utils import next_power_of_2
36
from vllm.utils.torch_utils import set_random_seed
37
38
try:
@@ -174,6 +175,7 @@ class TestData:
175
routing_method=layer.routing_method_type,
176
activation=activation,
177
device=w13_quantized.device,
178
+ max_num_tokens=next_power_of_2(m),
179
)
180
181
return TestData(
@@ -348,6 +350,7 @@ def test_flashinfer_cutlass_moe_fp8_no_graph(
350
in_dtype=torch.bfloat16,
351
is_act_and_mul=activation.is_gated,
352
routing_method=RoutingMethodType.TopK,
353
+ max_num_tokens=next_power_of_2(m),
354
)
355
356
kernel = mk.FusedMoEKernel(
tests/kernels/moe/test_flashinfer_moe.py
+2
@@ -29,6 +29,7 @@ from vllm.model_executor.layers.fused_moe.flashinfer_cutlass_moe import (
29
from vllm.model_executor.layers.fused_moe.modular_kernel import FusedMoEKernel
30
from vllm.platforms import current_platform
31
from vllm.utils.flashinfer import has_flashinfer_cutlass_fused_moe
32
+from vllm.utils.math_utils import next_power_of_2
33
from vllm.utils.torch_utils import set_random_seed
34
35
if not has_flashinfer_cutlass_fused_moe() or not current_platform.has_device_capability(
@@ -105,6 +106,7 @@ def test_flashinfer_fp4_moe_no_graph(
106
in_dtype=dtype,
107
is_act_and_mul=is_gated_act,
108
routing_method=RoutingMethodType.TopK,
109
+ max_num_tokens=next_power_of_2(m),
110
)
111
112
flashinfer_experts = FusedMoEKernel(
tests/kernels/moe/test_moe.py
+2
-1
@@ -59,6 +59,7 @@ from vllm.model_executor.layers.quantization.utils.quant_utils import quantize_w
59
from vllm.model_executor.models.mixtral import MixtralMoE
60
from vllm.platforms import current_platform
61
from vllm.scalar_type import ScalarType, scalar_types
62
+from vllm.utils.math_utils import next_power_of_2
63
from vllm.utils.torch_utils import set_random_seed
64
from vllm.v1.worker.workspace import init_workspace_manager
65
@@ -1676,7 +1677,7 @@ def test_unquantized_bf16_flashinfer_trtllm_backend(
1677
in_dtype=dtype,
1678
is_act_and_mul=True,
1679
routing_method=RoutingMethodType.Renormalize,
1679
- max_num_tokens=m,
1680
+ max_num_tokens=next_power_of_2(m),
1681
)
1682
1683
with set_current_vllm_config(vllm_config):
tests/kernels/moe/test_moe_layer.py
+13
-10
@@ -26,6 +26,7 @@ from tests.kernels.moe.utils import TestMLP, make_test_weights, moe_quantize_wei
26
from vllm.config import (
27
CompilationConfig,
28
ParallelConfig,
29
+ SchedulerConfig,
30
VllmConfig,
31
set_current_vllm_config,
32
)
@@ -53,7 +54,7 @@ from vllm.utils.flashinfer import (
54
has_flashinfer_nvlink_two_sided,
55
)
56
from vllm.utils.import_utils import has_deep_ep, has_mori, has_nixl_ep
56
-from vllm.utils.math_utils import cdiv
57
+from vllm.utils.math_utils import cdiv, next_power_of_2
58
from vllm.utils.torch_utils import set_random_seed
59
from vllm.v1.worker.workspace import (
60
init_workspace_manager,
@@ -65,8 +66,9 @@ fp8_dtype = torch.float8_e4m3fn # current_platform.fp8_dtype
66
SHAPE_COMBOS = [
67
(1, 128, 256),
68
(32, 1024, 512),
68
- (222, 2048, 2048), # should be big enough to exercise DP chunking
69
+ (222, 2048, 2048),
70
]
71
+MAX_M = max([x[0] for x in SHAPE_COMBOS])
72
73
NUM_EXPERTS = [8, 64]
74
TOP_KS = [2, 6]
@@ -112,7 +114,7 @@ BACKEND_SUPPORTED_QUANTS: dict[str, set[str | None]] = {
114
"mori": {None, "fp8", "modelopt_fp8"},
115
"flashinfer_nvlink_two_sided": {None, "modelopt_fp8", "modelopt_fp4"},
116
"flashinfer_nvlink_one_sided": {None, "modelopt_fp8", "modelopt_fp4"},
115
- "deepep_low_latency": {None, "fp8", "modelopt_fp8", "modelopt_fp4"},
117
+ "deepep_low_latency": {None, "modelopt_fp8", "modelopt_fp4"},
118
"deepep_high_throughput": {None, "fp8", "modelopt_fp8", "modelopt_fp4"},
119
"nixl_ep": {None, "fp8", "modelopt_fp8"},
120
}
@@ -363,9 +365,9 @@ def is_valid_config(config: MoETestConfig) -> tuple[bool, str | None]:
365
)
366
367
# routed_input_transform + quantization + high hidden dimensions
366
- # TODO: Disable >= 2048 w/fp8 + deepep LL for now due to insane errors.
368
+ # TODO: Disable >= 2048 for now due to insane errors.
369
if (
368
- (config.use_routed_input_transform or config.backend == "deepep_low_latency")
370
+ config.use_routed_input_transform
371
and config.quantization is not None
372
and config.k >= 2048
373
):
@@ -1663,9 +1665,6 @@ def test_moe_layer(
1665
1666
verbosity = pytestconfig.getoption("verbose")
1667
1666
- test_env = dict()
1667
- test_env["VLLM_MOE_DP_CHUNK_SIZE"] = "128"
1668
- monkeypatch.setenv("VLLM_MOE_DP_CHUNK_SIZE", "128")
1668
if os.environ.get("VLLM_LOGGING_LEVEL") is None:
1669
monkeypatch.setenv("VLLM_LOGGING_LEVEL", "ERROR")
1670
@@ -1690,7 +1689,11 @@ def test_moe_layer(
1689
compilation_config.pass_config.fuse_allreduce_rms = False # for now
1690
1691
vllm_config = VllmConfig(
1693
- parallel_config=parallel_config, compilation_config=compilation_config
1692
+ parallel_config=parallel_config,
1693
+ compilation_config=compilation_config,
1694
+ scheduler_config=SchedulerConfig.default_factory(
1695
+ max_num_batched_tokens=next_power_of_2(MAX_M)
1696
+ ),
1697
)
1698
1699
test_configs = generate_valid_test_configs(
@@ -1718,7 +1721,7 @@ def test_moe_layer(
1721
world_size,
1722
_parallel_worker,
1723
vllm_config,
1721
- test_env,
1724
+ None,
1725
test_configs,
1726
verbosity,
1727
)
tests/kernels/moe/utils.py
+1
@@ -69,6 +69,7 @@ def make_dummy_moe_config(
69
in_dtype=in_dtype,
70
device="cuda",
71
routing_method=RoutingMethodType.TopK,
72
+ max_num_tokens=512,
73
)
74
75
vllm/config/parallel.py
+12
@@ -622,6 +622,18 @@ class ParallelConfig:
622
and self.data_parallel_size > 1
623
)
624
625
+ @property
626
+ def use_batched_dp_moe(self) -> bool:
627
+ return (
628
+ self.all2all_backend
629
+ in (
630
+ "deepep_low_latency",
631
+ "nixl_ep",
632
+ )
633
+ and self.enable_expert_parallel
634
+ and self.data_parallel_size > 1
635
+ )
636
+
637
@property
638
def node_rank_within_dp(self) -> int:
639
return self.node_rank % self.nnodes_within_dp
vllm/config/scheduler.py
+1
@@ -40,6 +40,7 @@ class SchedulerConfig:
40
"""
41
42
DEFAULT_MAX_NUM_BATCHED_TOKENS: ClassVar[int] = 2048
43
+ DEFAULT_MAX_NUM_BATCHED_TOKENS_FOR_BATCHED_DP: ClassVar[int] = 256
44
DEFAULT_MAX_NUM_SEQS: ClassVar[int] = 128
45
46
runner_type: RunnerType = "generate"
vllm/engine/arg_utils.py
+16
-7
@@ -1588,9 +1588,6 @@ class EngineArgs:
1588
1589
self._check_feature_supported()
1590
self._set_default_chunked_prefill_and_prefix_caching_args(model_config)
1591
- self._set_default_max_num_seqs_and_batched_tokens_args(
1592
- usage_context, model_config
1593
- )
1591
self._set_default_reasoning_config_args()
1592
sliding_window: int | None = None
1593
if not is_interleaved(model_config.hf_text_config):
@@ -1846,6 +1843,12 @@ class EngineArgs:
1843
target_parallel_config=parallel_config,
1844
)
1845
1846
+ self._set_default_max_num_seqs_and_batched_tokens_args(
1847
+ usage_context,
1848
+ model_config,
1849
+ parallel_config,
1850
+ )
1851
+
1852
assert self.max_num_batched_tokens is not None, (
1853
"max_num_batched_tokens must be set by this point"
1854
)
@@ -2244,6 +2247,7 @@ class EngineArgs:
2247
self,
2248
usage_context: UsageContext | None,
2249
model_config: ModelConfig,
2250
+ parallel_config: ParallelConfig,
2251
):
2252
world_size = self.pipeline_parallel_size * self.tensor_parallel_size
2253
(
@@ -2255,10 +2259,15 @@ class EngineArgs:
2259
orig_max_num_seqs = self.max_num_seqs
2260
2261
if self.max_num_batched_tokens is None:
2258
- self.max_num_batched_tokens = default_max_num_batched_tokens.get(
2259
- usage_context,
2260
- SchedulerConfig.DEFAULT_MAX_NUM_BATCHED_TOKENS,
2261
- )
2262
+ if parallel_config.use_batched_dp_moe:
2263
+ self.max_num_batched_tokens = (
2264
+ SchedulerConfig.DEFAULT_MAX_NUM_BATCHED_TOKENS_FOR_BATCHED_DP
2265
+ )
2266
+ else:
2267
+ self.max_num_batched_tokens = default_max_num_batched_tokens.get(
2268
+ usage_context,
2269
+ SchedulerConfig.DEFAULT_MAX_NUM_BATCHED_TOKENS,
2270
+ )
2271
2272
if self.max_num_seqs is None:
2273
self.max_num_seqs = default_max_num_seqs.get(
vllm/envs.py
-11
@@ -146,8 +146,6 @@ if TYPE_CHECKING:
146
VLLM_ENABLE_PREGRAD_PASSES: bool = False
147
VLLM_DP_MASTER_IP: str = ""
148
VLLM_DP_MASTER_PORT: int = 0
149
- VLLM_MOE_DP_CHUNK_SIZE: int = 256
150
- VLLM_ENABLE_MOE_DP_CHUNK: bool = True
149
VLLM_RANDOMIZE_DP_DUMMY_INPUTS: bool = False
150
VLLM_RAY_DP_PACK_STRATEGY: Literal["strict", "fill", "span"] = "strict"
151
VLLM_RAY_EXTRA_ENV_VAR_PREFIXES_TO_COPY: str = ""
@@ -1140,15 +1138,6 @@ environment_variables: dict[str, Callable[[], Any]] = {
1138
"VLLM_DP_MASTER_IP": lambda: os.getenv("VLLM_DP_MASTER_IP", "127.0.0.1"),
1139
# Port of the master node in the data parallel setting
1140
"VLLM_DP_MASTER_PORT": lambda: int(os.getenv("VLLM_DP_MASTER_PORT", "0")),
1143
- # In the context of executing MoE models with Data-Parallel, Expert-Parallel
1144
- # and Batched All-to-All dispatch/combine kernels, VLLM_MOE_DP_CHUNK_SIZE
1145
- # dictates the quantum of tokens that can be dispatched from a DP
1146
- # rank. All DP ranks process the activations in VLLM_MOE_DP_CHUNK_SIZE
1147
- # units.
1148
- "VLLM_MOE_DP_CHUNK_SIZE": lambda: int(os.getenv("VLLM_MOE_DP_CHUNK_SIZE", "256")),
1149
- "VLLM_ENABLE_MOE_DP_CHUNK": lambda: bool(
1150
- int(os.getenv("VLLM_ENABLE_MOE_DP_CHUNK", "1"))
1151
- ),
1141
# Randomize inputs during dummy runs when using Data Parallel
1142
"VLLM_RANDOMIZE_DP_DUMMY_INPUTS": lambda: (
1143
os.environ.get("VLLM_RANDOMIZE_DP_DUMMY_INPUTS", "0") == "1"
vllm/forward_context.py
+1
-60
@@ -70,27 +70,8 @@ def _compute_sp_num_tokens(
70
return sp_tokens.tolist()
71
72
73
-def _compute_chunked_local_num_tokens(
74
- num_tokens_across_dp_cpu: torch.Tensor,
75
- sequence_parallel_size: int,
76
- max_num_tokens: int,
77
- chunk_idx: int,
78
-) -> list[int]:
79
- sp_tokens = _compute_sp_num_tokens(num_tokens_across_dp_cpu, sequence_parallel_size)
80
- sp_size = len(sp_tokens)
81
-
82
- local_size = [-1] * sp_size
83
- for i in range(sp_size):
84
- # Take into account sharding if MoE activation is sequence parallel.
85
- local_size[i] = min(max_num_tokens, sp_tokens[i] - (max_num_tokens * chunk_idx))
86
- if local_size[i] <= 0:
87
- local_size[i] = 1 # ensure lockstep even if done
88
- return local_size
89
-
90
-
73
@dataclass
74
class DPMetadata:
93
- max_tokens_across_dp_cpu: torch.Tensor
75
num_tokens_across_dp_cpu: torch.Tensor
76
77
# NOTE: local_sizes should only be set by the chunked_sizes context manager
@@ -113,47 +94,7 @@ class DPMetadata:
94
assert num_tokens_across_dp_cpu[dp_rank] == batchsize, (
95
f"{num_tokens_across_dp_cpu[dp_rank]} {batchsize}"
96
)
116
- max_tokens_across_dp_cpu = torch.max(num_tokens_across_dp_cpu)
117
- return DPMetadata(max_tokens_across_dp_cpu, num_tokens_across_dp_cpu)
118
-
119
- @contextmanager
120
- def chunked_sizes(
121
- self, sequence_parallel_size: int, max_chunk_size_per_rank: int, chunk_idx: int
122
- ):
123
- """
124
- Context manager to compute and temporarily set the per-rank local token
125
- sizes for a specific chunk during chunked forward execution.
126
-
127
- This is necessary to ensure each DP (data parallel) rank processes its
128
- designated portion of tokens in lockstep with others, even when the
129
- token counts are uneven or some ranks have completed their input early.
130
-
131
- For chunked execution, we break up the total tokens on each rank into
132
- multiple chunks (of at most `max_chunk_size_per_rank`), and for a given
133
- `chunk_idx`, this context manager sets `self.local_sizes` to the number
134
- of tokens to process in that chunk on each rank.
135
-
136
- `self.local_sizes` is only valid inside the context.
137
-
138
- Args:
139
- sequence_parallel_size: When Attn is TP and MoE layers are EP,
140
- we use SP between the layers to avoid
141
- redundant ops. We need this value to
142
- compute the chunked sizes.
143
- max_chunk_size_per_rank: The max number of tokens each rank is
144
- allowed to process in this chunk.
145
- chunk_idx: The index of the chunk to compute sizes for.
146
- """
147
- self.local_sizes = _compute_chunked_local_num_tokens(
148
- self.num_tokens_across_dp_cpu,
149
- sequence_parallel_size,
150
- max_chunk_size_per_rank,
151
- chunk_idx,
152
- )
153
- try:
154
- yield self.local_sizes
155
- finally:
156
- self.local_sizes = None
97
+ return DPMetadata(num_tokens_across_dp_cpu)
98
99
@contextmanager
100
def sp_local_sizes(self, sequence_parallel_size: int):
vllm/model_executor/layers/fused_moe/config.py
+2
-12
@@ -6,8 +6,7 @@ from typing import Union
6
7
import torch
8
9
-import vllm.envs as envs
10
-from vllm.config import ParallelConfig
9
+from vllm.config import ParallelConfig, SchedulerConfig
10
from vllm.distributed import get_dp_group, get_pcp_group, get_tensor_model_parallel_rank
11
from vllm.logger import init_logger
12
from vllm.model_executor.layers.fused_moe.activation import MoEActivation
@@ -937,15 +936,6 @@ class FusedMoEParallelConfig:
936
all2all_backend: str # all2all backend for MoE communication
937
enable_eplb: bool # whether to enable expert load balancing
938
940
- @property
941
- def use_dp_chunking(self) -> bool:
942
- return (
943
- self.use_deepep_ll_kernels
944
- or self.use_mori_kernels
945
- or self.use_fi_nvl_two_sided_kernels
946
- or self.use_nixl_ep_kernels
947
- ) and envs.VLLM_ENABLE_MOE_DP_CHUNK
948
-
939
@property
940
def is_sequence_parallel(self) -> bool:
941
return self.sp_size > 1
@@ -1184,7 +1174,7 @@ class FusedMoEConfig:
1174
intermediate_size_per_partition_unpadded: int | None = None
1175
1176
moe_backend: str = "auto"
1187
- max_num_tokens: int = envs.VLLM_MOE_DP_CHUNK_SIZE
1177
+ max_num_tokens: int = SchedulerConfig.DEFAULT_MAX_NUM_BATCHED_TOKENS_FOR_BATCHED_DP
1178
has_bias: bool = False
1179
is_act_and_mul: bool = True
1180
is_lora_enabled: bool = False
vllm/model_executor/layers/fused_moe/layer.py
+1
-2
@@ -8,7 +8,6 @@ from typing import Literal, cast, get_args, overload
8
import torch
9
from torch.nn.parameter import UninitializedParameter
10
11
-import vllm.envs as envs
11
from vllm._aiter_ops import rocm_aiter_ops
12
from vllm.config import VllmConfig, get_current_vllm_config
13
from vllm.config.parallel import ExpertPlacementStrategy
@@ -479,7 +478,7 @@ class FusedMoE(CustomOp):
478
in_dtype=moe_in_dtype,
479
moe_backend=vllm_config.kernel_config.moe_backend,
480
router_logits_dtype=router_logits_dtype,
482
- max_num_tokens=envs.VLLM_MOE_DP_CHUNK_SIZE,
481
+ max_num_tokens=vllm_config.scheduler_config.max_num_batched_tokens,
482
has_bias=has_bias,
483
is_act_and_mul=is_act_and_mul,
484
is_lora_enabled=vllm_config.lora_config is not None,
vllm/model_executor/layers/fused_moe/runner/chunking_moe_runner.py
deleted
-243
@@ -1,243 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-
4
-import torch
5
-
6
-from vllm.forward_context import (
7
- get_forward_context,
8
-)
9
-from vllm.model_executor.layers.fused_moe.fused_moe_method_base import (
10
- FusedMoEMethodBase,
11
-)
12
-from vllm.model_executor.layers.fused_moe.runner.moe_runner_base import MoERunnerBase
13
-from vllm.model_executor.layers.fused_moe.runner.shared_experts import (
14
- SharedExperts,
15
-)
16
-from vllm.utils.math_utils import cdiv
17
-from vllm.v1.worker.ubatching import dbo_current_ubatch_id
18
-from vllm.v1.worker.workspace import current_workspace_manager
19
-
20
-
21
-class ChunkingMoERunner(MoERunnerBase):
22
- """
23
- MoE runner wrapper that adds chunked processing to any MoERunnerBase.
24
-
25
- This runner wraps an inner MoERunnerBase and overrides _forward_impl to
26
- process large batches by breaking them into smaller chunks. Each chunk
27
- is delegated to the inner runner's _forward_impl, making chunking
28
- composable with any runner implementation.
29
-
30
- All MoERunnerBase state (moe_config, router, quant_method, etc.) is
31
- transparently delegated to the inner runner via __getattr__.
32
- ChunkingMoERunner only owns chunking-specific state: the pre-allocated
33
- workspace buffers and the reduce_results override.
34
-
35
- Key behaviors:
36
- - Pre-allocates workspace tensors for CUDA graph compatibility
37
- - Processes chunks via inner._forward_impl per chunk
38
- - Never reduces results (reduce_results always returns False)
39
- """
40
-
41
- def __init__(self, inner: MoERunnerBase):
42
- # Assert that _maybe_dispatch/_maybe_combine will be nops.
43
- assert inner.moe_config.pcp_size == 1
44
-
45
- # Skip MoERunnerBase.__init__ — all state is delegated to inner
46
- # via __getattr__. Only chunking-specific state lives here.
47
- self._inner = inner
48
-
49
- # Pre-allocated staging buffers. These need to exist ahead of time
50
- # due to CUDA graph construction needing fixed buffer addresses.
51
- self.batched_hidden_states, self.batched_router_logits = (
52
- self._init_dp_chunking()
53
- )
54
-
55
- def __getattr__(self, name):
56
- # Delegate attribute access to the inner runner. This is only
57
- # called when normal lookup (instance __dict__, class MRO) fails,
58
- # so ChunkingMoERunner's own attributes and methods take priority.
59
- return getattr(self._inner, name)
60
-
61
- @property
62
- def shared_experts(self) -> SharedExperts | None:
63
- return self._inner.shared_experts
64
-
65
- # TODO(bnell): temporary hack, do not call this method.
66
- def _replace_quant_method(self, quant_method: FusedMoEMethodBase):
67
- self._inner._replace_quant_method(quant_method)
68
- self.quant_method = quant_method
69
-
70
- def is_internal_router(self) -> bool:
71
- return self._inner.gate is not None
72
-
73
- # Reducing results when chunking is handled by the MK finalize operations
74
- # when DP chunking is enabled..
75
- # This will be removed by #35949
76
- @property
77
- def reduce_results(self) -> bool:
78
- return False
79
-
80
- def _init_dp_chunking(self) -> list[torch.Tensor]:
81
- states_shape: tuple[int, ...]
82
- logits_shape: tuple[int, ...]
83
-
84
- moe = self.moe_config
85
-
86
- if self.enable_dbo:
87
- states_shape = (2, moe.max_num_tokens, self.moe_config.hidden_dim)
88
- logits_shape = (2, moe.max_num_tokens, self.moe_config.num_logical_experts)
89
- else:
90
- states_shape = (moe.max_num_tokens, self.moe_config.hidden_dim)
91
- logits_shape = (moe.max_num_tokens, self.moe_config.num_logical_experts)
92
-
93
- # Does this need some kind of profiling run check like modular_kernel.py?
94
- return current_workspace_manager().get_simultaneous(
95
- (states_shape, moe.in_dtype),
96
- (logits_shape, moe.router_logits_dtype),
97
- )
98
-
99
- def _allocate_dp_chunking_outputs(
100
- self,
101
- hidden_states: torch.Tensor,
102
- router_logits: torch.Tensor,
103
- shared_experts_input: torch.Tensor | None,
104
- ) -> tuple[torch.Tensor | None, torch.Tensor]:
105
- # Assert the inputs are of the proper type and shape.
106
- assert self.batched_hidden_states is not None
107
- assert self.batched_router_logits is not None
108
-
109
- assert self.batched_hidden_states.dtype == hidden_states.dtype, (
110
- f"{self.batched_hidden_states.dtype} == {hidden_states.dtype}"
111
- )
112
- assert self.batched_router_logits.dtype == router_logits.dtype, (
113
- f"{self.batched_router_logits.dtype} == {router_logits.dtype}"
114
- )
115
-
116
- # Check size compatibility.
117
- assert self.batched_hidden_states.size(-1) == hidden_states.size(-1)
118
- assert self.batched_router_logits.size(-1) == router_logits.size(-1)
119
-
120
- final_fused_hidden_states = torch.empty_like(hidden_states)
121
- if self.shared_experts is not None:
122
- if shared_experts_input is not None:
123
- final_shared_hidden_states = torch.empty_like(shared_experts_input)
124
- else:
125
- final_shared_hidden_states = torch.empty_like(hidden_states)
126
- else:
127
- final_shared_hidden_states = None
128
-
129
- return final_shared_hidden_states, final_fused_hidden_states
130
-
131
- def _slice_and_copy_input(
132
- self,
133
- out_slice: torch.Tensor,
134
- orig: torch.Tensor | None,
135
- start: int,
136
- end: int,
137
- ) -> torch.Tensor:
138
- assert orig is not None
139
- slice_size = end - start
140
- orig_slice = orig[start:end, :]
141
- if self.enable_dbo:
142
- assert out_slice.dim() == 3
143
- batch_buffer_idx = dbo_current_ubatch_id()
144
- out_slice = out_slice[batch_buffer_idx, :]
145
-
146
- assert out_slice.size(0) >= slice_size
147
- out_slice = out_slice[:slice_size, :]
148
- out_slice.copy_(orig_slice, non_blocking=True)
149
- return out_slice
150
-
151
- def _forward_impl(
152
- self,
153
- layer: torch.nn.Module,
154
- hidden_states: torch.Tensor,
155
- router_logits: torch.Tensor,
156
- shared_experts_input: torch.Tensor | None,
157
- ) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
158
- final_shared_hidden_states, final_fused_hidden_states = (
159
- self._allocate_dp_chunking_outputs(
160
- hidden_states, router_logits, shared_experts_input
161
- )
162
- )
163
-
164
- ctx = get_forward_context()
165
- # flashinfer_cutlass_kernels can handle: optional DP + TP/EP
166
- max_tokens_across_dispatchers = ctx.dp_metadata.max_tokens_across_dp_cpu
167
- moe_dp_chunk_size_per_rank = self.moe_config.max_num_tokens
168
-
169
- # If the input to the MoE is sequence parallel then divide by sp_size
170
- # to find the maximum number of tokens for any individual dispatcher.
171
- if self.moe_config.is_sequence_parallel:
172
- max_tokens_across_dispatchers = cdiv(
173
- max_tokens_across_dispatchers, self.moe_config.sp_size
174
- )
175
-
176
- num_tokens = hidden_states.size(0)
177
- for chunk_idx, chunk_start_ in enumerate(
178
- range(0, max_tokens_across_dispatchers, moe_dp_chunk_size_per_rank)
179
- ):
180
- chunk_start = chunk_start_
181
- chunk_end = min(
182
- chunk_start + moe_dp_chunk_size_per_rank, max_tokens_across_dispatchers
183
- )
184
- # clamp start and end
185
- chunk_start = min(chunk_start, num_tokens - 1)
186
- chunk_end = min(chunk_end, num_tokens)
187
- chunk_sizes = ctx.dp_metadata.chunked_sizes(
188
- self.moe_config.sp_size, moe_dp_chunk_size_per_rank, chunk_idx
189
- )
190
- with chunk_sizes:
191
- hidden_states_chunk = self._slice_and_copy_input(
192
- self.batched_hidden_states,
193
- hidden_states,
194
- chunk_start,
195
- chunk_end,
196
- )
197
-
198
- router_logits_chunk = self._slice_and_copy_input(
199
- self.batched_router_logits,
200
- router_logits,
201
- chunk_start,
202
- chunk_end,
203
- )
204
-
205
- shared_experts_input_chunk = (
206
- shared_experts_input[chunk_start:chunk_end, :]
207
- if shared_experts_input is not None
208
- else None
209
- )
210
-
211
- # Delegate per-chunk computation to the inner runner.
212
- chunk_result = self._inner._forward_impl(
213
- layer=layer,
214
- hidden_states=hidden_states_chunk,
215
- router_logits=router_logits_chunk,
216
- shared_experts_input=shared_experts_input_chunk,
217
- )
218
-
219
- # Store outputs
220
- # TODO(bnell): document when chunk_start >= num_tokens
221
- if chunk_start < num_tokens:
222
- if self.shared_experts is not None:
223
- assert isinstance(chunk_result, tuple)
224
- shared_output_chunk, hidden_states_chunk = chunk_result
225
- final_fused_hidden_states[chunk_start:chunk_end, :].copy_(
226
- hidden_states_chunk, non_blocking=True
227
- )
228
- assert shared_output_chunk is not None
229
- assert final_shared_hidden_states is not None
230
- final_shared_hidden_states[chunk_start:chunk_end, :].copy_(
231
- shared_output_chunk, non_blocking=True
232
- )
233
- else:
234
- assert isinstance(chunk_result, torch.Tensor)
235
- final_fused_hidden_states[chunk_start:chunk_end, :].copy_(
236
- chunk_result, non_blocking=True
237
- )
238
-
239
- if self.shared_experts is None:
240
- return final_fused_hidden_states
241
- else:
242
- assert final_shared_hidden_states is not None
243
- return (final_shared_hidden_states, final_fused_hidden_states)
vllm/model_executor/layers/fused_moe/runner/moe_runner_factory.py
+1
-7
@@ -12,9 +12,6 @@ from vllm.model_executor.layers.fused_moe.fused_moe_method_base import (
12
from vllm.model_executor.layers.fused_moe.router.fused_moe_router import (
13
FusedMoERouter,
14
)
15
-from vllm.model_executor.layers.fused_moe.runner.chunking_moe_runner import (
16
- ChunkingMoERunner,
17
-)
15
from vllm.model_executor.layers.fused_moe.runner.default_moe_runner import (
16
DefaultMoERunner,
17
)
@@ -35,7 +32,7 @@ def create_moe_runner(
32
reduce_results: bool,
33
enable_dbo: bool,
34
) -> MoERunner:
38
- runner = DefaultMoERunner(
35
+ return DefaultMoERunner(
36
layer_name,
37
moe_config,
38
router,
@@ -46,6 +43,3 @@ def create_moe_runner(
43
reduce_results,
44
enable_dbo,
45
)
49
- if moe_config.moe_parallel_config.use_dp_chunking:
50
- return ChunkingMoERunner(runner)
51
- return runner
vllm/model_executor/layers/fused_moe/runner/shared_experts.py
-16
@@ -69,7 +69,6 @@ class SharedExperts:
69
self._moe_config = moe_config
70
self._quant_method = quant_method
71
self._reduce_results = reduce_results
72
- self._use_dp_chunking = moe_config.moe_parallel_config.use_dp_chunking
72
73
# Allow disabling of the separate shared experts stream for
74
# debug purposes.
@@ -87,20 +86,6 @@ class SharedExperts:
86
"Enabled separate cuda stream for MoE shared_experts", scope="local"
87
)
88
90
- @property
91
- def _use_external_experts(self) -> bool:
92
- if self._use_dp_chunking:
93
- return False
94
-
95
- # Disable shared expert overlap if:
96
- # - we are using eplb with non-default backend, because of correctness issues
97
- # - we are using flashinfer with DP, since there nothing to gain
98
- backend = self._moe_config.moe_parallel_config.all2all_backend
99
- return (
100
- self._moe_config.moe_parallel_config.enable_eplb
101
- and backend != "allgather_reducescatter"
102
- ) or self._moe_config.moe_parallel_config.use_fi_nvl_two_sided_kernels
103
-
89
def _determine_shared_experts_order(
90
self,
91
hidden_states: torch.Tensor,
@@ -110,7 +95,6 @@ class SharedExperts:
95
96
should_run_shared_in_aux_stream = (
97
current_platform.is_cuda()
113
- and not self._use_dp_chunking
98
and self._stream is not None
99
and hidden_states.shape[0]
100
<= envs.VLLM_SHARED_EXPERTS_STREAM_TOKEN_THRESHOLD
vllm/model_executor/layers/quantization/quark/quark_moe.py
+2
-2
@@ -1502,9 +1502,9 @@ class QuarkOCP_MX_MoEMethod_OSS(QuarkOCP_MX_MoEMethod):
1502
layer.w2_bias = torch.nn.Parameter(w2_bias, requires_grad=False)
1503
1504
# FIXME warp need to be adjusted based on batch size
1505
- # only apply to batched mode
1505
+ # only apply to batched mode
1506
if self.moe.use_ep:
1507
- num_warps = 4 if envs.VLLM_MOE_DP_CHUNK_SIZE <= 512 else 8
1507
+ num_warps = 4 if self.moe.max_num_tokens <= 512 else 8
1508
else:
1509
num_warps = 8
1510