[Bugfix][Hybrid] Fix cross-block race on num_accepted in MRv2 align prefix cache - #50432
Conversation
0f2d780 to
3d5901b
Compare
…ostprocess run_fused_postprocess_align passed num_accepted_tokens_gpu as both the kernel's read source and the in-place write target. This could lead to a race. The MRv1 path already avoided this by writing to a distinct num_accepted_tokens_out buffer. This PR applies the same pattern to MRv2. Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
3dad264 to
1867c16
Compare
|
cc @izhuhaoran |
izhuhaoran
left a comment
There was a problem hiding this comment.
@fuscof-ibm Thanks for identifying and fixing this subtle cross-program race. Separating the kernel’s read source from its write target is the correct approach. I left a suggested change to further simplify the implementation: reuse the existing output buffer as an immutable snapshot for the MRv2 path, while writing reset values directly to num_accepted_tokens_gpu. This keeps MRv1 unchanged, remains safe with non-contiguous idx_mapping, and eliminates the final full-buffer copy back. Also cc @njhill
| ``num_accepted_tokens_gpu`` is updated with the aid of a scratch tensor | ||
| (reset to 1 when the accepted position stays in the running block) to | ||
| avoid races in the `postprocess_mamba_fused_kernel`. | ||
| ``new_num_computed_tokens`` already holds the post-step computed count | ||
| (PRECOMPUTED_NEW_COMPUTED). | ||
| ``idx_mapping`` maps batch row -> req-state slot (HAS_IDX_MAPPING). | ||
| """ | ||
| if num_reqs == 0 or not self.is_initialized: | ||
| return | ||
|
|
||
| # Seed the whole scratch tensor: the kernel writes at idx_mapping | ||
| # positions which are not contiguous in [0:num_reqs] under V2. | ||
| self.num_accepted_tokens_out.copy_(num_accepted_tokens_gpu) | ||
|
|
||
| total_states = self.num_layers * self.num_state_types | ||
| grid = (num_reqs, total_states) | ||
|
|
||
| postprocess_mamba_fused_kernel[grid]( | ||
| num_accepted_tokens_gpu, | ||
| state_idx_gpu, |
There was a problem hiding this comment.
| ``num_accepted_tokens_gpu`` is updated with the aid of a scratch tensor | |
| (reset to 1 when the accepted position stays in the running block) to | |
| avoid races in the `postprocess_mamba_fused_kernel`. | |
| ``new_num_computed_tokens`` already holds the post-step computed count | |
| (PRECOMPUTED_NEW_COMPUTED). | |
| ``idx_mapping`` maps batch row -> req-state slot (HAS_IDX_MAPPING). | |
| """ | |
| if num_reqs == 0 or not self.is_initialized: | |
| return | |
| # Seed the whole scratch tensor: the kernel writes at idx_mapping | |
| # positions which are not contiguous in [0:num_reqs] under V2. | |
| self.num_accepted_tokens_out.copy_(num_accepted_tokens_gpu) | |
| total_states = self.num_layers * self.num_state_types | |
| grid = (num_reqs, total_states) | |
| postprocess_mamba_fused_kernel[grid]( | |
| num_accepted_tokens_gpu, | |
| state_idx_gpu, | |
| ``num_accepted_tokens_gpu`` is updated in place while the kernel reads | |
| from a snapshot to avoid cross-program races when the accepted position | |
| stays in the running block and the count is reset to 1. | |
| ``new_num_computed_tokens`` already holds the post-step computed count | |
| (PRECOMPUTED_NEW_COMPUTED). | |
| ``idx_mapping`` maps batch row -> req-state slot (HAS_IDX_MAPPING). | |
| """ | |
| if num_reqs == 0 or not self.is_initialized: | |
| return | |
| # V2 reads non-contiguous idx_mapping positions, so snapshot the whole | |
| # decision buffer rather than only [:num_reqs]. | |
| num_accepted_tokens_snapshot = self.num_accepted_tokens_out | |
| num_accepted_tokens_snapshot.copy_(num_accepted_tokens_gpu) | |
| total_states = self.num_layers * self.num_state_types | |
| grid = (num_reqs, total_states) | |
| postprocess_mamba_fused_kernel[grid]( | |
| num_accepted_tokens_snapshot, | |
| state_idx_gpu, |
There was a problem hiding this comment.
Thanks @izhuhaoran . Indeed one can save a D2D copy. I pushed the update you suggested (and rerun the test).
CC @njhill
| @@ -890,6 +895,8 @@ def run_fused_postprocess_align( | |||
| PRECOMPUTED_NEW_COMPUTED=True, | |||
| ) | |||
|
|
|||
| num_accepted_tokens_gpu.copy_(self.num_accepted_tokens_out) | |||
|
|
|||
There was a problem hiding this comment.
| num_accepted_tokens_gpu, | |
| idx_mapping, | |
| num_reqs, | |
| block_size=self.block_size, | |
| COPY_BLOCK_SIZE=1024, | |
| CONV_STATE_DIM_FIRST=is_conv_state_dim_first(), | |
| HAS_IDX_MAPPING=True, | |
| PRECOMPUTED_NEW_COMPUTED=True, | |
| ) | |
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
izhuhaoran
left a comment
There was a problem hiding this comment.
Thanks for this fix. LGTM
njhill
left a comment
There was a problem hiding this comment.
Thanks @fuscof-ibm @izhuhaoran
Port upstream vLLM vllm-project#50432 to remove a cross-block race in MRV2 aligned prefix-cache state updates.
### What this PR does / why we need it? #### Upgrade baseline - Update the verified vLLM main anchor from [`2e09247c2d7b6b97d13af6e71a85bf8d1271deb6`](vllm-project/vllm@2e09247) to [`58d3918e3ea0a544ffedadad2ba84559e9c51d8f`](vllm-project/vllm@58d3918). The full upstream range is available in this [comparison](vllm-project/vllm@2e09247...58d3918). - Preserve the vLLM `0.26.0` compatibility lane while adapting the main lane to the new upstream contracts. Version gates use `vllm_version_is("0.26.0")` and are limited to real contract differences. - The changes are organized in the same order as the changed files in this PR. Each item identifies the upstream change, the downstream adaptation, and why the adaptation is required. #### Changes by file ##### 1. `.github/vllm-main-verified.commit` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Update anchor to `58d3918e` | Upgrade window [0351e9aa...58d3918e](vllm-project/vllm@0351e9a...58d3918). | Set anchor. | Source of truth for main2main workflow. | ##### 2. `vllm_ascend/patch/platform/patch_fused_moe.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate FusedMoE → FusedMoEFactory rename | [vllm #44941](vllm-project/vllm#44941) renamed `FusedMoE` to `FusedMoEFactory`. | On main, capture and patch `FusedMoEFactory`; on v0.26.0, also patch legacy `FusedMoE`. | Both lanes need the Ascend runner patch at the correct binding. | ##### 3. `vllm_ascend/models/deepseek_v4.py` / `vllm_ascend/models/minimax_m3/minimax_m3.py` / `vllm_ascend/ops/fused_moe/fused_moe.py` / `vllm_ascend/ops/fused_moe/routed_experts.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Import and use `FusedMoEFactory`; remove dead `FusedMoE` re-export | [vllm #44941](vllm-project/vllm#44941). | Replace `FusedMoE` with `FusedMoEFactory`. | Old symbol no longer exists on main. Remove stale `FusedMoE` re-export from `fused_moe.py` and dead reference in `routed_experts.py` comment. | ##### 4. `tests/ut/models/test_deepseek_v4_moe.py` / `tests/ut/models/minimax_m3/test_minimax_m3.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Update monkeypatch target to `FusedMoEFactory` | [vllm #44941](vllm-project/vllm#44941). | `"FusedMoE"` → `"FusedMoEFactory"`. | Must match the symbol imported by models. | ##### 5. `vllm_ascend/worker/model_runner_v1.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate `calculate_kv_scales` removal | [vllm #49389](vllm-project/vllm#49389) removed runtime KV-scale calculation. | Add `vllm_version_is("0.26.0")` guard. | Ascend MRV1 still supports it on v0.26.0; attribute absent on main. | | Version-gate `clear_buffer()` removal | [vllm #50721](vllm-project/vllm#50721) removed `clear_buffer()` from `RoutedExpertsCapturer`. | Wrap in `vllm_version_is("0.26.0")` guard. | On main, each routed layer overwrites current step's token rows. | ##### 6. `vllm_ascend/models/layer/attention/layer.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Remove dead `Q/K/V_SCALE_CONSTANT` references | [vllm #49389](vllm-project/vllm#49389) removed env var registrations. Module-level constants still exist. | Remove unused `q_range`/`k_range`/`v_range` initializations and dead `import envs`. | Dead-code cleanup; `DSAAttention.forward()` never used these attributes. | ##### 7. `tests/ut/patch/platform/test_deepseek_v4_thinking.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate reasoning effort expectations | [vllm #50580](vllm-project/vllm#50580) maps `low`/`minimal`/`medium` → `low`. | `vllm_version_is("0.26.0")` guard. | v0.26.0 keeps old mapping; main uses new. | ##### 8. `tests/e2e/pull_request/one_card/spec_decode/test_extract_hidden_states.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Enable `chunked_prefill` for hybrid model | [vllm #50991](vllm-project/vllm#50991) enabled prefix cache by default for Mamba/hybrid models. | `False` → `True`. | Hybrid model now requires chunked prefill. | ##### 9. `vllm_ascend/patch/platform/patch_vision.py` (new) + `vllm_ascend/patch/platform/__init__.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Patch `FusedInputNorm.forward` eps=0.0 → eps=1e-5 | [vllm #50411](vllm-project/vllm#50411) added `FusedInputNorm` with `F.batch_norm(eps=0.0)`. | Monkey-patch forward to use `eps=1e-5`; guarded with `contextlib.suppress(ImportError)`. | Upstream PyTorch 2.13.0 allows eps >= 0 for inference; vllm-ascend PyTorch 2.10.0 requires eps > 0 always. Release wheels lack `FusedInputNorm`. Remove this patch once bundled PyTorch >= 2.13.0. | ##### 10. `vllm_ascend/ops/triton/mamba/postprocess.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Add kernel signature parameters | [vllm #50432](vllm-project/vllm#50432) changed signature. | Add `CONV_STATE_DIM_FIRST`, `HAS_IDX_MAPPING`, `PRECOMPUTED_NEW_COMPUTED`, `state_dim_row_count/stride`, `idx_mapping_ptr` parameters, and `num_loops` for DS conv copy. | Must match upstream kernel contract. | ##### 11. `tests/e2e/conftest.py` / `tests/ut/spec_decode/test_speculators_vwn_eagle3.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | HunyuanVL placeholder version gate; remove unused `maybe_calc_kv_scales` mock | [vllm #49691](vllm-project/vllm#49691), #49389. | Version gate and dead-mock removal. | Adapt to upstream contract changes. | ##### 12. `vllm_ascend/patch/__init__.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Document FusedMoE → FusedMoEFactory rename and new patch_vision entry | — | Update patch registry documentation. | Keep the patch manifest in sync with reality. | #### Compatibility and review notes - Version gates use `vllm_version_is("0.26.0")` exclusively; no `hasattr` fallbacks beyond the explicitly justified `clear_buffer` guard (where the upstream change is a method removal, not a rename). - The `FusedMoE` → `FusedMoEFactory` rename is applied consistently across all call sites: `deepseek_v4.py`, `minimax_m3.py`, `fused_moe.py`, `routed_experts.py`, and `patch_fused_moe.py`. - The `layer.py` `Q/K/V_SCALE_CONSTANT` removal is a dead-code cleanup: the `DSAAttention` class initialized these tensors from `envs` module-level constants (which still exist), but never used them in `forward()`. ### Does this PR introduce _any_ user-facing change? No. This is a compatibility update; no new Ascend-specific public API is introduced. ### How was this patch tested? CI on the branch. See Buildkite workflow run for detailed results. - vLLM version: v0.26.0 - vLLM main: vllm-project/vllm@0351e9a --------- Signed-off-by: liaoqidan <1107297340@qq.com>
### What this PR does / why we need it? #### Upgrade baseline - Update the verified vLLM main anchor from [`2e09247c2d7b6b97d13af6e71a85bf8d1271deb6`](vllm-project/vllm@2e09247) to [`58d3918e3ea0a544ffedadad2ba84559e9c51d8f`](vllm-project/vllm@58d3918). The full upstream range is available in this [comparison](vllm-project/vllm@2e09247...58d3918). - Preserve the vLLM `0.26.0` compatibility lane while adapting the main lane to the new upstream contracts. Version gates use `vllm_version_is("0.26.0")` and are limited to real contract differences. - The changes are organized in the same order as the changed files in this PR. Each item identifies the upstream change, the downstream adaptation, and why the adaptation is required. #### Changes by file ##### 1. `.github/vllm-main-verified.commit` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Update anchor to `58d3918e` | Upgrade window [0351e9aa...58d3918e](vllm-project/vllm@0351e9a...58d3918). | Set anchor. | Source of truth for main2main workflow. | ##### 2. `vllm_ascend/patch/platform/patch_fused_moe.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate FusedMoE → FusedMoEFactory rename | [vllm #44941](vllm-project/vllm#44941) renamed `FusedMoE` to `FusedMoEFactory`. | On main, capture and patch `FusedMoEFactory`; on v0.26.0, also patch legacy `FusedMoE`. | Both lanes need the Ascend runner patch at the correct binding. | ##### 3. `vllm_ascend/models/deepseek_v4.py` / `vllm_ascend/models/minimax_m3/minimax_m3.py` / `vllm_ascend/ops/fused_moe/fused_moe.py` / `vllm_ascend/ops/fused_moe/routed_experts.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Import and use `FusedMoEFactory`; remove dead `FusedMoE` re-export | [vllm #44941](vllm-project/vllm#44941). | Replace `FusedMoE` with `FusedMoEFactory`. | Old symbol no longer exists on main. Remove stale `FusedMoE` re-export from `fused_moe.py` and dead reference in `routed_experts.py` comment. | ##### 4. `tests/ut/models/test_deepseek_v4_moe.py` / `tests/ut/models/minimax_m3/test_minimax_m3.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Update monkeypatch target to `FusedMoEFactory` | [vllm #44941](vllm-project/vllm#44941). | `"FusedMoE"` → `"FusedMoEFactory"`. | Must match the symbol imported by models. | ##### 5. `vllm_ascend/worker/model_runner_v1.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate `calculate_kv_scales` removal | [vllm #49389](vllm-project/vllm#49389) removed runtime KV-scale calculation. | Add `vllm_version_is("0.26.0")` guard. | Ascend MRV1 still supports it on v0.26.0; attribute absent on main. | | Version-gate `clear_buffer()` removal | [vllm #50721](vllm-project/vllm#50721) removed `clear_buffer()` from `RoutedExpertsCapturer`. | Wrap in `vllm_version_is("0.26.0")` guard. | On main, each routed layer overwrites current step's token rows. | ##### 6. `vllm_ascend/models/layer/attention/layer.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Remove dead `Q/K/V_SCALE_CONSTANT` references | [vllm #49389](vllm-project/vllm#49389) removed env var registrations. Module-level constants still exist. | Remove unused `q_range`/`k_range`/`v_range` initializations and dead `import envs`. | Dead-code cleanup; `DSAAttention.forward()` never used these attributes. | ##### 7. `tests/ut/patch/platform/test_deepseek_v4_thinking.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate reasoning effort expectations | [vllm #50580](vllm-project/vllm#50580) maps `low`/`minimal`/`medium` → `low`. | `vllm_version_is("0.26.0")` guard. | v0.26.0 keeps old mapping; main uses new. | ##### 8. `tests/e2e/pull_request/one_card/spec_decode/test_extract_hidden_states.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Enable `chunked_prefill` for hybrid model | [vllm #50991](vllm-project/vllm#50991) enabled prefix cache by default for Mamba/hybrid models. | `False` → `True`. | Hybrid model now requires chunked prefill. | ##### 9. `vllm_ascend/patch/platform/patch_vision.py` (new) + `vllm_ascend/patch/platform/__init__.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Patch `FusedInputNorm.forward` eps=0.0 → eps=1e-5 | [vllm #50411](vllm-project/vllm#50411) added `FusedInputNorm` with `F.batch_norm(eps=0.0)`. | Monkey-patch forward to use `eps=1e-5`; guarded with `contextlib.suppress(ImportError)`. | Upstream PyTorch 2.13.0 allows eps >= 0 for inference; vllm-ascend PyTorch 2.10.0 requires eps > 0 always. Release wheels lack `FusedInputNorm`. Remove this patch once bundled PyTorch >= 2.13.0. | ##### 10. `vllm_ascend/ops/triton/mamba/postprocess.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Add kernel signature parameters | [vllm #50432](vllm-project/vllm#50432) changed signature. | Add `CONV_STATE_DIM_FIRST`, `HAS_IDX_MAPPING`, `PRECOMPUTED_NEW_COMPUTED`, `state_dim_row_count/stride`, `idx_mapping_ptr` parameters, and `num_loops` for DS conv copy. | Must match upstream kernel contract. | ##### 11. `tests/e2e/conftest.py` / `tests/ut/spec_decode/test_speculators_vwn_eagle3.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | HunyuanVL placeholder version gate; remove unused `maybe_calc_kv_scales` mock | [vllm #49691](vllm-project/vllm#49691), #49389. | Version gate and dead-mock removal. | Adapt to upstream contract changes. | ##### 12. `vllm_ascend/patch/__init__.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Document FusedMoE → FusedMoEFactory rename and new patch_vision entry | — | Update patch registry documentation. | Keep the patch manifest in sync with reality. | #### Compatibility and review notes - Version gates use `vllm_version_is("0.26.0")` exclusively; no `hasattr` fallbacks beyond the explicitly justified `clear_buffer` guard (where the upstream change is a method removal, not a rename). - The `FusedMoE` → `FusedMoEFactory` rename is applied consistently across all call sites: `deepseek_v4.py`, `minimax_m3.py`, `fused_moe.py`, `routed_experts.py`, and `patch_fused_moe.py`. - The `layer.py` `Q/K/V_SCALE_CONSTANT` removal is a dead-code cleanup: the `DSAAttention` class initialized these tensors from `envs` module-level constants (which still exist), but never used them in `forward()`. ### Does this PR introduce _any_ user-facing change? No. This is a compatibility update; no new Ascend-specific public API is introduced. ### How was this patch tested? CI on the branch. See Buildkite workflow run for detailed results. - vLLM version: v0.26.0 - vLLM main: vllm-project/vllm@0351e9a --------- Signed-off-by: liaoqidan <1107297340@qq.com>
### What this PR does / why we need it? #### Upgrade baseline - Update the verified vLLM main anchor from [`2e09247c2d7b6b97d13af6e71a85bf8d1271deb6`](vllm-project/vllm@2e09247) to [`58d3918e3ea0a544ffedadad2ba84559e9c51d8f`](vllm-project/vllm@58d3918). The full upstream range is available in this [comparison](vllm-project/vllm@2e09247...58d3918). - Preserve the vLLM `0.26.0` compatibility lane while adapting the main lane to the new upstream contracts. Version gates use `vllm_version_is("0.26.0")` and are limited to real contract differences. - The changes are organized in the same order as the changed files in this PR. Each item identifies the upstream change, the downstream adaptation, and why the adaptation is required. #### Changes by file ##### 1. `.github/vllm-main-verified.commit` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Update anchor to `58d3918e` | Upgrade window [0351e9aa...58d3918e](vllm-project/vllm@0351e9a...58d3918). | Set anchor. | Source of truth for main2main workflow. | ##### 2. `vllm_ascend/patch/platform/patch_fused_moe.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate FusedMoE → FusedMoEFactory rename | [vllm #44941](vllm-project/vllm#44941) renamed `FusedMoE` to `FusedMoEFactory`. | On main, capture and patch `FusedMoEFactory`; on v0.26.0, also patch legacy `FusedMoE`. | Both lanes need the Ascend runner patch at the correct binding. | ##### 3. `vllm_ascend/models/deepseek_v4.py` / `vllm_ascend/models/minimax_m3/minimax_m3.py` / `vllm_ascend/ops/fused_moe/fused_moe.py` / `vllm_ascend/ops/fused_moe/routed_experts.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Import and use `FusedMoEFactory`; remove dead `FusedMoE` re-export | [vllm #44941](vllm-project/vllm#44941). | Replace `FusedMoE` with `FusedMoEFactory`. | Old symbol no longer exists on main. Remove stale `FusedMoE` re-export from `fused_moe.py` and dead reference in `routed_experts.py` comment. | ##### 4. `tests/ut/models/test_deepseek_v4_moe.py` / `tests/ut/models/minimax_m3/test_minimax_m3.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Update monkeypatch target to `FusedMoEFactory` | [vllm #44941](vllm-project/vllm#44941). | `"FusedMoE"` → `"FusedMoEFactory"`. | Must match the symbol imported by models. | ##### 5. `vllm_ascend/worker/model_runner_v1.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate `calculate_kv_scales` removal | [vllm #49389](vllm-project/vllm#49389) removed runtime KV-scale calculation. | Add `vllm_version_is("0.26.0")` guard. | Ascend MRV1 still supports it on v0.26.0; attribute absent on main. | | Version-gate `clear_buffer()` removal | [vllm #50721](vllm-project/vllm#50721) removed `clear_buffer()` from `RoutedExpertsCapturer`. | Wrap in `vllm_version_is("0.26.0")` guard. | On main, each routed layer overwrites current step's token rows. | ##### 6. `vllm_ascend/models/layer/attention/layer.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Remove dead `Q/K/V_SCALE_CONSTANT` references | [vllm #49389](vllm-project/vllm#49389) removed env var registrations. Module-level constants still exist. | Remove unused `q_range`/`k_range`/`v_range` initializations and dead `import envs`. | Dead-code cleanup; `DSAAttention.forward()` never used these attributes. | ##### 7. `tests/ut/patch/platform/test_deepseek_v4_thinking.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate reasoning effort expectations | [vllm #50580](vllm-project/vllm#50580) maps `low`/`minimal`/`medium` → `low`. | `vllm_version_is("0.26.0")` guard. | v0.26.0 keeps old mapping; main uses new. | ##### 8. `tests/e2e/pull_request/one_card/spec_decode/test_extract_hidden_states.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Enable `chunked_prefill` for hybrid model | [vllm #50991](vllm-project/vllm#50991) enabled prefix cache by default for Mamba/hybrid models. | `False` → `True`. | Hybrid model now requires chunked prefill. | ##### 9. `vllm_ascend/patch/platform/patch_vision.py` (new) + `vllm_ascend/patch/platform/__init__.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Patch `FusedInputNorm.forward` eps=0.0 → eps=1e-5 | [vllm #50411](vllm-project/vllm#50411) added `FusedInputNorm` with `F.batch_norm(eps=0.0)`. | Monkey-patch forward to use `eps=1e-5`; guarded with `contextlib.suppress(ImportError)`. | Upstream PyTorch 2.13.0 allows eps >= 0 for inference; vllm-ascend PyTorch 2.10.0 requires eps > 0 always. Release wheels lack `FusedInputNorm`. Remove this patch once bundled PyTorch >= 2.13.0. | ##### 10. `vllm_ascend/ops/triton/mamba/postprocess.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Add kernel signature parameters | [vllm #50432](vllm-project/vllm#50432) changed signature. | Add `CONV_STATE_DIM_FIRST`, `HAS_IDX_MAPPING`, `PRECOMPUTED_NEW_COMPUTED`, `state_dim_row_count/stride`, `idx_mapping_ptr` parameters, and `num_loops` for DS conv copy. | Must match upstream kernel contract. | ##### 11. `tests/e2e/conftest.py` / `tests/ut/spec_decode/test_speculators_vwn_eagle3.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | HunyuanVL placeholder version gate; remove unused `maybe_calc_kv_scales` mock | [vllm #49691](vllm-project/vllm#49691), #49389. | Version gate and dead-mock removal. | Adapt to upstream contract changes. | ##### 12. `vllm_ascend/patch/__init__.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Document FusedMoE → FusedMoEFactory rename and new patch_vision entry | — | Update patch registry documentation. | Keep the patch manifest in sync with reality. | #### Compatibility and review notes - Version gates use `vllm_version_is("0.26.0")` exclusively; no `hasattr` fallbacks beyond the explicitly justified `clear_buffer` guard (where the upstream change is a method removal, not a rename). - The `FusedMoE` → `FusedMoEFactory` rename is applied consistently across all call sites: `deepseek_v4.py`, `minimax_m3.py`, `fused_moe.py`, `routed_experts.py`, and `patch_fused_moe.py`. - The `layer.py` `Q/K/V_SCALE_CONSTANT` removal is a dead-code cleanup: the `DSAAttention` class initialized these tensors from `envs` module-level constants (which still exist), but never used them in `forward()`. ### Does this PR introduce _any_ user-facing change? No. This is a compatibility update; no new Ascend-specific public API is introduced. ### How was this patch tested? CI on the branch. See Buildkite workflow run for detailed results. - vLLM version: v0.26.0 - vLLM main: vllm-project/vllm@0351e9a --------- Signed-off-by: liaoqidan <1107297340@qq.com>
### What this PR does / why we need it? #### Upgrade baseline - Update the verified vLLM main anchor from [`2e09247c2d7b6b97d13af6e71a85bf8d1271deb6`](vllm-project/vllm@2e09247) to [`58d3918e3ea0a544ffedadad2ba84559e9c51d8f`](vllm-project/vllm@58d3918). The full upstream range is available in this [comparison](vllm-project/vllm@2e09247...58d3918). - Preserve the vLLM `0.26.0` compatibility lane while adapting the main lane to the new upstream contracts. Version gates use `vllm_version_is("0.26.0")` and are limited to real contract differences. - The changes are organized in the same order as the changed files in this PR. Each item identifies the upstream change, the downstream adaptation, and why the adaptation is required. #### Changes by file ##### 1. `.github/vllm-main-verified.commit` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Update anchor to `58d3918e` | Upgrade window [0351e9aa...58d3918e](vllm-project/vllm@0351e9a...58d3918). | Set anchor. | Source of truth for main2main workflow. | ##### 2. `vllm_ascend/patch/platform/patch_fused_moe.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate FusedMoE → FusedMoEFactory rename | [vllm #44941](vllm-project/vllm#44941) renamed `FusedMoE` to `FusedMoEFactory`. | On main, capture and patch `FusedMoEFactory`; on v0.26.0, also patch legacy `FusedMoE`. | Both lanes need the Ascend runner patch at the correct binding. | ##### 3. `vllm_ascend/models/deepseek_v4.py` / `vllm_ascend/models/minimax_m3/minimax_m3.py` / `vllm_ascend/ops/fused_moe/fused_moe.py` / `vllm_ascend/ops/fused_moe/routed_experts.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Import and use `FusedMoEFactory`; remove dead `FusedMoE` re-export | [vllm #44941](vllm-project/vllm#44941). | Replace `FusedMoE` with `FusedMoEFactory`. | Old symbol no longer exists on main. Remove stale `FusedMoE` re-export from `fused_moe.py` and dead reference in `routed_experts.py` comment. | ##### 4. `tests/ut/models/test_deepseek_v4_moe.py` / `tests/ut/models/minimax_m3/test_minimax_m3.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Update monkeypatch target to `FusedMoEFactory` | [vllm #44941](vllm-project/vllm#44941). | `"FusedMoE"` → `"FusedMoEFactory"`. | Must match the symbol imported by models. | ##### 5. `vllm_ascend/worker/model_runner_v1.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate `calculate_kv_scales` removal | [vllm #49389](vllm-project/vllm#49389) removed runtime KV-scale calculation. | Add `vllm_version_is("0.26.0")` guard. | Ascend MRV1 still supports it on v0.26.0; attribute absent on main. | | Version-gate `clear_buffer()` removal | [vllm #50721](vllm-project/vllm#50721) removed `clear_buffer()` from `RoutedExpertsCapturer`. | Wrap in `vllm_version_is("0.26.0")` guard. | On main, each routed layer overwrites current step's token rows. | ##### 6. `vllm_ascend/models/layer/attention/layer.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Remove dead `Q/K/V_SCALE_CONSTANT` references | [vllm #49389](vllm-project/vllm#49389) removed env var registrations. Module-level constants still exist. | Remove unused `q_range`/`k_range`/`v_range` initializations and dead `import envs`. | Dead-code cleanup; `DSAAttention.forward()` never used these attributes. | ##### 7. `tests/ut/patch/platform/test_deepseek_v4_thinking.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate reasoning effort expectations | [vllm #50580](vllm-project/vllm#50580) maps `low`/`minimal`/`medium` → `low`. | `vllm_version_is("0.26.0")` guard. | v0.26.0 keeps old mapping; main uses new. | ##### 8. `tests/e2e/pull_request/one_card/spec_decode/test_extract_hidden_states.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Enable `chunked_prefill` for hybrid model | [vllm #50991](vllm-project/vllm#50991) enabled prefix cache by default for Mamba/hybrid models. | `False` → `True`. | Hybrid model now requires chunked prefill. | ##### 9. `vllm_ascend/patch/platform/patch_vision.py` (new) + `vllm_ascend/patch/platform/__init__.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Patch `FusedInputNorm.forward` eps=0.0 → eps=1e-5 | [vllm #50411](vllm-project/vllm#50411) added `FusedInputNorm` with `F.batch_norm(eps=0.0)`. | Monkey-patch forward to use `eps=1e-5`; guarded with `contextlib.suppress(ImportError)`. | Upstream PyTorch 2.13.0 allows eps >= 0 for inference; vllm-ascend PyTorch 2.10.0 requires eps > 0 always. Release wheels lack `FusedInputNorm`. Remove this patch once bundled PyTorch >= 2.13.0. | ##### 10. `vllm_ascend/ops/triton/mamba/postprocess.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Add kernel signature parameters | [vllm #50432](vllm-project/vllm#50432) changed signature. | Add `CONV_STATE_DIM_FIRST`, `HAS_IDX_MAPPING`, `PRECOMPUTED_NEW_COMPUTED`, `state_dim_row_count/stride`, `idx_mapping_ptr` parameters, and `num_loops` for DS conv copy. | Must match upstream kernel contract. | ##### 11. `tests/e2e/conftest.py` / `tests/ut/spec_decode/test_speculators_vwn_eagle3.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | HunyuanVL placeholder version gate; remove unused `maybe_calc_kv_scales` mock | [vllm #49691](vllm-project/vllm#49691), #49389. | Version gate and dead-mock removal. | Adapt to upstream contract changes. | ##### 12. `vllm_ascend/patch/__init__.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Document FusedMoE → FusedMoEFactory rename and new patch_vision entry | — | Update patch registry documentation. | Keep the patch manifest in sync with reality. | #### Compatibility and review notes - Version gates use `vllm_version_is("0.26.0")` exclusively; no `hasattr` fallbacks beyond the explicitly justified `clear_buffer` guard (where the upstream change is a method removal, not a rename). - The `FusedMoE` → `FusedMoEFactory` rename is applied consistently across all call sites: `deepseek_v4.py`, `minimax_m3.py`, `fused_moe.py`, `routed_experts.py`, and `patch_fused_moe.py`. - The `layer.py` `Q/K/V_SCALE_CONSTANT` removal is a dead-code cleanup: the `DSAAttention` class initialized these tensors from `envs` module-level constants (which still exist), but never used them in `forward()`. ### Does this PR introduce _any_ user-facing change? No. This is a compatibility update; no new Ascend-specific public API is introduced. ### How was this patch tested? CI on the branch. See Buildkite workflow run for detailed results. - vLLM version: v0.26.0 - vLLM main: vllm-project/vllm@0351e9a --------- Signed-off-by: liaoqidan <1107297340@qq.com>
### What this PR does / why we need it? #### Upgrade baseline - Update the verified vLLM main anchor from [`2e09247c2d7b6b97d13af6e71a85bf8d1271deb6`](vllm-project/vllm@2e09247) to [`58d3918e3ea0a544ffedadad2ba84559e9c51d8f`](vllm-project/vllm@58d3918). The full upstream range is available in this [comparison](vllm-project/vllm@2e09247...58d3918). - Preserve the vLLM `0.26.0` compatibility lane while adapting the main lane to the new upstream contracts. Version gates use `vllm_version_is("0.26.0")` and are limited to real contract differences. - The changes are organized in the same order as the changed files in this PR. Each item identifies the upstream change, the downstream adaptation, and why the adaptation is required. #### Changes by file ##### 1. `.github/vllm-main-verified.commit` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Update anchor to `58d3918e` | Upgrade window [0351e9aa...58d3918e](vllm-project/vllm@0351e9a...58d3918). | Set anchor. | Source of truth for main2main workflow. | ##### 2. `vllm_ascend/patch/platform/patch_fused_moe.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate FusedMoE → FusedMoEFactory rename | [vllm #44941](vllm-project/vllm#44941) renamed `FusedMoE` to `FusedMoEFactory`. | On main, capture and patch `FusedMoEFactory`; on v0.26.0, also patch legacy `FusedMoE`. | Both lanes need the Ascend runner patch at the correct binding. | ##### 3. `vllm_ascend/models/deepseek_v4.py` / `vllm_ascend/models/minimax_m3/minimax_m3.py` / `vllm_ascend/ops/fused_moe/fused_moe.py` / `vllm_ascend/ops/fused_moe/routed_experts.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Import and use `FusedMoEFactory`; remove dead `FusedMoE` re-export | [vllm #44941](vllm-project/vllm#44941). | Replace `FusedMoE` with `FusedMoEFactory`. | Old symbol no longer exists on main. Remove stale `FusedMoE` re-export from `fused_moe.py` and dead reference in `routed_experts.py` comment. | ##### 4. `tests/ut/models/test_deepseek_v4_moe.py` / `tests/ut/models/minimax_m3/test_minimax_m3.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Update monkeypatch target to `FusedMoEFactory` | [vllm #44941](vllm-project/vllm#44941). | `"FusedMoE"` → `"FusedMoEFactory"`. | Must match the symbol imported by models. | ##### 5. `vllm_ascend/worker/model_runner_v1.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate `calculate_kv_scales` removal | [vllm #49389](vllm-project/vllm#49389) removed runtime KV-scale calculation. | Add `vllm_version_is("0.26.0")` guard. | Ascend MRV1 still supports it on v0.26.0; attribute absent on main. | | Version-gate `clear_buffer()` removal | [vllm #50721](vllm-project/vllm#50721) removed `clear_buffer()` from `RoutedExpertsCapturer`. | Wrap in `vllm_version_is("0.26.0")` guard. | On main, each routed layer overwrites current step's token rows. | ##### 6. `vllm_ascend/models/layer/attention/layer.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Remove dead `Q/K/V_SCALE_CONSTANT` references | [vllm #49389](vllm-project/vllm#49389) removed env var registrations. Module-level constants still exist. | Remove unused `q_range`/`k_range`/`v_range` initializations and dead `import envs`. | Dead-code cleanup; `DSAAttention.forward()` never used these attributes. | ##### 7. `tests/ut/patch/platform/test_deepseek_v4_thinking.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Version-gate reasoning effort expectations | [vllm #50580](vllm-project/vllm#50580) maps `low`/`minimal`/`medium` → `low`. | `vllm_version_is("0.26.0")` guard. | v0.26.0 keeps old mapping; main uses new. | ##### 8. `tests/e2e/pull_request/one_card/spec_decode/test_extract_hidden_states.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Enable `chunked_prefill` for hybrid model | [vllm #50991](vllm-project/vllm#50991) enabled prefix cache by default for Mamba/hybrid models. | `False` → `True`. | Hybrid model now requires chunked prefill. | ##### 9. `vllm_ascend/patch/platform/patch_vision.py` (new) + `vllm_ascend/patch/platform/__init__.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Patch `FusedInputNorm.forward` eps=0.0 → eps=1e-5 | [vllm #50411](vllm-project/vllm#50411) added `FusedInputNorm` with `F.batch_norm(eps=0.0)`. | Monkey-patch forward to use `eps=1e-5`; guarded with `contextlib.suppress(ImportError)`. | Upstream PyTorch 2.13.0 allows eps >= 0 for inference; vllm-ascend PyTorch 2.10.0 requires eps > 0 always. Release wheels lack `FusedInputNorm`. Remove this patch once bundled PyTorch >= 2.13.0. | ##### 10. `vllm_ascend/ops/triton/mamba/postprocess.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Add kernel signature parameters | [vllm #50432](vllm-project/vllm#50432) changed signature. | Add `CONV_STATE_DIM_FIRST`, `HAS_IDX_MAPPING`, `PRECOMPUTED_NEW_COMPUTED`, `state_dim_row_count/stride`, `idx_mapping_ptr` parameters, and `num_loops` for DS conv copy. | Must match upstream kernel contract. | ##### 11. `tests/e2e/conftest.py` / `tests/ut/spec_decode/test_speculators_vwn_eagle3.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | HunyuanVL placeholder version gate; remove unused `maybe_calc_kv_scales` mock | [vllm #49691](vllm-project/vllm#49691), #49389. | Version gate and dead-mock removal. | Adapt to upstream contract changes. | ##### 12. `vllm_ascend/patch/__init__.py` | Change | Upstream change | Downstream adaptation | Why | |---|---|---|---| | Document FusedMoE → FusedMoEFactory rename and new patch_vision entry | — | Update patch registry documentation. | Keep the patch manifest in sync with reality. | #### Compatibility and review notes - Version gates use `vllm_version_is("0.26.0")` exclusively; no `hasattr` fallbacks beyond the explicitly justified `clear_buffer` guard (where the upstream change is a method removal, not a rename). - The `FusedMoE` → `FusedMoEFactory` rename is applied consistently across all call sites: `deepseek_v4.py`, `minimax_m3.py`, `fused_moe.py`, `routed_experts.py`, and `patch_fused_moe.py`. - The `layer.py` `Q/K/V_SCALE_CONSTANT` removal is a dead-code cleanup: the `DSAAttention` class initialized these tensors from `envs` module-level constants (which still exist), but never used them in `forward()`. ### Does this PR introduce _any_ user-facing change? No. This is a compatibility update; no new Ascend-specific public API is introduced. ### How was this patch tested? CI on the branch. See Buildkite workflow run for detailed results. - vLLM version: v0.26.0 - vLLM main: vllm-project/vllm@0351e9a --------- Signed-off-by: liaoqidan <1107297340@qq.com>
- Remove the second per-step DP dispatch all-reduce for dense Domino drafts while publishing a DP-shaped token-count tensor for the draft forward. - Zero dummy block-table rows and moved rows, and restage FULL dummy metadata, so idle DP dummies cannot write Mamba/GDN state through stale freed blocks (vLLM vllm-project#49757). - Backport the MRV2 Mamba num_accepted_tokens snapshot and scalar-fill fixes (vLLM vllm-project#50432, vllm-project#50327, vllm-project#49736). - Generalize KV block zeroing to all AttentionSpec groups (vLLM vllm-project#51749).
Purpose
PR #42406 introduced the support of aligned prefix cache in MRv2 by reusing the
postprocess_mamba_fused_alignkernels developed for MRv1. However there is a race condition that needs to be fixed.run_fused_postprocess_align(the MRv2 align-mode postprocess path) passesnum_accepted_tokens_gpuas both thepostprocess_mamba_fused_alignkernel's read source (num_accepted = tl.load(num_accepted_tokens_ptr + req_idx)at the top of every program) and the in-place write target (tl.store(num_accepted_tokens_ptr + req_idx, 1).Programs are launched with grid
(num_reqs, num_layers * num_state_types).For a given
req_idx, onlystate_idx == 0performs the store, but every otherstate_idxfor the samereq_idxreads the same address.Under
PRECOMPUTED_NEW_COMPUTED:So different layers can compute different
accept_token_biasvalues — some perform the state copy, some hit theaccept_token_bias == 0early return — leaving the mamba state inconsistent across layers.The correctness of current code depends on GPU launch timing/ number of SMs/ number of hybrid layers rather than the memory model.
The race is visible when
Every program loads
num_acceptedin its first few instructions, whilestate_idx == 0's store happens only after several loads, arithmetic, and copy. When all programs for a givenreq_idxland in the same wave they all complete their load before the store can land, so every program sees the original value. If there are multiple waves, a later-wave can observe the (1) and computeaccept_token_bias == 0, while an earlier-wave program already committed to a copy with the originalnum_accepted > 1. The two disagree, leaving the mamba state inconsistent across layers.The fix: In this PR we apply the same pattern MRv1 already used: write to a distinct
num_accepted_tokens_outbuffer, then copy back intonum_accepted_tokens_gpuafter the kernel finishes (both operations are enqueued on the same stream, so the copy is strictly ordered after all programs complete). The kernel branch onHAS_IDX_MAPPINGfor the store is removed. It now unconditionally targetsnum_accepted_tokens_out_ptr. Read buffer and write buffer are now disjoint, so no cross-program race.The difference with MRv1 is that we need to copy the entire tensor (of size
max_num_reqsofint32) as the requests are not contiguous. However the copy size is negligible ( 512 bytes for the default 128 requests)Claude discovered the race.
Test Plan
Test Result
The MRv2 tests are passing.
Essential Elements of an Effective PR Description Checklist
supported_models.mdandexamplesfor a new model.