Repository navigation
[MoE][Bugfix] Skip SP padded rows in grouped MoE routing - #56079
Conversation
0d3e2c9 to
169a56b
Compare
There was a problem hiding this comment.
Looks like there is an issue with DBO -- details via codex
Details
Review comment:
- [P2] Propagate the mask into DBO's microbatch contexts — /Users/tms/code/vllm/vllm/v1/worker/gpu_model_runner.py:4555-4555
When the legacy runner enables DBO, _model_forward enters UBatchWrapper, whose _make_ubatch_metadata() replaces this outer context with per-microbatch contexts created without is_padding. Kimi's
sp_padding_mask therefore treats existing DP/CUDA-graph padding in each microbatch as real tokens, and the grouped router still dispatches those rows under DeepEP v2. Pass the appropriately sliced mask
into each DBO context as the v2 runner does.
DBO needs to be handled in the legacy vllm/v1/worker/gpu_ubatch_wrapper.py:252, because it replaces the outer forward context.
The flow should be:
- gpu_model_runner.py puts the full-batch is_padding mask on the outer context.
- UBatchWrapper.call() (vllm/v1/worker/gpu_ubatch_wrapper.py:375) reads forward_context.is_padding.
- Both _make_ubatch_metadata() calls pass that mask onward.
- Each per-microbatch create_forward_context() gets:
is_padding=(
is_padding[ubatch_slice.token_slice]
if is_padding is not None
else None
)
The two paths to cover are:
- CUDA-graph capture at line 406 (vllm/v1/worker/gpu_ubatch_wrapper.py:406)
- Ordinary DBO execution at line 432 (vllm/v1/worker/gpu_ubatch_wrapper.py:432)
That mirrors the v2 implementation in vllm/v1/worker/gpu/ubatch_utils.py:351, where each microbatch context receives its sliced is_padding tensor. Merely passing the mask into the outer context in
gpu_model_runner.py is insufficient because DBO overrides it.
Otherwise LGTM
Propagate persistent padding masks through both GPU model runners. Opt grouped-router invalidation in only for Kimi-K3 and require the resolved MoE backend to be DeepEP v2. Co-authored-by: OpenAI Codex <codex@openai.com> Signed-off-by: Elvir Crncevic <elvircrn@gmail.com>
Co-authored-by: OpenAI Codex <codex@openai.com> Signed-off-by: Elvir Crncevic <elvircrn@gmail.com>
169a56b to
28e965f
Compare
|
✅ @elvircrn, CI is now available for this PR.
|
|
/ci run |
|
✅ Triggered Buildkite CI #88818 for commit |
|
/ci run |
|
✅ Triggered Buildkite CI #89406 for commit |
|
/ci retry |
|
✅ Triggered Buildkite CI #89695 for commit |
Root cause: upstream vllm#56079 added a `skip_padding: bool = False` kwarg to create_fused_moe_router()/GroupedTopKRouter to invalidate sequence-parallel padding rows in grouped MoE routing. The vllm-gaudi override mirrors this factory's signature and did not accept the new kwarg, so every call site now raises: TypeError: create_fused_moe_router() got an unexpected keyword argument 'skip_padding' Upstream: vllm-project/vllm#56079 Fix: accept skip_padding on the override (signature parity) and forward it to GroupedTopKRouter; the guard it enables only fires under VLLM_MOE_SKIP_PADDING + DeepEP-v2-kernel forward context, which HPU never exercises, so this is a no-op on HPU beyond restoring the call signature. Signed-off-by: Paweł Olejniczak <pawelx.olejniczak@intel.com>
…d skip_padding kwarg, drop stale manager.touch() (+3 more) (#1806) This PR consolidates 5 hourly-CI fixes against vllm@`9a70c233cd5d3ef3b14d79c582a6f9ddfa03cf80`. ## Bug 1: forward skip_padding kwarg through HPU MoE router factory override - **State machine id**: create_fused_moe_router_unexpected_kwarg - **Commit**: 65cc65e ### Root cause upstream vllm#56079 added a `skip_padding: bool = False` kwarg to create_fused_moe_router()/GroupedTopKRouter to invalidate sequence-parallel padding rows in grouped MoE routing. The vllm-gaudi override mirrors this factory's signature and did not accept the new kwarg, so every call site now raises: TypeError: create_fused_moe_router() got an unexpected keyword argument 'skip_padding' ### Culprit Regression introduced by [PR #56079](vllm-project/vllm#56079). ### Fix accept skip_padding on the override (signature parity) and forward it to GroupedTopKRouter; the guard it enables only fires under VLLM_MOE_SKIP_PADDING + DeepEP-v2-kernel forward context, which HPU never exercises, so this is a no-op on HPU beyond restoring the call signature. ## Bug 2: drop stale manager.touch() assertions in offloading connector test - **State machine id**: offloading_connector_touch_assertion - **Commit**: c5c5c55 ### Root cause upstream vllm#51787 ("Track cache recency once per request") removed OffloadingConnectorScheduler._touch and every manager.touch() call site, replacing per-call cache-recency tracking with req_context.set_offload_key_position() tracked once per request. vllm-gaudi's vendored copy of the unit test still asserted the old manager.touch() calls, so it now fails: AssertionError: Expected 'touch' to have been called. ### Culprit Probable culprit: [PR #51787](vllm-project/vllm#51787) - pinned by symbol archaeology, bisect not run. Candidate range: [compare](vllm-project/vllm@4be3dcf...9a70c23). ### Fix mirror upstream's own post-#51787 test update (its analogous tests/v1/kv_connector/unit/offloading_connector/test_scheduler.py) by dropping the removed-call assertions and asserting touch is no longer called for the same scenario. ## Bug 3: add missing release_kv_cache_memory to MultiModelEngineClient - **State machine id**: online_model_swap_multimodelengineclient_abstract - **Commit**: 7ba9ac9 ### Root cause upstream vllm#44890 added a new abstract method release_kv_cache_memory to EngineClient; MultiModelEngineClient never implemented it, so instantiation raised TypeError. ### Culprit Probable culprit: [PR #44890](vllm-project/vllm#44890) - pinned by symbol archaeology, bisect not run. Candidate range: [compare](vllm-project/vllm@4be3dcf...9a70c23). ### Fix delegate to the wrapped AsyncLLM instance, mirroring the existing sleep/wake_up passthrough pattern. ## Bug 4: skip is_sleeping assignment on read-only Executor property - **State machine id**: online_model_swap_multimodelengineclient_abstract - **Commit**: 198d7e9 ### Root cause upstream vllm#44890 (same PR as the MultiModelEngineClient abstract-method break) turned Executor.is_sleeping into a read-only property computed from sleeping_tags. gaudi_reconfigure_engine's _reset_executor_sleep_state still assigned model_executor.is_sleeping directly, raising AttributeError: property 'is_sleeping' of 'UniProcExecutor' object has no setter during online model swap. ### Culprit Probable culprit: [PR #44890](vllm-project/vllm#44890) - pinned by symbol archaeology, bisect not run. Candidate range: [compare](vllm-project/vllm@4be3dcf...9a70c23). ### Fix feature-detect whether is_sleeping is a class-level property before assigning it; clearing sleeping_tags already makes the property read False on the new executor. ## Bug 5: implement apply_lora_full_linear on PunicaWrapperHPU - **State machine id**: hpu_unit_tests_engine_core_init_failed - **Commit**: 18d4414 ### Root cause upstream vllm PR 53555 ("[LoRA] Support modules_to_save for sequence classification") added a new abstract method apply_lora_full_linear to PunicaWrapperABC and implemented it for CPU, GPU and XPU. PunicaWrapperHPU never implemented it, so it is no longer a concrete class and get_punica_wrapper() raises TypeError: Can't instantiate abstract class PunicaWrapperHPU without an implementation for abstract method 'apply_lora_full_linear' while loading any LoRA model on HPU, which the engine surfaces as the generic "Engine core initialization failed". ### Culprit Probable culprit: [PR #53555](vllm-project/vllm#53555) - pinned by symbol archaeology, bisect not run. Candidate range: [compare](vllm-project/vllm@4be3dcf...9a70c23). ### Fix implement the hook with plain torch ops, mirroring the CPU and GPU versions: route rows through the prompt-level sampler_indices mapping and hand off to the inherited _select_full_linear_output helper for the bias and module-enabled selection. Multiplying against every adapter and gathering the routed row afterwards keeps the weight operand statically shaped for HPU graph compilation. The new method only references _select_full_linear_output at call time, and its only caller (ClassificationHeadWithLoRA) postdates PR 53555, so the change stays compatible with older VLLM_STABLE_COMMIT builds. --------- Signed-off-by: Paweł Olejniczak <pawelx.olejniczak@intel.com>
The gist of the issue is that sequence parallelism needs to pad token counts divisible by TP size and that vllm incorrectly doesn't mark these padded tokens as ignored.
Purpose
While running Kimi k3 e2e experiments, an imbalance in expert routing was observed:
making rank 0 a straggler rank:
tanking prefill performance.
With this patch, we get the following accumulated expert token counts during a subset of the 15-min aiperf benchmark run with claude code traces:

and get the following e2e speed-ups:
with the following gsm8k scores:
Test Plan
Test Result
Essential Elements of an Effective PR Description Checklist
supported_models.mdandexamplesfor a new model.