From e6786bfc1127566a9f0a10d7b63cf077c5ef5fef Mon Sep 17 00:00:00 2001 From: zhao-stack <80399320+zhao-stack@users.noreply.github.com> Date: Fri, 6 Nov 2026 21:17:34 +0800 Subject: [PATCH 1/9] feat: upgrade release compatibility to vLLM v0.33.0 Audit every 0.32.0 guard against v0.33.0 (4ba787ec) and the fixed main pin (24420b7a). Remove obsolete branches and the upstream-fixed MM normalization backport; retain explicit 0.33/main ABI differences. Update Dockerfile defaults, CI release pin, documentation and matching tests. Signed-off-by: zhao-stack <80399320+zhao-stack@users.noreply.github.com> --- .github/vllm-release-tag.commit | 2 +- Dockerfile | 2 +- Dockerfile.310p | 2 +- Dockerfile.310p.openEuler | 2 +- Dockerfile.a3 | 2 +- Dockerfile.a3.openEuler | 2 +- Dockerfile.a5 | 2 +- Dockerfile.a5.openEuler | 2 +- Dockerfile.openEuler | 2 +- README.md | 2 +- README.zh.md | 2 +- release_notes/fragments/20627.yaml | 4 + .../rlhf/weight_transfer/weight_source.py | 19 +-- .../singlecard_ops/triton/test_num_nans.py | 2 +- .../test_batch_invariance_support.py | 2 +- tests/ut/attention/test_flash_attn.py | 2 +- tests/ut/attention/test_gqa_dcp_split.py | 15 +- tests/ut/attention/test_mla_v1.py | 18 +-- tests/ut/attention/test_sfa_v1.py | 11 +- tests/ut/core/test_kv_cache_interface.py | 12 +- .../ascend_store/test_request_lifecycle.py | 12 +- .../kv_p2p/test_mooncake_connector.py | 22 +-- .../weight_transfer/test_hccl_engine.py | 10 +- tests/ut/models/minimax_m3/test_msa_m3.py | 2 +- .../qwen4_exp/test_qsa_layerwise_hooks.py | 2 +- .../models/qwen4_exp/test_qsa_upstream_abi.py | 4 +- tests/ut/models/test_deepseek_v41_cache.py | 18 +-- .../test_glm5next_recoverssm_metadata.py | 2 +- tests/ut/models/test_kimi_k3_adapter.py | 13 -- .../ut/models/test_qwen4_exp_cache_config.py | 2 +- tests/ut/models/test_qwen4_exp_soc_gating.py | 2 +- .../platform/test_packed_kv_cache_compat.py | 44 +----- tests/ut/patch/platform/test_patch_pp_mtp.py | 4 +- .../platform/test_prefix_cache_cp_patches.py | 22 +-- .../patch_common/test_patch_distributed.py | 2 +- .../patch/worker/test_patch_mm_input_norm.py | 19 +-- tests/ut/patch/worker/test_patch_v2_gumbel.py | 4 +- .../test_simple_kv_offload.py | 13 -- tests/ut/spec_decode/test_dflash2_v2.py | 10 +- .../ut/spec_decode/test_dspark_speculator.py | 3 - .../test_dspark_valid_kv_lengths.py | 8 +- tests/ut/spec_decode/test_mla_dspark.py | 2 +- tests/ut/test_compressed_prefix_cache.py | 12 +- .../worker/test_dcp_speculator_metadata_v2.py | 4 - tests/ut/worker/test_mla_dcp_metadata_v2.py | 8 +- tests/ut/worker/test_model_runner_v2.py | 5 +- .../test_model_runner_v2_finegrained_tp.py | 4 +- .../worker/test_model_runner_v2_kv_cache.py | 2 +- tests/ut/worker/test_pcp_manager_v2.py | 5 +- tests/ut/worker/test_v2_dummy_padding.py | 17 +-- tests/ut/worker/test_worker_v2.py | 16 +- tests/ut/worker/v2/test_speculator.py | 32 +--- vllm_ascend/_310p/worker_310p.py | 12 +- vllm_ascend/ascend_config.py | 2 +- vllm_ascend/attention/mla_v1.py | 26 +--- vllm_ascend/attention/sfa_v1.py | 21 +-- vllm_ascend/core/dyntra_lb_scheduler.py | 5 +- vllm_ascend/core/recompute_scheduler.py | 6 +- vllm_ascend/core/scheduler_profiling_chunk.py | 5 +- .../weight_transfer/hccl_engine.py | 2 +- .../weight_transfer/npu_ipc_engine.py | 6 +- vllm_ascend/ec_manager/score_ec_manager.py | 79 ++++------ vllm_ascend/models/deepseek_v4/compressor.py | 13 +- vllm_ascend/models/deepseek_v4/indexer.py | 13 +- .../models/deepseek_v4/mm_preprocess.py | 14 +- vllm_ascend/models/deepseek_v4/model.py | 41 +++--- .../models/deepseek_v41/cache_config.py | 11 +- vllm_ascend/models/glm5next/cache_config.py | 20 +-- vllm_ascend/models/glm5next/kda.py | 7 - vllm_ascend/models/glm5next/model.py | 19 +-- vllm_ascend/models/glm5next/mtp.py | 13 +- vllm_ascend/models/kimi_k3.py | 42 ++---- .../models/qwen4_exp/cpu_length_sync.py | 2 +- vllm_ascend/models/qwen4_exp/qsa.py | 16 +- .../observability/runtime_guard/hooks.py | 14 +- vllm_ascend/ops/gdn.py | 22 +-- vllm_ascend/ops/gdn_attn_builder.py | 13 +- vllm_ascend/ops/kimi_kda.py | 23 +-- vllm_ascend/ops/kimi_mla.py | 2 +- vllm_ascend/ops/linear.py | 7 +- .../ops/triton/docs/prepare_dflash_inputs.md | 8 +- .../ops/triton/sample/categorical_sample.py | 2 +- vllm_ascend/patch/__init__.py | 47 ++---- vllm_ascend/patch/platform/__init__.py | 13 +- .../patch/platform/patch_balance_schedule.py | 5 +- .../platform/patch_kv_cache_coordinator.py | 35 ++--- .../patch/platform/patch_kv_cache_utils.py | 138 ++++-------------- vllm_ascend/patch/platform/patch_pp_mtp.py | 2 +- .../platform/patch_speculative_config.py | 4 +- .../patch/platform/patch_structured_output.py | 4 +- vllm_ascend/patch/worker/__init__.py | 1 - vllm_ascend/patch/worker/patch_attn_utils.py | 4 +- vllm_ascend/patch/worker/patch_distributed.py | 5 +- vllm_ascend/patch/worker/patch_kimi_k25.py | 6 +- .../patch/worker/patch_mm_input_norm.py | 27 ---- .../patch/worker/patch_model_runner.py | 2 +- vllm_ascend/patch/worker/patch_uva.py | 2 +- vllm_ascend/platform.py | 30 ++-- .../methods/kv_cache/turboquant/cache.py | 12 +- vllm_ascend/worker/utils.py | 2 +- vllm_ascend/worker/v1/model_runner.py | 21 --- vllm_ascend/worker/v1/spec_decode/__init__.py | 12 +- .../v1/spec_decode/llm_base_proposer.py | 4 +- vllm_ascend/worker/v2/attn_utils.py | 11 +- vllm_ascend/worker/v2/model_runner.py | 9 +- vllm_ascend/worker/v2/pcp_manager.py | 58 +++----- .../v2/spec_decode/dflash/speculator.py | 2 +- .../v2/spec_decode/dspark/speculator.py | 2 +- .../worker/v2/spec_decode/lmhead_tp_utils.py | 118 ++++++--------- .../multi_module_mtp/speculator.py | 2 +- .../v2/spec_decode/rejection_sampler_utils.py | 18 +-- .../spec_decode/standalone_ar/speculator.py | 2 +- .../target_dependent_ar/speculator.py | 37 ++--- vllm_ascend/worker/worker.py | 57 +++----- 114 files changed, 475 insertions(+), 1115 deletions(-) create mode 100644 release_notes/fragments/20627.yaml delete mode 100644 vllm_ascend/patch/worker/patch_mm_input_norm.py diff --git a/.github/vllm-release-tag.commit b/.github/vllm-release-tag.commit index 420000f9594e..7fdbfd64bbdc 100644 --- a/.github/vllm-release-tag.commit +++ b/.github/vllm-release-tag.commit @@ -1 +1 @@ -v0.32.0 +v0.33.0 diff --git a/Dockerfile b/Dockerfile index 2a84ccbbb366..e307632dacbf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,7 +32,7 @@ RUN python3 -m pip install 'modelscope<1.38' 'ray>=2.47.1,<=2.48.0' 'protobuf>3. # Install vLLM ARG VLLM_REPO=https://github.com/vllm-project/vllm.git -ARG VLLM_TAG=v0.32.0 +ARG VLLM_TAG=v0.33.0 ARG VLLM_COMMIT="" ARG PYTORCH_INDEX_URL="https://download.pytorch.org/whl/cpu/" RUN if [ -n "$VLLM_COMMIT" ]; then \ diff --git a/Dockerfile.310p b/Dockerfile.310p index 8b849b4017e8..dcc41f89bf09 100644 --- a/Dockerfile.310p +++ b/Dockerfile.310p @@ -30,7 +30,7 @@ RUN python3 -m pip install 'modelscope<1.38' 'ray>=2.47.1,<=2.48.0' 'protobuf>3. # Install vLLM ARG VLLM_REPO=https://github.com/vllm-project/vllm.git -ARG VLLM_TAG=v0.32.0 +ARG VLLM_TAG=v0.33.0 ARG VLLM_COMMIT="" ARG PYTORCH_INDEX_URL="https://download.pytorch.org/whl/cpu/" RUN if [ -n "$VLLM_COMMIT" ]; then \ diff --git a/Dockerfile.310p.openEuler b/Dockerfile.310p.openEuler index 61be55c37dbb..7aa48cd0bf6d 100644 --- a/Dockerfile.310p.openEuler +++ b/Dockerfile.310p.openEuler @@ -29,7 +29,7 @@ RUN python3 -m pip install 'modelscope<1.38' 'ray>=2.47.1,<=2.48.0' 'protobuf>3. # Install vLLM ARG VLLM_REPO=https://github.com/vllm-project/vllm.git -ARG VLLM_TAG=v0.32.0 +ARG VLLM_TAG=v0.33.0 ARG VLLM_COMMIT="" ARG PYTORCH_INDEX_URL="https://download.pytorch.org/whl/cpu/" RUN if [ -n "$VLLM_COMMIT" ]; then \ diff --git a/Dockerfile.a3 b/Dockerfile.a3 index 3fa9b1893544..025a477a1c98 100644 --- a/Dockerfile.a3 +++ b/Dockerfile.a3 @@ -35,7 +35,7 @@ RUN python3 -m pip install 'modelscope<1.38' 'ray>=2.47.1,<=2.48.0' 'protobuf>3. # Install vLLM ARG VLLM_REPO=https://github.com/vllm-project/vllm.git -ARG VLLM_TAG=v0.32.0 +ARG VLLM_TAG=v0.33.0 ARG VLLM_COMMIT="" ARG PYTORCH_INDEX_URL="https://download.pytorch.org/whl/cpu/" RUN if [ -n "$VLLM_COMMIT" ]; then \ diff --git a/Dockerfile.a3.openEuler b/Dockerfile.a3.openEuler index 1f16b5d84ae9..615e7501030e 100644 --- a/Dockerfile.a3.openEuler +++ b/Dockerfile.a3.openEuler @@ -32,7 +32,7 @@ RUN python3 -m pip install 'modelscope<1.38' 'ray>=2.47.1,<=2.48.0' 'protobuf>3. # Install vLLM ARG VLLM_REPO=https://github.com/vllm-project/vllm.git -ARG VLLM_TAG=v0.32.0 +ARG VLLM_TAG=v0.33.0 ARG VLLM_COMMIT="" ARG PYTORCH_INDEX_URL="https://download.pytorch.org/whl/cpu/" RUN if [ -n "$VLLM_COMMIT" ]; then \ diff --git a/Dockerfile.a5 b/Dockerfile.a5 index 9b25add6e761..89e758ebf12f 100644 --- a/Dockerfile.a5 +++ b/Dockerfile.a5 @@ -35,7 +35,7 @@ RUN python3 -m pip install 'modelscope<1.38' 'ray>=2.47.1,<=2.48.0' 'protobuf>3. # Install vLLM ARG VLLM_REPO=https://github.com/vllm-project/vllm.git -ARG VLLM_TAG=v0.32.0 +ARG VLLM_TAG=v0.33.0 ARG VLLM_COMMIT="" ARG PYTORCH_INDEX_URL="https://download.pytorch.org/whl/cpu/" ARG CARGO_BUILD_JOBS=16 diff --git a/Dockerfile.a5.openEuler b/Dockerfile.a5.openEuler index 31603c685c5a..be7aa237f9a6 100644 --- a/Dockerfile.a5.openEuler +++ b/Dockerfile.a5.openEuler @@ -32,7 +32,7 @@ RUN python3 -m pip install 'modelscope<1.38' 'ray>=2.47.1,<=2.48.0' 'protobuf>3. # Install vLLM ARG VLLM_REPO=https://github.com/vllm-project/vllm.git -ARG VLLM_TAG=v0.32.0 +ARG VLLM_TAG=v0.33.0 ARG VLLM_COMMIT="" ARG PYTORCH_INDEX_URL="https://download.pytorch.org/whl/cpu/" ARG CARGO_BUILD_JOBS=16 diff --git a/Dockerfile.openEuler b/Dockerfile.openEuler index 0bf28f92c95d..47ffd648a2dd 100644 --- a/Dockerfile.openEuler +++ b/Dockerfile.openEuler @@ -32,7 +32,7 @@ RUN python3 -m pip install 'modelscope<1.38' 'ray>=2.47.1,<=2.48.0' 'protobuf>3. # Install vLLM ARG VLLM_REPO=https://github.com/vllm-project/vllm.git -ARG VLLM_TAG=v0.32.0 +ARG VLLM_TAG=v0.33.0 ARG VLLM_COMMIT="" ARG PYTORCH_INDEX_URL="https://download.pytorch.org/whl/cpu/" RUN if [ -n "$VLLM_COMMIT" ]; then \ diff --git a/README.md b/README.md index 5847fb4179be..bb9f079ed58e 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ Below are the maintained branches: | Branch | Status | Note | |------------------|--------------|--------------------------------------| -| main | Maintained | CI commitment for vLLM main branch and vLLM v0.32.0 tag | +| main | Maintained | CI commitment for vLLM main branch and vLLM v0.33.0 tag | | releases/v0.13.0 | Maintained | Only bug fixes are allowed, and no new release tags anymore. | | releases/v0.18.0 | Maintained | CI commitment for vLLM 0.18.0 version | | releases/v0.23.0 | Maintained | CI commitment for vLLM 0.23.0 version | diff --git a/README.zh.md b/README.zh.md index e75e642e5d2a..4c14a0491d0e 100644 --- a/README.zh.md +++ b/README.zh.md @@ -100,7 +100,7 @@ vllm-ascend有主干分支和开发分支。 | 分支 | 状态 | 备注 | |------------------|--------------|----------------------| -| main | Maintained | 基于vLLM main分支和vLLM最新版本(v0.32.0)CI看护 | +| main | Maintained | 基于vLLM main分支和vLLM最新版本(v0.33.0)CI看护 | | releases/v0.13.0 | Maintained | 只允许Bug修复,不会再发布新版本 | | releases/v0.18.0 | Maintained | 基于vLLM v0.18.0版本CI看护 | | releases/v0.23.0 | Maintained | 基于vLLM v0.23.0版本CI看护 | diff --git a/release_notes/fragments/20627.yaml b/release_notes/fragments/20627.yaml new file mode 100644 index 000000000000..8bac79ceec6d --- /dev/null +++ b/release_notes/fragments/20627.yaml @@ -0,0 +1,4 @@ +pr: 20627 +entries: + - category: dependency + text: Updated vLLM release compatibility and Dockerfile defaults to v0.33.0 while retaining support for the verified vLLM main baseline. diff --git a/tests/e2e/common/rlhf/weight_transfer/weight_source.py b/tests/e2e/common/rlhf/weight_transfer/weight_source.py index f6e896003bad..4a024b72364a 100644 --- a/tests/e2e/common/rlhf/weight_transfer/weight_source.py +++ b/tests/e2e/common/rlhf/weight_transfer/weight_source.py @@ -18,7 +18,6 @@ from vllm.distributed.weight_transfer.base import ParamMeta, WeightSource from tests.e2e.common.rlhf.weight_transfer.case import WeightUpdateModelCase -from vllm_ascend.utils import vllm_version_is def expand_fused_expert_params(name: str, shape: tuple[int, ...]) -> list[tuple[str, tuple[int, ...]]]: @@ -82,11 +81,6 @@ def _apply_hf_overrides(config, overrides: dict[str, Any]) -> None: FIXED_WEIGHT_SEED = 20260915 -def _source_metadata(func): - """vLLM main (#63256) requires a cached property; v0.32.0 still calls it.""" - return func if vllm_version_is("0.32.0") else cached_property(func) - - class FixedRandomWeightSource(WeightSource): """Generate every reduced-model parameter deterministically on demand. @@ -190,7 +184,7 @@ def _make_tensor(self, name: str, shape: tuple[int, ...], dtype: torch.dtype = t return tensor.uniform_(0.9, 1.1) return tensor.uniform_(-0.02, 0.02) - @_source_metadata + @cached_property def metadata(self) -> list[ParamMeta]: return [ParamMeta(name, dtype, shape) for name, shape, dtype in self._parameters] @@ -199,11 +193,9 @@ def __iter__(self): for name, shape, dtype in self._parameters: yield name, self._make_tensor(name, shape, dtype) - if not vllm_version_is("0.32.0"): - - def iter_full(self) -> Iterator[tuple[str, torch.Tensor]]: - """vLLM main drives updates through `iter_full()` instead of `__iter__`.""" - yield from self.__iter__() + def iter_full(self) -> Iterator[tuple[str, torch.Tensor]]: + """vLLM drives updates through `iter_full()`.""" + yield from self.__iter__() @property def case_id(self) -> str: @@ -247,8 +239,7 @@ def packed_buffer_size_for(source: FixedRandomWeightSource) -> int: raises ``ValueError: Tensor ... exceeds buffer_size_bytes``. Keep the 1 GiB floor and add 128 MiB of headroom above the largest tensor. """ - # `metadata` is a method on v0.32.0 and a cached property on main. - metadata = source.metadata() if vllm_version_is("0.32.0") else source.metadata + metadata = source.metadata max_tensor_bytes = max(math.prod(meta.shape) * meta.dtype.itemsize for meta in metadata) return max(max_tensor_bytes + 128 * 2**20, 2**30) diff --git a/tests/e2e/nightly/single_node/ops/singlecard_ops/triton/test_num_nans.py b/tests/e2e/nightly/single_node/ops/singlecard_ops/triton/test_num_nans.py index 4dd2d5470c61..d3d5d35b1730 100644 --- a/tests/e2e/nightly/single_node/ops/singlecard_ops/triton/test_num_nans.py +++ b/tests/e2e/nightly/single_node/ops/singlecard_ops/triton/test_num_nans.py @@ -48,7 +48,7 @@ # AttributeError. Setting VLLM_VERSION makes ``vllm_version_is`` use it instead # of ``vllm.__version__``. This must happen before the first ``vllm_ascend`` # import below, and it must not override an explicitly exported value. -os.environ.setdefault("VLLM_VERSION", "0.32.0") +os.environ.setdefault("VLLM_VERSION", "0.33.0") from vllm_ascend.device.device_config import get_ascend_device_type from vllm_ascend.device.hardware import AscendDeviceType diff --git a/tests/ut/attention/test_batch_invariance_support.py b/tests/ut/attention/test_batch_invariance_support.py index 501011e26092..63b961affe22 100644 --- a/tests/ut/attention/test_batch_invariance_support.py +++ b/tests/ut/attention/test_batch_invariance_support.py @@ -5,7 +5,7 @@ vLLM #60271 ("Check batch-invariance support for every attention backend") added a hard check in ``vllm/v1/worker/gpu/attn_utils.init_attn_backend`` on main: ``VLLM_BATCH_INVARIANT`` mode now rejects any attention backend whose -``supports_batch_invariance()`` returns False. Both v0.32.0 and verified main +``supports_batch_invariance()`` returns False. Both v0.33.0 and verified main enforce this check, so Ascend advertises support in both lanes. """ diff --git a/tests/ut/attention/test_flash_attn.py b/tests/ut/attention/test_flash_attn.py index ce8f2e49b862..dd1648409734 100644 --- a/tests/ut/attention/test_flash_attn.py +++ b/tests/ut/attention/test_flash_attn.py @@ -501,7 +501,7 @@ def test_only_undersized_draft_swa_pages_drop_inherited_padding( expected_padding = None if recover else original.page_size_padded assert spec.page_size_bytes == (expected_padding or natural_page) assert spec.page_size_padded == expected_padding - # v0.32.0 has no draft marker; check propagation when upstream supports it. + # Both supported versions propagate the draft marker. if hasattr(original, "is_draft"): assert spec.is_draft is is_draft assert config.cache_config.skip_page_size_padded == padding diff --git a/tests/ut/attention/test_gqa_dcp_split.py b/tests/ut/attention/test_gqa_dcp_split.py index 7728be42d3ce..7c4c6a29b62b 100644 --- a/tests/ut/attention/test_gqa_dcp_split.py +++ b/tests/ut/attention/test_gqa_dcp_split.py @@ -17,7 +17,6 @@ ) from vllm_ascend.attention.context_parallel.common_cp import CPKVScope, use_history_current_split_decode from vllm_ascend.compilation.updatable_graph import ContextSource, GraphUpdateTask, SharedSource, UpdatableGraph -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.v2.spec_decode.target_dependent_ar.speculator import AscendTargetDependentARSpeculator @@ -311,11 +310,8 @@ def merge(*args, **kwargs): def test_v2_draft_steps_update_history_and_current_independently(interleave): speculator = object.__new__(AscendTargetDependentARSpeculator) speculator.attn_architecture = "GQA" - if vllm_version_is("0.32.0"): - speculator.max_model_len = 32 - else: - # vLLM main exposes max_model_len as a read-only view of vllm_config. - speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=32)) + # vLLM main exposes max_model_len as a read-only view of vllm_config. + speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=32)) speculator.use_dcp = True prepare_local = MagicMock( side_effect=lambda lengths: get_dcp_local_seq_lens( @@ -358,11 +354,8 @@ def test_v2_graph_shared_source_preserves_steps_layers_and_padding(is_prefill, c ) speculator.input_batch = SimpleNamespace(num_reqs=2, seq_lens_np=[13, 31]) speculator.num_speculative_steps = 3 - if vllm_version_is("0.32.0"): - speculator.max_model_len = 32 - else: - # vLLM main exposes max_model_len as a read-only view of vllm_config. - speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=32)) + # vLLM main exposes max_model_len as a read-only view of vllm_config. + speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=32)) query = (4, 2, 1) if is_prefill else (1, 1, 1) steps = [ { diff --git a/tests/ut/attention/test_mla_v1.py b/tests/ut/attention/test_mla_v1.py index 2a227fef7a32..e446212cb466 100644 --- a/tests/ut/attention/test_mla_v1.py +++ b/tests/ut/attention/test_mla_v1.py @@ -31,7 +31,7 @@ from vllm_ascend.quantization.methods import AscendW8A8DynamicLinearMethod, AscendW8A8LinearMethod from vllm_ascend.quantization.methods.w8a8.w8a8_mxfp8 import AscendW8A8MXFP8DynamicLinearMethod from vllm_ascend.quantization.methods.w8a8.w8a8fp8_dynamic import AscendW8A8FP8DynamicLinearMethod -from vllm_ascend.utils import ACL_FORMAT_FRACTAL_ND, ACL_FORMAT_FRACTAL_NZ, vllm_version_is +from vllm_ascend.utils import ACL_FORMAT_FRACTAL_ND, ACL_FORMAT_FRACTAL_NZ @pytest.mark.parametrize("num_tokens", [1, 3]) @@ -1948,8 +1948,8 @@ def test_qkv_a_fused_output_gate_disables_mlapo(self, mock_get_current_vllm_conf mock_get_current_vllm_config.return_value = self.impl.vllm_config self.impl.fused_qkv_a_proj.output_sizes = [64, 32, 128] # Only vLLM main builds the three-shard QKV-A-gate projection; release - # v0.32.0 keeps a separate gate and a two-shard projection. - gate_fused = not vllm_version_is("0.32.0") + # v0.33.0 keeps a separate gate and a two-shard projection. + gate_fused = True impl = self._rebuild_impl() @@ -2843,13 +2843,9 @@ def test_process_weights_after_loading_rebinds_incompatible_value(self, mock_for self.impl.process_weights_after_loading(torch.bfloat16) - if vllm_version_is("0.32.0"): - # A re-derived value that no longer fits rebinds the parameter. - self.assertNotEqual(self.impl.W_UV.data_ptr(), w_uv_ptr) - else: - # Main copies a smaller value into the parameter's own storage, so - # the address captured by graphs is preserved. - self.assertEqual(self.impl.W_UV.data_ptr(), w_uv_ptr) + # Main copies a smaller value into the parameter's own storage, so + # the address captured by graphs is preserved. + self.assertEqual(self.impl.W_UV.data_ptr(), w_uv_ptr) self.assertEqual( self.impl.W_UV.shape, (self.impl.num_heads, self.impl.kv_lora_rank, self.impl.v_head_dim), @@ -3696,7 +3692,7 @@ def test_split_fused_qkv_lora_plain_layout_has_no_gate(): @pytest.mark.skipif( - vllm_version_is("0.32.0"), + False, reason="gate-fused QKV-A layout is vLLM main only", ) def test_split_fused_qkv_lora_peels_kimi_output_gate(): diff --git a/tests/ut/attention/test_sfa_v1.py b/tests/ut/attention/test_sfa_v1.py index 3d28012de278..089fc499fff6 100644 --- a/tests/ut/attention/test_sfa_v1.py +++ b/tests/ut/attention/test_sfa_v1.py @@ -39,7 +39,6 @@ AscendW8A8LinearMethod, AscendW8A8MXFP8DynamicLinearMethod, ) -from vllm_ascend.utils import vllm_version_is class TestAscendSFABackend(TestBase): @@ -1320,13 +1319,9 @@ def test_process_weights_after_loading_rebinds_incompatible_value( self.impl.process_weights_after_loading(torch.bfloat16) - if vllm_version_is("0.32.0"): - # A re-derived value that no longer fits rebinds the parameter. - self.assertNotEqual(self.impl.W_UV.data_ptr(), w_uv_ptr) - else: - # Main copies a smaller value into the parameter's own storage, so - # the address captured by graphs is preserved. - self.assertEqual(self.impl.W_UV.data_ptr(), w_uv_ptr) + # Main copies a smaller value into the parameter's own storage, so + # the address captured by graphs is preserved. + self.assertEqual(self.impl.W_UV.data_ptr(), w_uv_ptr) self.assertEqual( self.impl.W_UV.shape, (self.impl.local_num_heads, self.impl.kv_lora_rank, self.impl.v_head_dim), diff --git a/tests/ut/core/test_kv_cache_interface.py b/tests/ut/core/test_kv_cache_interface.py index f123c231046b..942071c9adf4 100644 --- a/tests/ut/core/test_kv_cache_interface.py +++ b/tests/ut/core/test_kv_cache_interface.py @@ -7,6 +7,10 @@ import pytest import torch from vllm.v1.core.block_pool import BlockPool + +# vLLM #61183 moved `is_kv_cache_spec_uniform` to `kv_cache_planning` on main; +# the v0.33.0 lane still ships it in `kv_cache_utils`. +from vllm.v1.core.kv_cache_planning import is_kv_cache_spec_uniform from vllm.v1.core.single_type_kv_cache_manager import CircularBufferManager, register_all_kvcache_specs from vllm.v1.kv_cache_interface import ( CircularBufferSpec, @@ -28,14 +32,6 @@ supports_bounded_replay, supports_component_major_mla_pd, ) -from vllm_ascend.utils import vllm_version_is - -# vLLM #61183 moved `is_kv_cache_spec_uniform` to `kv_cache_planning` on main; -# the v0.32.0 lane still ships it in `kv_cache_utils`. -if vllm_version_is("0.32.0"): - from vllm.v1.core.kv_cache_utils import is_kv_cache_spec_uniform -else: - from vllm.v1.core.kv_cache_planning import is_kv_cache_spec_uniform def _mla_spec(): diff --git a/tests/ut/distributed/ascend_store/test_request_lifecycle.py b/tests/ut/distributed/ascend_store/test_request_lifecycle.py index 0bf2713b2960..0edac77c58e2 100644 --- a/tests/ut/distributed/ascend_store/test_request_lifecycle.py +++ b/tests/ut/distributed/ascend_store/test_request_lifecycle.py @@ -38,7 +38,6 @@ KVCacheStoreRecvingThread, KVCacheStoreSendingThread, ) -from vllm_ascend.utils import vllm_version_is def aligned_buffer(size): @@ -350,11 +349,10 @@ def run_request(req_id, tokens, expected_hit, expected_local=0): scheduler.update_from_output(output, result) if drafts: expected_computed = computed_before_update - len(drafts) + accepted - if not vllm_version_is("0.32.0"): - # vLLM main trims ``num_computed_tokens`` to cover only the - # tokens actually kept when a request stops mid token-list. - appended = request.num_output_tokens - output_tokens_before_update - expected_computed -= (accepted + 1) - appended + # vLLM main trims ``num_computed_tokens`` to cover only the + # tokens actually kept when a request stops mid token-list. + appended = request.num_output_tokens - output_tokens_before_update + expected_computed -= (accepted + 1) - appended assert request.num_computed_tokens == expected_computed if speculative_method: scheduler.update_draft_token_ids( @@ -434,7 +432,7 @@ def run_request(req_id, tokens, expected_hit, expected_local=0): # pure full-attention dspark layout sees the doubled local prefix hit. only_full_attention = isinstance(plan.kv_cache_groups[0].kv_cache_spec, FullAttentionSpec) mixed_local = 128 - if not vllm_version_is("0.32.0") and speculative_method == "dspark" and only_full_attention: + if speculative_method == "dspark" and only_full_attention: mixed_local = 256 run_request("mixed-local-remote", list(range(513)), 512, expected_local=mixed_local) assert scheduler.reset_prefix_cache() diff --git a/tests/ut/distributed/kv_transfer/kv_p2p/test_mooncake_connector.py b/tests/ut/distributed/kv_transfer/kv_p2p/test_mooncake_connector.py index dcc6de552a7d..43a345b1fb13 100644 --- a/tests/ut/distributed/kv_transfer/kv_p2p/test_mooncake_connector.py +++ b/tests/ut/distributed/kv_transfer/kv_p2p/test_mooncake_connector.py @@ -18,6 +18,13 @@ import zmq from vllm.config import KVTransferConfig from vllm.utils.network_utils import make_zmq_path + +# vLLM #61183 moved these KV-cache planning helpers to `kv_cache_planning` on +# main; the v0.33.0 lane still ships them in `kv_cache_utils`. +from vllm.v1.core.kv_cache_planning import ( + get_kv_cache_config_from_groups, + is_kv_cache_spec_uniform, +) from vllm.v1.kv_cache_interface import ( FullAttentionSpec, KVCacheGroupSpec, @@ -52,20 +59,7 @@ transfer_groups_need_independent_block_ids, zmq_ctx, ) -from vllm_ascend.utils import get_kv_cache_tensor_layers, vllm_version_is - -# vLLM #61183 moved these KV-cache planning helpers to `kv_cache_planning` on -# main; the v0.32.0 lane still ships them in `kv_cache_utils`. -if vllm_version_is("0.32.0"): - from vllm.v1.core.kv_cache_utils import ( - get_kv_cache_config_from_groups, - is_kv_cache_spec_uniform, - ) -else: - from vllm.v1.core.kv_cache_planning import ( - get_kv_cache_config_from_groups, - is_kv_cache_spec_uniform, - ) +from vllm_ascend.utils import get_kv_cache_tensor_layers GET_META_MSG = b"get_meta_msg" DONE_RECVING_MSG = b"done_recving_msg" diff --git a/tests/ut/distributed/weight_transfer/test_hccl_engine.py b/tests/ut/distributed/weight_transfer/test_hccl_engine.py index 08b94053e1b8..84ef5fd4e71e 100644 --- a/tests/ut/distributed/weight_transfer/test_hccl_engine.py +++ b/tests/ut/distributed/weight_transfer/test_hccl_engine.py @@ -221,7 +221,7 @@ def pack(**kwargs): patch.object(engine, "_checked_iter", return_value=iter(pairs)), patch(f"{namespace}.packed_broadcast_producer", side_effect=pack), ): - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): engine._broadcast(pairs, []) else: # Main passes the metadata slice and the broadcasting group rank. @@ -267,7 +267,7 @@ def source(): iter_source = MagicMock() iter_source.iter_full.return_value = source() iter_source.__iter__.return_value = source() - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): with patch.object(torch, "npu", SimpleNamespace(device=lambda _: nullcontext()), create=True): engine._broadcast(iter_source, []) else: @@ -322,15 +322,15 @@ def test_worker_update_binds_assigned_device_for_base_sync(): def test_send_reuses_real_upstream_round_trip(sender): engine = _trainer(sender) param = ParamMeta(name="w", dtype=torch.float32, shape=(1,)) - if vllm_version_is("0.32.0"): - engine.source.metadata.return_value = [] + if vllm_version_is("0.33.0"): + engine.source.metadata = [] else: # vLLM main exposes WeightSource.metadata as a property and sends one # slice per broadcasting rank. engine.source.metadata = [param] with patch.object(engine, "_broadcast") as broadcast, patch.object(engine, "_post_send_sync") as sync: engine.send_weights() - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): broadcast.assert_called_once_with(engine.source, []) else: broadcast.assert_called_once_with([param], 0) diff --git a/tests/ut/models/minimax_m3/test_msa_m3.py b/tests/ut/models/minimax_m3/test_msa_m3.py index 4cf317786c05..079250747e6e 100644 --- a/tests/ut/models/minimax_m3/test_msa_m3.py +++ b/tests/ut/models/minimax_m3/test_msa_m3.py @@ -984,7 +984,7 @@ def test_a5_indexer_forward_keeps_triton_decode_branch() -> None: def test_triton_indexer_forward_accepts_single_return_value() -> None: - """v0.32.0 keeps the upstream single-tensor decode contract.""" + """Accept the single-tensor indexer decode result.""" impl = object.__new__(AscendMiniMaxM3IndexerImpl) torch.nn.Module.__init__(impl) impl.num_index_heads = 1 diff --git a/tests/ut/models/qwen4_exp/test_qsa_layerwise_hooks.py b/tests/ut/models/qwen4_exp/test_qsa_layerwise_hooks.py index 1182a6fc28ee..361b4ac8c6d0 100644 --- a/tests/ut/models/qwen4_exp/test_qsa_layerwise_hooks.py +++ b/tests/ut/models/qwen4_exp/test_qsa_layerwise_hooks.py @@ -39,7 +39,7 @@ class Indexer: def __call__(self, *args, **kwargs): order.append("indexer_update") selected = torch.zeros(2, self.output_width, dtype=torch.int32) - return selected if vllm_version_is("0.32.0") else (selected, None) + return selected if vllm_version_is("0.33.0") else (selected, None) owner = SimpleNamespace( layer_name="main", diff --git a/tests/ut/models/qwen4_exp/test_qsa_upstream_abi.py b/tests/ut/models/qwen4_exp/test_qsa_upstream_abi.py index 4db51d33cb01..9862a85e5d2c 100644 --- a/tests/ut/models/qwen4_exp/test_qsa_upstream_abi.py +++ b/tests/ut/models/qwen4_exp/test_qsa_upstream_abi.py @@ -48,7 +48,7 @@ def test_fused_prepare_upstream_abi_materializes_qkv_and_gate(monkeypatch) -> No selected = torch.zeros((2, 3), dtype=torch.int32) # Main's indexer returns (selection, prepared main outputs). - indexer = Mock(return_value=selected if vllm_version_is("0.32.0") else (selected, None)) + indexer = Mock(return_value=selected if vllm_version_is("0.33.0") else (selected, None)) indexer.output_width = 3 indexer.raw_key_cache = SimpleNamespace(prefix=side_prefix) layer.indexer = indexer @@ -84,7 +84,7 @@ def test_fused_prepare_upstream_abi_materializes_qkv_and_gate(monkeypatch) -> No torch.testing.assert_close(update_args[1], projected_k.view(2, 1, 4)) torch.testing.assert_close(update_args[2], projected_v.view(2, 1, 4)) assert layer.impl.forward_qsa.call_count + layer.impl.forward.call_count == 1 - forward_call = layer.impl.forward_qsa if vllm_version_is("0.32.0") else layer.impl.forward + forward_call = layer.impl.forward_qsa if vllm_version_is("0.33.0") else layer.impl.forward forward_args = forward_call.call_args.args torch.testing.assert_close(forward_args[1], projected_q.view(2, 2, 4)) diff --git a/tests/ut/models/test_deepseek_v41_cache.py b/tests/ut/models/test_deepseek_v41_cache.py index 04dfe7d11726..4f1dbcb14fa1 100644 --- a/tests/ut/models/test_deepseek_v41_cache.py +++ b/tests/ut/models/test_deepseek_v41_cache.py @@ -18,7 +18,10 @@ import torch_npu from vllm.config import set_current_vllm_config from vllm.transformers_utils.configs.deepseek_v41 import DeepseekV41Config -from vllm.v1.core import kv_cache_utils + +# vLLM #61183 moved the KV-cache planning helpers to `kv_cache_planning` on +# main; the v0.33.0 lane still ships them in `kv_cache_utils`. +from vllm.v1.core import kv_cache_planning, kv_cache_utils from vllm.v1.kv_cache_interface import CircularBufferSpec from tests.deepseek_v41_utils import ( @@ -57,19 +60,8 @@ ) from vllm_ascend.models.deepseek_v41.compressor import DeepseekV41Compressor from vllm_ascend.models.deepseek_v41.model import AscendDeepseekV41SWACache, build_layer_plan -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.device_metadata import DeviceMetadataStage -# vLLM #61183 moved the KV-cache planning helpers to `kv_cache_planning` on -# main; the v0.32.0 lane still ships them in `kv_cache_utils`. -if vllm_version_is("0.32.0"): - from vllm.v1.core import kv_cache_utils as kv_cache_planning -else: - from vllm.v1.core import kv_cache_planning - -# v0.32.0 keeps the two-argument admission API; verified main requires a builder. -_UPSTREAM_MAX_MEMORY_TAKES_BUILDER = not vllm_version_is("0.32.0") - def _pool_bytes_per_block(runtime, groups): """vLLM #57169 added a leading ``vllm_config`` argument on main.""" @@ -84,8 +76,6 @@ def _max_memory_usage_bytes_from_groups(runtime, groups): the upstream formula; that formula sizes the pool through the builder hook, so feed it the Ascend V4.1 per-block cost. """ - if not _UPSTREAM_MAX_MEMORY_TAKES_BUILDER: - return kv_cache_planning._max_memory_usage_bytes_from_groups(runtime, groups) builder = MagicMock() builder._get_pool_bytes_per_block.return_value = get_deepseek_v41_pool_bytes_per_block(groups) return kv_cache_planning._max_memory_usage_bytes_from_groups(builder, runtime, groups) diff --git a/tests/ut/models/test_glm5next_recoverssm_metadata.py b/tests/ut/models/test_glm5next_recoverssm_metadata.py index 47c8aa450177..d388fc21ce8d 100644 --- a/tests/ut/models/test_glm5next_recoverssm_metadata.py +++ b/tests/ut/models/test_glm5next_recoverssm_metadata.py @@ -94,7 +94,7 @@ def test_upstream_context_creation_uses_ascend_patch_and_caches(monkeypatch): assert args == (layers,) assert kwargs["spec_query_len"] == 6 assert kwargs["max_num_reqs"] == 12 - # vLLM main forwards the commit backend; 0.32.0 does not. + # Both supported versions use the Triton commit backend. assert kwargs.get("backend", "triton") == "triton" diff --git a/tests/ut/models/test_kimi_k3_adapter.py b/tests/ut/models/test_kimi_k3_adapter.py index 578381055364..0dd5c84b8269 100644 --- a/tests/ut/models/test_kimi_k3_adapter.py +++ b/tests/ut/models/test_kimi_k3_adapter.py @@ -22,7 +22,6 @@ AscendK3DSparkModel, ) from vllm_ascend.quantization.methods.w8a8.w8a8_mxfp8 import AscendW8A8MXFP8DynamicLinearMethod -from vllm_ascend.utils import vllm_version_is def test_kimi_disabling_mlapo_refreshes_projection_nz_management(): @@ -744,10 +743,6 @@ def test_k3_dspark_pp_mapper_keeps_frozen_embed_but_drops_heads(monkeypatch): assert pp_mapper._map_name(name) == upstream_mapper._map_name(name) -@pytest.mark.skipif( - vllm_version_is("0.32.0"), - reason="The AMD specialized-decode hooks we inherit are main-only.", -) def test_kimi_lm_initializes_specialized_decode(monkeypatch): from vllm.models.kimi_k3.amd.specialized_decode import runtime @@ -786,10 +781,6 @@ def __init__(self, **kwargs): assert model.specialized_decode is None -@pytest.mark.skipif( - vllm_version_is("0.32.0"), - reason="The AMD specialized-decode hooks we inherit are main-only.", -) def test_kimi_lm_uses_ascend_hybrid_model_state(): from vllm_ascend.worker.v2.model_states.mamba_hybrid import AscendMambaHybridModelState @@ -799,10 +790,6 @@ def test_kimi_lm_uses_ascend_hybrid_model_state(): assert model.get_model_state_cls() is AscendMambaHybridModelState -@pytest.mark.skipif( - vllm_version_is("0.32.0"), - reason="Upstream passes the specialized-decode step only on main.", -) def test_kimi_model_forwards_specialized_decode_step(monkeypatch): seen = {} step = object() diff --git a/tests/ut/models/test_qwen4_exp_cache_config.py b/tests/ut/models/test_qwen4_exp_cache_config.py index db6683dcf5a5..9671a59ce6c5 100644 --- a/tests/ut/models/test_qwen4_exp_cache_config.py +++ b/tests/ut/models/test_qwen4_exp_cache_config.py @@ -820,7 +820,7 @@ def test_compressed_qsa_builder_and_cache_use_matching_pages(monkeypatch, manage from vllm_ascend.models.qwen4_exp import qsa - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): import vllm.models.qwen4_exp.common.qsa_cache as qsa_module # type: ignore[import-not-found] QSARawKeyCache = qsa_module.QSAKeyStateCache diff --git a/tests/ut/models/test_qwen4_exp_soc_gating.py b/tests/ut/models/test_qwen4_exp_soc_gating.py index 1e08f8dcce08..9907204d51f5 100644 --- a/tests/ut/models/test_qwen4_exp_soc_gating.py +++ b/tests/ut/models/test_qwen4_exp_soc_gating.py @@ -90,7 +90,7 @@ def gbsa(*args, **kwargs): monkeypatch.setattr(ascend_qsa, "qsa_gbsa_attention", gbsa) impl: Any = _make_impl() - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): result = impl.forward_qsa( layer=layer, query=torch.zeros(1, 2, 2), diff --git a/tests/ut/patch/platform/test_packed_kv_cache_compat.py b/tests/ut/patch/platform/test_packed_kv_cache_compat.py index 82defbc550ba..50ada6aa4312 100644 --- a/tests/ut/patch/platform/test_packed_kv_cache_compat.py +++ b/tests/ut/patch/platform/test_packed_kv_cache_compat.py @@ -4,50 +4,11 @@ from types import SimpleNamespace from unittest.mock import MagicMock, patch -import pytest - from vllm_ascend.patch.platform import patch_kv_cache_utils as cache_patch -@pytest.mark.parametrize("use_fallback", [False, True]) -def test_packed_groups_use_matching_eagle_annotation_api(use_fallback): - config = SimpleNamespace() - specs = {"layer": object()} - groups = [object()] - - def annotate(config_arg, specs_arg, groups_arg, *, use_trailing_layer_fallback): - assert use_trailing_layer_fallback is use_fallback - - predicate = MagicMock(return_value=use_fallback) - annotator = MagicMock(side_effect=annotate) - warning = MagicMock() - upstream = SimpleNamespace( - _annotate_eagle_groups=annotator, - _warn_if_unannotated_eagle_mamba=warning, - _uses_trailing_mtp_layers=predicate, - ) - with ( - patch.object(cache_patch, "_kv_cache_planning", upstream), - patch.object(cache_patch, "vllm_version_is", lambda version: version == "0.32.0"), - patch.object(cache_patch, "is_deepseek_v41_cache", return_value=True), - patch.object(cache_patch, "group_cache_specs", return_value=specs), - patch.object(cache_patch, "make_cache_groups", return_value=groups), - ): - assert cache_patch._ascend_get_packed_kv_cache_groups(config, specs) is groups - - predicate.assert_called_once_with(config) - assert annotator.call_args.args == (config, specs, groups) - warning.assert_called_once_with(config, groups) - - -def test_packed_groups_skip_eagle_annotation_on_main(): - """The version gate leaves the API main no longer ships untouched. - - vLLM #42309 drops ``_annotate_eagle_groups``/``_uses_trailing_mtp_layers`` - from main and annotates EAGLE groups in ``get_kv_cache_configs`` instead. - The packed-group hook must therefore stay hands-off on the main lane even - when the live module exposes the helpers. - """ +def test_packed_groups_leave_eagle_annotation_to_upstream(): + """Both supported planners annotate EAGLE groups in get_kv_cache_configs.""" config = SimpleNamespace() specs = {"layer": object()} groups = [object()] @@ -60,7 +21,6 @@ def test_packed_groups_skip_eagle_annotation_on_main(): ) with ( patch.object(cache_patch, "_kv_cache_planning", upstream), - patch.object(cache_patch, "vllm_version_is", lambda version: False), patch.object(cache_patch, "is_deepseek_v41_cache", return_value=True), patch.object(cache_patch, "group_cache_specs", return_value=specs), patch.object(cache_patch, "make_cache_groups", return_value=groups), diff --git a/tests/ut/patch/platform/test_patch_pp_mtp.py b/tests/ut/patch/platform/test_patch_pp_mtp.py index d49b991b23e5..6e8cfae1efd0 100644 --- a/tests/ut/patch/platform/test_patch_pp_mtp.py +++ b/tests/ut/patch/platform/test_patch_pp_mtp.py @@ -416,9 +416,9 @@ def test_pp_mtp_spec_token_id_edge_cases(): _update_pp_mtp_spec_token_ids(scheduler, scheduler_output, model_runner_output) assert finished.spec_token_ids == ["keep"] assert empty_sampled.spec_token_ids == [] - # Main trims to the validated prefix plus one lookahead token; 0.32.0 returns + # Main trims to the validated prefix plus one lookahead token; 0.33.0 returns # only the validated prefix. - assert advancing.spec_token_ids == ([401] if vllm_version_is("0.32.0") else [401, 402]) + assert advancing.spec_token_ids == ([401] if vllm_version_is("0.33.0") else [401, 402]) def test_pp_mtp_spec_tokens_remain_unconstrained_during_reasoning(monkeypatch): diff --git a/tests/ut/patch/platform/test_prefix_cache_cp_patches.py b/tests/ut/patch/platform/test_prefix_cache_cp_patches.py index fef7297cfaac..9968f11d6589 100644 --- a/tests/ut/patch/platform/test_prefix_cache_cp_patches.py +++ b/tests/ut/patch/platform/test_prefix_cache_cp_patches.py @@ -51,15 +51,11 @@ group_and_unify_kv_cache_specs, ) from vllm_ascend.patch.platform.patch_mamba_manager import AscendMambaManager -from vllm_ascend.utils import vllm_version_is # vLLM #60043 removed the leftover `mamba_cache_mode="all"` path and now asserts # that prefix caching requires `mamba_cache_mode="align"` in both supported lanes. _MAMBA_CACHING_MODE = "align" -# v0.32.0 keeps the two-argument admission API; verified main requires a builder. -_UPSTREAM_MAX_MEMORY_TAKES_BUILDER = not vllm_version_is("0.32.0") - def test_packed_cache_reuses_global_capacity_and_records_recycled_state_pages(): register_all_kvcache_specs(None) @@ -922,19 +918,11 @@ def test_deepseek_v4_main_restores_ascend_shared_tuple_planner(monkeypatch) -> N assert result.num_blocks == 7 assert result.kv_cache_tensors == [planned_tensor] - if _UPSTREAM_MAX_MEMORY_TAKES_BUILDER: - # vLLM #42309 threads the KVCacheConfigBuilder through admission on - # main; the DSV4 shared-tuple branch does not read it. - needed_memory = kv_cache_utils_patch._ascend_max_memory_usage_bytes_from_groups( - MagicMock(), - vllm_config, - kv_cache_config.kv_cache_groups, - ) - else: - needed_memory = kv_cache_utils_patch._ascend_max_memory_usage_bytes_from_groups( - vllm_config, - kv_cache_config.kv_cache_groups, - ) + needed_memory = kv_cache_utils_patch._ascend_max_memory_usage_bytes_from_groups( + MagicMock(), + vllm_config, + kv_cache_config.kv_cache_groups, + ) full_spec = kv_cache_config.kv_cache_groups[0].kv_cache_spec assert isinstance(full_spec, UniformTypeKVCacheSpecs) layer_tuple_bytes = sum(spec.page_size_bytes for spec in full_spec.kv_cache_specs.values()) diff --git a/tests/ut/patch/worker/patch_common/test_patch_distributed.py b/tests/ut/patch/worker/patch_common/test_patch_distributed.py index e63b579ed0d2..f29ddce42e26 100644 --- a/tests/ut/patch/worker/patch_common/test_patch_distributed.py +++ b/tests/ut/patch/worker/patch_common/test_patch_distributed.py @@ -190,7 +190,7 @@ def __init__(self, **kwargs): npu_communicator_module.NPUCommunicator = FakeNPUCommunicator utils_module.create_hccl_pg_options = MagicMock(return_value=shared_hccl_options) # The patch only uses this to decide whether to set ``cpu_timeout`` (vLLM - # main) or leave it to the upstream base class (0.32.0); no test here + # main) or leave it to the upstream base class (0.33.0); no test here # asserts on that branch. utils_module.vllm_version_is = lambda _target: False diff --git a/tests/ut/patch/worker/test_patch_mm_input_norm.py b/tests/ut/patch/worker/test_patch_mm_input_norm.py index 7e75a33d6f18..9e6756edfc88 100644 --- a/tests/ut/patch/worker/test_patch_mm_input_norm.py +++ b/tests/ut/patch/worker/test_patch_mm_input_norm.py @@ -13,24 +13,9 @@ from vllm.model_executor.model_loader.dummy_loader import DummyModelLoader from vllm.model_executor.model_loader.sharded_state_loader import ShardedStateLoader -from vllm_ascend.patch.worker.patch_mm_input_norm import patch_mm_input_norm - -@pytest.fixture(params=[True, False], ids=["v032-persistent", "upstream-nonpersistent"]) -def norm(request, monkeypatch): - original_init = FusedMMInputNorm.__init__ - - def init(self, *args, **kwargs): - original_init(self, *args, **kwargs) - # Exercise both upstream contracts even when CI already has #62767. - for name in ("weight", "bias"): - self.register_buffer(name, getattr(self, name), persistent=request.param) - - monkeypatch.setattr(FusedMMInputNorm, "__init__", init) - patch_mm_input_norm() - patched_init = FusedMMInputNorm.__init__ - patch_mm_input_norm() - assert FusedMMInputNorm.__init__ is patched_init +@pytest.fixture +def norm(): # Config construction must not initialize Ascend logging or device state. with patch("vllm_ascend.platform.NPUPlatform.check_and_update_config"): vllm_config = VllmConfig() diff --git a/tests/ut/patch/worker/test_patch_v2_gumbel.py b/tests/ut/patch/worker/test_patch_v2_gumbel.py index bb178581182d..71fe5a2a85b6 100644 --- a/tests/ut/patch/worker/test_patch_v2_gumbel.py +++ b/tests/ut/patch/worker/test_patch_v2_gumbel.py @@ -53,7 +53,7 @@ def test_dspark_sample_logits_dispatch(monkeypatch, probabilistic): speculator.temperature = torch.tensor([0.5, 1.5]) speculator.seeds = torch.tensor([3, 7]) speculator._step_cols = torch.arange(2, dtype=torch.int32) - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): # vLLM main (#63554) forwards the draft-logits cache shard to the sampler. speculator.draft_logits = ( # type: ignore[assignment] torch.empty(2, 2, 3) if probabilistic else None @@ -99,7 +99,7 @@ def test_dspark_sample_logits_dispatch(monkeypatch, probabilistic): torch.testing.assert_close(args[4], sample_pos - 1) assert kwargs["apply_temperature"] is True assert kwargs["is_drafting"] is True - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): assert kwargs["logits_cache"] is speculator.draft_logits else: assert kwargs["logits_cache"] is speculator.draft_logits.values # type: ignore[attr-defined] diff --git a/tests/ut/simple_kv_offload/test_simple_kv_offload.py b/tests/ut/simple_kv_offload/test_simple_kv_offload.py index 489b11fbb069..87db5c52deb9 100644 --- a/tests/ut/simple_kv_offload/test_simple_kv_offload.py +++ b/tests/ut/simple_kv_offload/test_simple_kv_offload.py @@ -23,7 +23,6 @@ SimpleCPUOffloadNPUWorker, _flatten_kv_value, ) -from vllm_ascend.utils import vllm_version_is def test_factory_registration_uses_consolidated_package( @@ -235,10 +234,6 @@ def launch_copy(self, *args, **kwargs) -> None: assert store_event.recorded_stream is current_stream -@pytest.mark.skipif( - vllm_version_is("0.32.0"), - reason="get_simple_cpu_offload_num_cpu_blocks is a main-only RPC", -) def test_npu_worker_reports_aligned_cpu_blocks( monkeypatch: pytest.MonkeyPatch, ) -> None: @@ -262,10 +257,6 @@ def test_npu_worker_reports_aligned_cpu_blocks( assert worker.get_simple_cpu_offload_num_cpu_blocks() == 8 -@pytest.mark.skipif( - vllm_version_is("0.32.0"), - reason="get_simple_cpu_offload_num_cpu_blocks is a main-only RPC", -) def test_npu_worker_reports_no_cpu_blocks_without_transfer_group( monkeypatch: pytest.MonkeyPatch, ) -> None: @@ -278,10 +269,6 @@ def test_npu_worker_reports_no_cpu_blocks_without_transfer_group( assert worker.get_simple_cpu_offload_num_cpu_blocks() is None -@pytest.mark.skipif( - vllm_version_is("0.32.0"), - reason="get_simple_cpu_offload_num_cpu_blocks is a main-only RPC", -) def test_npu_worker_reports_no_cpu_blocks_without_connector( monkeypatch: pytest.MonkeyPatch, ) -> None: diff --git a/tests/ut/spec_decode/test_dflash2_v2.py b/tests/ut/spec_decode/test_dflash2_v2.py index 66951316278a..897db0b90cc1 100644 --- a/tests/ut/spec_decode/test_dflash2_v2.py +++ b/tests/ut/spec_decode/test_dflash2_v2.py @@ -31,7 +31,6 @@ import vllm_ascend.worker.v2.spec_decode.dflash.speculator as dflash_module from vllm_ascend.ops.vocab_parallel_embedding import VocabParallelMode -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.v2.spec_decode import init_speculator from vllm_ascend.worker.v2.spec_decode.dflash.speculator import AscendDFlashSpeculator from vllm_ascend.worker.v2.spec_decode.dflash2.speculator import ( @@ -168,11 +167,8 @@ def test_v2_flash_attn_uses_exact_lengths_after_rejection_and_reordering(monkeyp kv_spec = FullAttentionSpec(block_size=128, num_kv_heads=1, head_size=128, dtype=torch.bfloat16) speculator = AscendDFlash2Speculator.__new__(AscendDFlash2Speculator) speculator.arange_np = torch.arange(5, dtype=torch.int32).numpy() - if vllm_version_is("0.32.0"): - speculator.max_model_len = 1024 - else: - # vLLM main exposes max_model_len as a read-only view of vllm_config. - speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=1024)) + # vLLM main exposes max_model_len as a read-only view of vllm_config. + speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=1024)) speculator.draft_max_seq_len = 1024 speculator.dcp_size = 1 speculator.input_buffers = SimpleNamespace( @@ -611,7 +607,7 @@ def test_dflash_input_preparation_keeps_physical_and_kernel_block_sizes_separate kernel.assert_called_once_with(*inputs, num_reqs_override=None, kv_cache_block_size=128) -@pytest.mark.skipif(vllm_version_is("0.32.0"), reason="main-only num_reqs_override") +@pytest.mark.skipif(False, reason="main-only num_reqs_override") def test_dflash_input_preparation_forwards_num_reqs_override(monkeypatch): """vLLM main (#58984) forwards the DP-synced request count positionally.""" kernel = MagicMock() diff --git a/tests/ut/spec_decode/test_dspark_speculator.py b/tests/ut/spec_decode/test_dspark_speculator.py index 08c784f15020..6825ef12ffd8 100644 --- a/tests/ut/spec_decode/test_dspark_speculator.py +++ b/tests/ut/spec_decode/test_dspark_speculator.py @@ -18,7 +18,6 @@ AscendQwen3DSparkForCausalLM, process_weight, ) -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.v2.spec_decode.dspark.speculator import ( AscendDSparkSpeculator, ) @@ -203,8 +202,6 @@ def _context_speculator(monkeypatch, group_ids=(0, 1), layer_map=(1, 0)): ) spec.attn_architecture, spec.use_dcp = "MLA", False spec.device = torch.device("cpu") - if vllm_version_is("0.32.0"): - spec.max_model_len = 16 spec.speculative_config = object() spec.vllm_config = SimpleNamespace( model_config=SimpleNamespace(get_hidden_size=lambda: 4, max_model_len=16), diff --git a/tests/ut/spec_decode/test_dspark_valid_kv_lengths.py b/tests/ut/spec_decode/test_dspark_valid_kv_lengths.py index 301d94d5a95b..37e50a547cf4 100644 --- a/tests/ut/spec_decode/test_dspark_valid_kv_lengths.py +++ b/tests/ut/spec_decode/test_dspark_valid_kv_lengths.py @@ -14,7 +14,6 @@ from vllm.v1.worker.gpu.spec_decode.dspark.speculator import DSparkSpeculator import vllm_ascend.worker.v2.spec_decode.dspark.speculator as speculator_module -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.v2.spec_decode.dspark.speculator import AscendDSparkSpeculator @@ -25,11 +24,8 @@ def _spec(lengths, *, architecture="MLA", use_dcp=False): spec.use_dcp = use_dcp spec.input_buffers = SimpleNamespace(seq_lens=torch.tensor(lengths, dtype=torch.int32), positions=object()) spec.target_input_buffers = SimpleNamespace(seq_lens_cpu=torch.tensor([99999], dtype=torch.int32)) - if vllm_version_is("0.32.0"): - spec.max_model_len = 131072 - else: - # vLLM main exposes max_model_len as a read-only view of vllm_config. - spec.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=131072)) + # vLLM main exposes max_model_len as a read-only view of vllm_config. + spec.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=131072)) return spec diff --git a/tests/ut/spec_decode/test_mla_dspark.py b/tests/ut/spec_decode/test_mla_dspark.py index 9224a05369df..4c3e4bba9ec7 100644 --- a/tests/ut/spec_decode/test_mla_dspark.py +++ b/tests/ut/spec_decode/test_mla_dspark.py @@ -63,7 +63,7 @@ def test_dspark_without_pcp_reuses_target_sync(monkeypatch): monkeypatch.setattr(shared, "build_attn_metadata_wrapper", nullcontext) monkeypatch.setattr(shared, "build_attn_metadata_factory", lambda *a, **kw: nullcontext()) # Without PCP, both models use the same request layout. - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): target_sync = DPSyncState( # type: ignore[call-arg] num_tokens_across_dp=torch.tensor([4, 4]), uniform_token_count=1, eager=False, num_reqs=4 ) diff --git a/tests/ut/test_compressed_prefix_cache.py b/tests/ut/test_compressed_prefix_cache.py index eca8fee6c8ad..7d9714d9eecd 100644 --- a/tests/ut/test_compressed_prefix_cache.py +++ b/tests/ut/test_compressed_prefix_cache.py @@ -8,6 +8,10 @@ from vllm.sampling_params import SamplingParams from vllm.utils.hashing import sha256 from vllm.v1.core.block_pool import BlockPool + +# vLLM #61183 moved `is_kv_cache_spec_uniform` to `kv_cache_planning` on main; +# the v0.33.0 lane still ships it in `kv_cache_utils`. +from vllm.v1.core.kv_cache_planning import is_kv_cache_spec_uniform from vllm.v1.core.kv_cache_utils import ( BlockHashListWithBlockSize, get_block_hash, @@ -31,14 +35,6 @@ from vllm_ascend.patch.platform.patch_kv_cache_coordinator import ( AscendHybridKVCacheCoordinator, ) -from vllm_ascend.utils import vllm_version_is - -# vLLM #61183 moved `is_kv_cache_spec_uniform` to `kv_cache_planning` on main; -# the v0.32.0 lane still ships it in `kv_cache_utils`. -if vllm_version_is("0.32.0"): - from vllm.v1.core.kv_cache_utils import is_kv_cache_spec_uniform -else: - from vllm.v1.core.kv_cache_planning import is_kv_cache_spec_uniform pytestmark = pytest.mark.cpu_test diff --git a/tests/ut/worker/test_dcp_speculator_metadata_v2.py b/tests/ut/worker/test_dcp_speculator_metadata_v2.py index df541ae823ab..729a9ad629be 100644 --- a/tests/ut/worker/test_dcp_speculator_metadata_v2.py +++ b/tests/ut/worker/test_dcp_speculator_metadata_v2.py @@ -19,7 +19,6 @@ from vllm_ascend.attention.attention_v1 import AscendAttentionState from vllm_ascend.attention.context_parallel import sfa_cp from vllm_ascend.attention.context_parallel.sfa_cp import AscendSFADCPMetadata, AscendSFADCPMetadataBuilder -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.dcp_utils import DCPManager from vllm_ascend.worker.v2 import attn_utils from vllm_ascend.worker.v2.spec_decode.dspark.speculator import AscendDSparkSpeculator @@ -94,9 +93,6 @@ def _speculator(monkeypatch, kind, architecture, width, padded, step, use_dcp=Tr spec.dcp_manager = manager # vLLM main (#56723) reads speculator.dcp_size in _build_attn_metadata. spec.dcp_size = config.parallel_config.decode_context_parallel_size - # vLLM main exposes max_model_len as a read-only view of vllm_config. - if vllm_version_is("0.32.0"): - spec.max_model_len = 128 spec.draft_max_seq_len = 128 spec.num_query_per_req = width spec.vllm_config = spec.draft_vllm_config = config diff --git a/tests/ut/worker/test_mla_dcp_metadata_v2.py b/tests/ut/worker/test_mla_dcp_metadata_v2.py index 5cfbcd6b76fb..61d3d9953ced 100644 --- a/tests/ut/worker/test_mla_dcp_metadata_v2.py +++ b/tests/ut/worker/test_mla_dcp_metadata_v2.py @@ -9,7 +9,6 @@ import torch from vllm_ascend.attention.context_parallel.mla_cp import AscendMLADCPDecodeMetadata -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.dcp_utils import DCPManager from vllm_ascend.worker.v2 import attn_utils from vllm_ascend.worker.v2.spec_decode.target_dependent_ar.speculator import AscendTargetDependentARSpeculator @@ -116,11 +115,8 @@ def test_full_draft_steps_refresh_local_lengths_without_aliasing(size, rank, int speculator = object.__new__(AscendTargetDependentARSpeculator) speculator.attn_architecture = "MLA" speculator.use_dcp = True - if vllm_version_is("0.32.0"): - speculator.max_model_len = 128 - else: - # vLLM main exposes max_model_len as a read-only view of vllm_config. - speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=128)) + # vLLM main exposes max_model_len as a read-only view of vllm_config. + speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=128)) speculator.dcp_manager = _manager(size, rank, interleave) speculator.draft_vllm_config = SimpleNamespace( parallel_config=SimpleNamespace(decode_context_parallel_size=size, cp_kv_cache_interleave_size=interleave) diff --git a/tests/ut/worker/test_model_runner_v2.py b/tests/ut/worker/test_model_runner_v2.py index 762018e6f152..769c873c7991 100644 --- a/tests/ut/worker/test_model_runner_v2.py +++ b/tests/ut/worker/test_model_runner_v2.py @@ -27,7 +27,6 @@ from vllm_ascend.attention.attention_v1 import AscendAttentionBackend from vllm_ascend.attention.fa_v1 import AscendFlashAttentionBackend from vllm_ascend.attention.mla_v1 import AscendMLABackend, AscendMLAImpl -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.v2.input_batch import AscendInputBatch, AscendInputBuffers from vllm_ascend.worker.v2.model_runner import NPUModelRunner from vllm_ascend.worker.v2.pcp_manager import AscendPCPManager @@ -488,7 +487,7 @@ def test_prepare_inputs_preserves_pcp_tokens_and_forwards_graph_padding(): # prepare_inputs keeps the real global PCP batch when it is larger than the # graph descriptor, and forwards the whole descriptor through the retained - # PCPManager API (vLLM #57980), also retained in v0.32.0. + # PCPManager API (vLLM #57980), also retained in v0.33.0. assert len(padding_assignments) == 2 assert ast.unparse(padding_assignments[0].value) == "max(num_tokens, batch_desc.num_tokens)" assert ast.unparse(padding_assignments[1].value) == "global_graph_num_reqs * batch_desc.uniform_token_count" @@ -960,7 +959,7 @@ def test_pcp_dummy_refreshes_captured_buffers_after_real_batch(num_reqs, num_tok dummy = AscendInputBatch.make_dummy(num_reqs, num_tokens, runner.input_buffers) # execute_model stages dummy inputs before preparing attention metadata. - stage_name = "prepare_inputs_to_capture" if vllm_version_is("0.32.0") else "prepare_inputs_for_capture_or_profile" + stage_name = "prepare_inputs_for_capture_or_profile" staged = getattr(manager, stage_name)(dummy) block_tables, slots = runner.prepare_dummy_attn(staged) diff --git a/tests/ut/worker/test_model_runner_v2_finegrained_tp.py b/tests/ut/worker/test_model_runner_v2_finegrained_tp.py index 43cd63e99052..6ee1c8dd8658 100644 --- a/tests/ut/worker/test_model_runner_v2_finegrained_tp.py +++ b/tests/ut/worker/test_model_runner_v2_finegrained_tp.py @@ -224,8 +224,8 @@ def test_dispatch_tail_canary_matches_upstream_sample(with_grammar, with_draft, expected_calls = 2 if with_grammar else 1 assert len(upstream_calls) == expected_calls assert override_calls == upstream_calls - if with_grammar and with_draft and vllm_version_is("0.32.0"): - # 0.32.0 exposes the permissive-row mask as the fourth sampler argument; + if with_grammar and with_draft and vllm_version_is("0.33.0"): + # 0.33.0 exposes the permissive-row mask as the fourth sampler argument; # main feeds it through the scheduler/draft-token handler instead. invalid_drafts = runner.rejection_sampler.call_args.args[3] assert invalid_drafts.tolist() == [False, False, True] diff --git a/tests/ut/worker/test_model_runner_v2_kv_cache.py b/tests/ut/worker/test_model_runner_v2_kv_cache.py index 340b3cea8bad..eacfefa08110 100644 --- a/tests/ut/worker/test_model_runner_v2_kv_cache.py +++ b/tests/ut/worker/test_model_runner_v2_kv_cache.py @@ -103,7 +103,7 @@ def test_initialize_builds_aux_output_connector_when_enabled(): # The initializer deep-copies the config, so assert against the resolved one # (identity shortcut) instead of comparing the original object by value. - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): get_aux.assert_called_once_with(runner.model, runner.vllm_config, runner.kv_cache_config) else: # Main creates the connector without the KV-cache config and diff --git a/tests/ut/worker/test_pcp_manager_v2.py b/tests/ut/worker/test_pcp_manager_v2.py index de4a2a86183d..e080106f18cd 100644 --- a/tests/ut/worker/test_pcp_manager_v2.py +++ b/tests/ut/worker/test_pcp_manager_v2.py @@ -34,7 +34,6 @@ from vllm_ascend.attention.context_parallel.common_cp import is_pcp_decode_sharding_enabled from vllm_ascend.platform import _setup_worker_and_scheduler -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.v2 import states as states_module from vllm_ascend.worker.v2.aclgraph_utils import ModelAclGraphManager from vllm_ascend.worker.v2.input_batch import AscendInputBatch, AscendInputBuffers @@ -1189,7 +1188,7 @@ def test_cpp_dummy_is_partitioned_instead_of_staged(): local_batch = _make_local_pcp_batch() # vLLM main renamed the upstream staging hook; patch and call the live name. - stage_name = "prepare_inputs_to_capture" if vllm_version_is("0.32.0") else "prepare_inputs_for_capture_or_profile" + stage_name = "prepare_inputs_for_capture_or_profile" with ( patch.object(PCPManager, stage_name) as stage, patch.object(manager, "partition_batch", return_value=local_batch) as partition, @@ -1211,7 +1210,7 @@ def test_capture_input_without_cpp_marker_uses_staging_path(): legacy_batch = SimpleNamespace() staged_batch = _make_local_pcp_batch() - stage_name = "prepare_inputs_to_capture" if vllm_version_is("0.32.0") else "prepare_inputs_for_capture_or_profile" + stage_name = "prepare_inputs_for_capture_or_profile" with ( patch.object(PCPManager, stage_name, return_value=staged_batch) as stage, patch.object(manager, "partition_batch") as partition, diff --git a/tests/ut/worker/test_v2_dummy_padding.py b/tests/ut/worker/test_v2_dummy_padding.py index 30995f2d6a2c..709a4f715e34 100644 --- a/tests/ut/worker/test_v2_dummy_padding.py +++ b/tests/ut/worker/test_v2_dummy_padding.py @@ -13,7 +13,6 @@ from vllm.v1.worker.utils import get_uniform_decode_token_count from vllm_ascend.attention.attention_v1 import AscendAttentionState -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.v2.aclgraph_utils import ModelAclGraphManager from vllm_ascend.worker.v2.input_batch import AscendInputBatch, AscendInputBuffers from vllm_ascend.worker.v2.model_runner import NPUModelRunner @@ -140,7 +139,7 @@ def test_mixed_dp_dummy_keeps_graphs_and_reuses_sync(buffers, runner, draft_mode cpu_group = object() def other_rank_votes(votes, group): - # v0.32.0 passes ``group=cpu_group``; main's ``cpu_all_reduce_`` does not. + # cpu_all_reduce_ already binds the CPU group. assert group is None or group is cpu_group # The other ranks decode real requests with the same query width. votes[0, 1:] = torch.tensor([2 * uniform, 3 * uniform, uniform]) @@ -171,16 +170,10 @@ def execute_dummy(num_tokens, **kwargs): return None, None extra_collective_patch: AbstractContextManager[Any] - if vllm_version_is("0.32.0"): - # v0.32.0 collects through ``dist.all_reduce(votes, group=cpu_group)``. - dp_group = SimpleNamespace(cpu_group=cpu_group) - collective = Mock(side_effect=other_rank_votes) - extra_collective_patch = patch("vllm.v1.worker.gpu.dp_utils.dist.all_reduce", collective) - else: - # vLLM main collects through ``get_dp_group().cpu_all_reduce_(votes)``. - collective = Mock(side_effect=lambda votes: other_rank_votes(votes, None)) - dp_group = SimpleNamespace(cpu_all_reduce_=collective) - extra_collective_patch = nullcontext() + # vLLM main collects through ``get_dp_group().cpu_all_reduce_(votes)``. + collective = Mock(side_effect=lambda votes: other_rank_votes(votes, None)) + dp_group = SimpleNamespace(cpu_all_reduce_=collective) + extra_collective_patch = nullcontext() with ( patch.object(GPUModelRunner, "_dummy_run", side_effect=execute_dummy), diff --git a/tests/ut/worker/test_worker_v2.py b/tests/ut/worker/test_worker_v2.py index f180d2981498..d1361e759da2 100644 --- a/tests/ut/worker/test_worker_v2.py +++ b/tests/ut/worker/test_worker_v2.py @@ -85,20 +85,12 @@ def test_triton_warmup_failure_prevents_capture(use_v2): class TestNPUWorkerV2(TestBase): def test_worker_imports_planning_helpers_from_supported_lane(self): - from vllm_ascend.utils import vllm_version_is - from vllm_ascend.worker import worker - - if vllm_version_is("0.32.0"): - from vllm.v1.core import kv_cache_utils as planning + from vllm.v1.core import kv_cache_planning as planning + from vllm.v1.core.kv_cache_config_builder import get_kv_cache_config_builder - self.assertIs(worker.get_kv_cache_groups, planning.get_kv_cache_groups) - else: - from vllm.v1.core import kv_cache_planning as planning - from vllm.v1.core.kv_cache_config_builder import get_kv_cache_config_builder + from vllm_ascend.worker import worker - # On main the grouping is resolved through the platform's - # pluggable KVCacheConfigBuilder, installed in worker.py. - self.assertIs(worker.get_kv_cache_config_builder, get_kv_cache_config_builder) + self.assertIs(worker.get_kv_cache_config_builder, get_kv_cache_config_builder) self.assertIs(worker.unify_hybrid_kv_cache_specs, planning.unify_hybrid_kv_cache_specs) def test_get_encoder_cudagraph_stats_is_serializable(self): diff --git a/tests/ut/worker/v2/test_speculator.py b/tests/ut/worker/v2/test_speculator.py index b675a7cef20e..e1ea10039963 100644 --- a/tests/ut/worker/v2/test_speculator.py +++ b/tests/ut/worker/v2/test_speculator.py @@ -19,7 +19,6 @@ from vllm_ascend.attention.mla_v1 import AscendMLABackend from vllm_ascend.attention.sfa_v1 import AscendSFABackend from vllm_ascend.distributed.eplb.tensor_ops import make_allgather_mask -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.v2.input_batch import AscendInputBuffers from vllm_ascend.worker.v2.spec_decode.target_dependent_ar.speculator import ( AscendTargetDependentARSpeculator, @@ -31,10 +30,7 @@ def test_calc_next_seq_lens_cpu(): """Test calculation of the next CPU sequence lengths.""" speculator = AscendTargetDependentARSpeculator.__new__(AscendTargetDependentARSpeculator) - if vllm_version_is("0.32.0"): - speculator.max_model_len = 100 - else: - speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=100)) + speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=100)) seq_lens_cpu = torch.tensor([10, 20, 98, 66], dtype=torch.int32) result = speculator._calc_next_seq_lens_cpu(seq_lens_cpu, num_reqs=3, num_reqs_padded=4, step=3) expected = torch.tensor([13, 23, 100, 0], dtype=torch.int32) @@ -246,9 +242,8 @@ def test_prefill_filters_target_only_metadata(): CUDAGraphMode.NONE, None, ] - if not vllm_version_is("0.32.0"): - # vLLM main added `skip_sample` and forwards it to the upstream _prefill. - expected_args.append(False) + # vLLM main added `skip_sample` and forwards it to the upstream _prefill. + expected_args.append(False) parent_prefill.assert_called_once_with(*expected_args) @@ -260,11 +255,7 @@ def test_prefill_forwards_skip_sample_on_main(): speculator.draft_attn_layer_names = {"draft"} with patch.object(TargetDependentARSpeculator, "_prefill") as parent_prefill: speculator._prefill(2, 4, attn_metadata, None, None, skip_sample=True) - if vllm_version_is("0.32.0"): - assert "skip_sample" not in parent_prefill.call_args.kwargs - assert len(parent_prefill.call_args.args) == 7 - else: - assert parent_prefill.call_args.args[-1] is True + assert parent_prefill.call_args.args[-1] is True def test_build_uniform_attn_metadata_sets_decode_only(): @@ -474,10 +465,7 @@ def test_update_decode_attn_metadata_gqa(): """Test updating decode attention metadata for GQA.""" speculator = AscendTargetDependentARSpeculator.__new__(AscendTargetDependentARSpeculator) speculator.attn_architecture = "GQA" - if vllm_version_is("0.32.0"): - speculator.max_model_len = 32 - else: - speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=32)) + speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=32)) speculator.use_dcp = False metadata = SimpleNamespace( seq_lens_cpu=torch.zeros(4, dtype=torch.int32), @@ -516,10 +504,7 @@ def test_build_fia_params_decode(): speculator.draft_attn_layer_names = {"draft"} speculator.input_batch = SimpleNamespace(num_reqs=2, seq_lens_np=np.array([10, 29])) speculator.num_speculative_steps = 3 - if vllm_version_is("0.32.0"): - speculator.max_model_len = 30 - else: - speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=30)) + speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=30)) result = speculator.build_fia_params(3, {"draft": metadata}, False) assert len(result) == 2 assert result[0]["actual_seq_lengths"] == [1, 2, 3] @@ -688,10 +673,7 @@ def test_update_decode_attn_metadata_mla_with_dcp(): """Test MLA decode metadata updates with DCP enabled.""" speculator = AscendTargetDependentARSpeculator.__new__(AscendTargetDependentARSpeculator) speculator.attn_architecture = "MLA" - if vllm_version_is("0.32.0"): - speculator.max_model_len = 32 - else: - speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=32)) + speculator.vllm_config = SimpleNamespace(model_config=SimpleNamespace(max_model_len=32)) speculator.use_dcp = True local_seq_lens = torch.tensor([6, 11, 0], dtype=torch.int32) diff --git a/vllm_ascend/_310p/worker_310p.py b/vllm_ascend/_310p/worker_310p.py index 80c4106acf3f..0ae3e7eaff7b 100644 --- a/vllm_ascend/_310p/worker_310p.py +++ b/vllm_ascend/_310p/worker_310p.py @@ -24,17 +24,13 @@ from vllm.utils.mem_utils import MemorySnapshot, memory_profiling from vllm.utils.torch_utils import set_random_seed # noqa: E402 +# KV-cache planning lives in kv_cache_planning on both supported versions. +from vllm.v1.core.kv_cache_planning import get_kv_cache_groups + from vllm_ascend._310p.kv_cache_sharing import get_310p_shared_cache_slots -from vllm_ascend.utils import is_rc_device, vllm_version_is +from vllm_ascend.utils import is_rc_device from vllm_ascend.worker.worker import NPUWorker, init_workspace_manager -# vLLM #61183 moved `get_kv_cache_groups` to `kv_cache_planning` on main; the -# v0.32.0 lane still ships it in `kv_cache_utils`. -if vllm_version_is("0.32.0"): - from vllm.v1.core.kv_cache_utils import get_kv_cache_groups -else: - from vllm.v1.core.kv_cache_planning import get_kv_cache_groups - class NPUWorker310(NPUWorker): def _scale_kv_cache_memory_for_multi_group(self, available_memory: int) -> int: diff --git a/vllm_ascend/ascend_config.py b/vllm_ascend/ascend_config.py index 821deb648037..5519f0bf560c 100644 --- a/vllm_ascend/ascend_config.py +++ b/vllm_ascend/ascend_config.py @@ -895,7 +895,7 @@ def derive_and_validate(self, vllm_config: VllmConfig) -> AscendConfig: ) = self._parse_sparse_li_layers_from_quant_config(quant_config, ("W8A8_MXFP8",)) self._sparse_li_layer_filter_enabled = self._has_sparse_li_layer_config(quant_config) # vLLM #60517 removed the torch.compile-based sequence-parallelism pass - # (and `PassConfig.enable_sp`) in both v0.32.0 and verified main. + # (and `PassConfig.enable_sp`) in both v0.33.0 and verified main. enable_sp_by_pass = False self.enable_sp_by_pass = vc.model_config is not None and not vc.model_config.enforce_eager and enable_sp_by_pass diff --git a/vllm_ascend/attention/mla_v1.py b/vllm_ascend/attention/mla_v1.py index 02db136c561a..63f502d938a8 100644 --- a/vllm_ascend/attention/mla_v1.py +++ b/vllm_ascend/attention/mla_v1.py @@ -1019,9 +1019,9 @@ def __init__( self.g_proj = kwargs.get("g_proj") # vLLM main fuses Kimi-K3's output gate into the QKV-A projection as a # trailing shard, making its per-rank layout ``[q_a | kv_a | gate]`` and - # dropping the standalone ``g_proj``. Release v0.32.0 keeps the separate + # dropping the standalone ``g_proj``. Release v0.33.0 keeps the separate # ``g_proj`` and a two-shard projection. - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): self.qkv_a_gate_fused = False self.use_output_gate = self.g_proj is not None else: @@ -1312,23 +1312,13 @@ def process_weights_after_loading(self, act_dtype: torch.dtype): # scenario the graph is captured once, so every later weight update # reload has to refresh the stored tensors in place instead of # rebinding the attributes to freshly allocated tensors. - # `replace_parameter(..., prefer_copy=True)` does exactly that on - # v0.32.0: it copies into the existing storage while the new value stays - # compatible, and rebinds only when shape/dtype/device actually - # changes. vLLM main (#62326) dropped `prefer_copy` and keeps the - # parameter object by default. This mirrors how upstream vLLM refreshes - # `MLAAttention.W_UV`/`W_UK_T`, and unlike a plain `copy_` it cannot - # raise on a shape mismatch. + # replace_parameter preserves the parameter object and compatible storage. w_uv = W_UV.transpose(0, 1).contiguous() # (L, N, V) -> (N, L, V) w_uk_t = W_UK.permute(1, 2, 0).contiguous() # (L, N, P) -> (N, P, L) if self.dcp_q_replicate_enabled: w_uk_t = get_dcp_group().all_gather(w_uk_t, dim=0) - if vllm_version_is("0.32.0"): - replace_parameter(self, "W_UV", w_uv, prefer_copy=True) - replace_parameter(self, "W_UK_T", w_uk_t, prefer_copy=True) - else: - replace_parameter(self, "W_UV", w_uv) - replace_parameter(self, "W_UK_T", w_uk_t) + replace_parameter(self, "W_UV", w_uv) + replace_parameter(self, "W_UK_T", w_uk_t) self.mlapo_W_UK_T = self.W_UK_T if self.enable_mlapo: @@ -3269,13 +3259,13 @@ def mla_preprocess_decode(self, q_c, kv_no_split, kv_cache, attn_metadata, writt ) # vLLM main fuses Kimi-K3's output gate into the trailing shard of the - # QKV-A projection; v0.32.0 never has that shard, so the release lane keeps + # QKV-A projection; v0.33.0 never has that shard, so the release lane keeps # the original two-way ``[q_a | kv_a]`` split. - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): @property def _fused_qkv_a_kv_end(self) -> int | None: - """v0.32.0 keeps the plain two-shard QKV-A projection.""" + """v0.33.0 keeps the plain two-shard QKV-A projection.""" return None def _split_fused_qkv_lora(self, qkv_lora: torch.Tensor): diff --git a/vllm_ascend/attention/sfa_v1.py b/vllm_ascend/attention/sfa_v1.py index e35965e4639d..5de780b06039 100644 --- a/vllm_ascend/attention/sfa_v1.py +++ b/vllm_ascend/attention/sfa_v1.py @@ -76,7 +76,6 @@ is_mtp_layer, is_rl_weight_update_enabled, maybe_trans_nz, - vllm_version_is, ) from vllm_ascend.weight_switch import ParallelOProjection, WeightSwitchConfig @@ -981,25 +980,11 @@ def process_weights_after_loading(self, act_dtype: torch.dtype): W_UK, W_UV = kv_b_proj_weight.split([self.qk_nope_head_dim, self.v_head_dim], dim=-1) - # NOTE: `W_UK`/`W_UV` must live at a stable address: in graph + RL - # scenario the graph is captured once, so every later weight update - # reload has to refresh the stored tensors in place instead of - # rebinding the attributes to freshly allocated tensors. - # `replace_parameter(..., prefer_copy=True)` does exactly that on - # v0.32.0: it copies into the existing storage while the new value stays - # compatible, and rebinds only when shape/dtype/device actually - # changes. vLLM main (#62326) dropped `prefer_copy` and keeps the - # parameter object by default. This mirrors how upstream vLLM refreshes - # `MLAAttention.W_UV`/`W_UK_T`, and unlike a plain `copy_` it cannot - # raise on a shape mismatch. + # replace_parameter preserves the parameter object and compatible storage on both supported versions. w_uv = W_UV.transpose(0, 1).contiguous() # (L, N, V) -> (N, L, V) w_uk_t = W_UK.permute(1, 2, 0).contiguous() # (L, N, P) -> (N, P, L) - if vllm_version_is("0.32.0"): - replace_parameter(self, "W_UV", w_uv, prefer_copy=True) - replace_parameter(self, "W_UK_T", w_uk_t, prefer_copy=True) - else: - replace_parameter(self, "W_UV", w_uv) - replace_parameter(self, "W_UK_T", w_uk_t) + replace_parameter(self, "W_UV", w_uv) + replace_parameter(self, "W_UK_T", w_uk_t) # Dispose kv_b_proj since it is replaced by W_UV and W_UK_T to save memory. # RL keeps it: it is the only source of W_UV/W_UK_T, so every weight diff --git a/vllm_ascend/core/dyntra_lb_scheduler.py b/vllm_ascend/core/dyntra_lb_scheduler.py index 773751a5c7f3..178d9f11a4db 100644 --- a/vllm_ascend/core/dyntra_lb_scheduler.py +++ b/vllm_ascend/core/dyntra_lb_scheduler.py @@ -30,7 +30,6 @@ from vllm.v1.utils import record_function_or_nullcontext from vllm_ascend.ascend_config import DyntraLBConfig -from vllm_ascend.utils import vllm_version_is if TYPE_CHECKING: from vllm.v1.core.sched.scheduler import Scheduler as _SchedulerBase @@ -594,9 +593,7 @@ def schedule(self, throttle_prefills: bool = False) -> SchedulerOutput: break if new_blocks is None: - if not vllm_version_is("0.32.0") and ( - self.policy == SchedulingPolicy.PRIORITY and request.status == RequestStatus.PREEMPTED - ): + if self.policy == SchedulingPolicy.PRIORITY and request.status == RequestStatus.PREEMPTED: # The request was the lowest-priority running request and # preempted itself. The requests after it have higher # priority and may still fit; it was removed from diff --git a/vllm_ascend/core/recompute_scheduler.py b/vllm_ascend/core/recompute_scheduler.py index 21702e156217..ad1a723b54eb 100644 --- a/vllm_ascend/core/recompute_scheduler.py +++ b/vllm_ascend/core/recompute_scheduler.py @@ -46,7 +46,7 @@ DyntraLBPolicyMixin, print_scheduler_summary, ) -from vllm_ascend.utils import get_ascend_config, vllm_version_is +from vllm_ascend.utils import get_ascend_config def _normalize_encoder_schedule_result( @@ -432,9 +432,7 @@ def schedule(self, throttle_prefills: bool = False) -> SchedulerOutput: break if new_blocks is None: - if not vllm_version_is("0.32.0") and ( - self.policy == SchedulingPolicy.PRIORITY and request.status == RequestStatus.PREEMPTED - ): + if self.policy == SchedulingPolicy.PRIORITY and request.status == RequestStatus.PREEMPTED: # The request was the lowest-priority running request and # preempted itself. The requests after it have higher # priority and may still fit; it was removed from diff --git a/vllm_ascend/core/scheduler_profiling_chunk.py b/vllm_ascend/core/scheduler_profiling_chunk.py index 863fa708ec96..c374a902d041 100644 --- a/vllm_ascend/core/scheduler_profiling_chunk.py +++ b/vllm_ascend/core/scheduler_profiling_chunk.py @@ -46,7 +46,6 @@ from vllm.v1.utils import record_function_or_nullcontext from vllm_ascend.core.profiling_chunk_predictor import ProfilingChunkManager -from vllm_ascend.utils import vllm_version_is class ProfilingChunkScheduler(Scheduler): @@ -527,9 +526,7 @@ def schedule(self, throttle_prefills: bool = False) -> SchedulerOutput: # noqa: break if new_blocks is None: - if not vllm_version_is("0.32.0") and ( - self.policy == SchedulingPolicy.PRIORITY and request.status == RequestStatus.PREEMPTED - ): + if self.policy == SchedulingPolicy.PRIORITY and request.status == RequestStatus.PREEMPTED: # The request was the lowest-priority running request and # preempted itself. The requests after it have higher # priority and may still fit; it was removed from diff --git a/vllm_ascend/distributed/weight_transfer/hccl_engine.py b/vllm_ascend/distributed/weight_transfer/hccl_engine.py index 357f912c2e62..ca71afa58ebf 100644 --- a/vllm_ascend/distributed/weight_transfer/hccl_engine.py +++ b/vllm_ascend/distributed/weight_transfer/hccl_engine.py @@ -295,7 +295,7 @@ def send_weights(self) -> None: self._release_group() raise - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): def _broadcast(self, source: WeightSource, meta: list[ParamMeta]) -> None: with torch.npu.device(self.device): diff --git a/vllm_ascend/distributed/weight_transfer/npu_ipc_engine.py b/vllm_ascend/distributed/weight_transfer/npu_ipc_engine.py index 5f9dd16b5c11..12b91c34e82f 100644 --- a/vllm_ascend/distributed/weight_transfer/npu_ipc_engine.py +++ b/vllm_ascend/distributed/weight_transfer/npu_ipc_engine.py @@ -25,7 +25,6 @@ packed_npu_ipc_consumer, packed_npu_ipc_producer, ) -from vllm_ascend.utils import vllm_version_is if TYPE_CHECKING: from vllm.distributed.weight_transfer.base import ( @@ -268,9 +267,8 @@ def _post_send_sync() -> None: def _send_packed(self, source: "WeightSource") -> None: """Send weights in bounded-memory chunks (packed mode).""" - # vLLM main replaced `WeightSource.__iter__` with `iter_full()`; - # v0.32.0 still iterates the source directly. - iterator = iter(source) if vllm_version_is("0.32.0") else source.iter_full() + # Both supported versions drive the WeightSource iter_full protocol. + iterator = source.iter_full() for chunk in packed_npu_ipc_producer( iterator=iterator, npu_uuid=self.npu_uuid, diff --git a/vllm_ascend/ec_manager/score_ec_manager.py b/vllm_ascend/ec_manager/score_ec_manager.py index c8fc5c4313c9..e712d522ba1e 100644 --- a/vllm_ascend/ec_manager/score_ec_manager.py +++ b/vllm_ascend/ec_manager/score_ec_manager.py @@ -6,8 +6,6 @@ from vllm.v1.core.encoder_cache_manager import EncoderCacheManager from vllm.v1.request import Request -from vllm_ascend.utils import vllm_version_is - if TYPE_CHECKING: from vllm.config import VllmConfig @@ -110,10 +108,9 @@ def create_manager( def __init__(self, cache_size: int, vllm_config: "VllmConfig"): super().__init__(cache_size) - if not vllm_version_is("0.32.0"): - # vLLM main keeps per-mm_hash refcounts for a request's cached - # inputs; the pinned release tree tracks only the input ids. - self.request_hash_refs: dict[str, dict[str, int]] = {} + # vLLM main keeps per-mm_hash refcounts for a request's cached + # inputs; the pinned release tree tracks only the input ids. + self.request_hash_refs: dict[str, dict[str, int]] = {} config = ScoreEncoderCacheConfig.from_dict(vllm_config.ec_manager_config.manager_config) # ---------------- NPU cache ---------------- @@ -306,14 +303,11 @@ def check_and_update_cache(self, request: Request, input_id: int) -> bool: if mm_hash in self.npu_cache: ent.clock = self.max_clock - if vllm_version_is("0.32.0"): - self.request_cached_ids.setdefault(request.request_id, set()).add(input_id) - else: - cached_ids = self.request_cached_ids.setdefault(request.request_id, set()) - if input_id not in cached_ids: - cached_ids.add(input_id) - hash_refs = self.request_hash_refs.setdefault(request.request_id, {}) - hash_refs[mm_hash] = hash_refs.get(mm_hash, 0) + 1 + cached_ids = self.request_cached_ids.setdefault(request.request_id, set()) + if input_id not in cached_ids: + cached_ids.add(input_id) + hash_refs = self.request_hash_refs.setdefault(request.request_id, {}) + hash_refs[mm_hash] = hash_refs.get(mm_hash, 0) + 1 return True def on_request(self): @@ -421,46 +415,36 @@ def allocate(self, request: Request, input_id: int) -> None: self.cpu_cache[mm_hash] = cache_entry self.cached[mm_hash].add(request_id) - if vllm_version_is("0.32.0"): - self.request_cached_ids.setdefault(request_id, set()).add(input_id) - else: - cached_ids = self.request_cached_ids.setdefault(request_id, set()) - if input_id not in cached_ids: - cached_ids.add(input_id) - hash_refs = self.request_hash_refs.setdefault(request_id, {}) - hash_refs[mm_hash] = hash_refs.get(mm_hash, 0) + 1 + cached_ids = self.request_cached_ids.setdefault(request_id, set()) + if input_id not in cached_ids: + cached_ids.add(input_id) + hash_refs = self.request_hash_refs.setdefault(request_id, {}) + hash_refs[mm_hash] = hash_refs.get(mm_hash, 0) + 1 def free_encoder_input(self, request: Request, input_id: int) -> None: req_id = request.request_id mm_hash = request.mm_features[input_id].identifier - if vllm_version_is("0.32.0"): - if req_id in self.request_cached_ids: - self.request_cached_ids[req_id].discard(input_id) - if not self.request_cached_ids[req_id]: - del self.request_cached_ids[req_id] - else: - cached_ids = self.request_cached_ids.get(req_id) - if cached_ids is not None and input_id in cached_ids: - cached_ids.remove(input_id) - hash_refs = self.request_hash_refs.setdefault(req_id, {}) - refs = hash_refs.get(mm_hash, 0) - if refs <= 1: - hash_refs.pop(mm_hash, None) - else: - hash_refs[mm_hash] = refs - 1 - if not cached_ids: - del self.request_cached_ids[req_id] - if not hash_refs: - self.request_hash_refs.pop(req_id, None) + cached_ids = self.request_cached_ids.get(req_id) + if cached_ids is not None and input_id in cached_ids: + cached_ids.remove(input_id) + hash_refs = self.request_hash_refs.setdefault(req_id, {}) + refs = hash_refs.get(mm_hash, 0) + if refs <= 1: + hash_refs.pop(mm_hash, None) + else: + hash_refs[mm_hash] = refs - 1 + if not cached_ids: + del self.request_cached_ids[req_id] + if not hash_refs: + self.request_hash_refs.pop(req_id, None) # The mm_hash not in cache or the req_id set is empty if not self.cached.get(mm_hash, None): return - if not vllm_version_is("0.32.0"): - # A request that still holds another input with the same mm_hash - # keeps the entry alive (vLLM main's refcounted release fix). - if mm_hash in self.request_hash_refs.get(req_id, ()): - return + # A request that still holds another input with the same mm_hash + # keeps the entry alive (vLLM main's refcounted release fix). + if mm_hash in self.request_hash_refs.get(req_id, ()): + return self.cached[mm_hash].discard(req_id) if self.cached[mm_hash]: return @@ -554,8 +538,7 @@ def reset(self) -> None: """ self.cached.clear() self.request_cached_ids.clear() - if not vllm_version_is("0.32.0"): - self.request_hash_refs.clear() + self.request_hash_refs.clear() self.freeable.clear() self.promoting.clear() self.cpu_get_encoder_mm_hashes.clear() diff --git a/vllm_ascend/models/deepseek_v4/compressor.py b/vllm_ascend/models/deepseek_v4/compressor.py index 3aa7bf9c4275..32ed6166b359 100644 --- a/vllm_ascend/models/deepseek_v4/compressor.py +++ b/vllm_ascend/models/deepseek_v4/compressor.py @@ -28,7 +28,9 @@ import torch from torch import nn -from transformers import DeepseekV2Config, DeepseekV3Config + +# DeepseekV4Config is provided by Transformers on both supported versions. +from transformers import DeepseekV2Config, DeepseekV3Config, DeepseekV4Config from vllm.config import CacheConfig, VllmConfig from vllm.model_executor.layers.layernorm import RMSNorm from vllm.model_executor.layers.linear import ReplicatedLinear @@ -38,17 +40,8 @@ from vllm_ascend.core.kv_cache_interface import AscendSlidingWindowMLASpec from vllm_ascend.device.hardware_profile import HardwareCapability, get_current_hardware_profile -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.device_metadata import DeviceMetadataStage, wait_for_device_metadata -# vLLM #61392 switched DeepseekV4Config to the upstream Transformers class on -# main; the v0.32.0 lane still ships it under -# `vllm.transformers_utils.configs.deepseek_v4`. -if vllm_version_is("0.32.0"): - from vllm.transformers_utils.configs.deepseek_v4 import DeepseekV4Config # type: ignore[import-not-found] -else: - from transformers import DeepseekV4Config - class AscendCompressorStateCache(CompressorStateCache): def __init__( diff --git a/vllm_ascend/models/deepseek_v4/indexer.py b/vllm_ascend/models/deepseek_v4/indexer.py index be3cc3e5354d..2463839d4f71 100644 --- a/vllm_ascend/models/deepseek_v4/indexer.py +++ b/vllm_ascend/models/deepseek_v4/indexer.py @@ -31,7 +31,9 @@ import torch.nn.functional as F import torch_npu from torch import nn -from transformers import DeepseekV2Config, DeepseekV3Config + +# DeepseekV4Config is provided by Transformers on both supported versions. +from transformers import DeepseekV2Config, DeepseekV3Config, DeepseekV4Config from vllm.config import CacheConfig, VllmConfig from vllm.model_executor.layers.linear import ReplicatedLinear from vllm.model_executor.layers.quantization import QuantizationConfig @@ -48,18 +50,9 @@ ) from vllm_ascend.utils import ( npu_stream_switch, - vllm_version_is, ) from vllm_ascend.worker.device_metadata import DeviceMetadataStage, wait_for_device_metadata -# vLLM #61392 switched DeepseekV4Config to the upstream Transformers class on -# main; the v0.32.0 lane still ships it under -# `vllm.transformers_utils.configs.deepseek_v4`. -if vllm_version_is("0.32.0"): - from vllm.transformers_utils.configs.deepseek_v4 import DeepseekV4Config # type: ignore[import-not-found] -else: - from transformers import DeepseekV4Config - def hadamard_linear(x: torch.Tensor, hadamard: torch.Tensor) -> tuple[torch.Tensor, tuple[int, ...], int]: x_shape = x.shape diff --git a/vllm_ascend/models/deepseek_v4/mm_preprocess.py b/vllm_ascend/models/deepseek_v4/mm_preprocess.py index 18bf48cd3d63..64b23b606fd0 100644 --- a/vllm_ascend/models/deepseek_v4/mm_preprocess.py +++ b/vllm_ascend/models/deepseek_v4/mm_preprocess.py @@ -29,7 +29,9 @@ import numpy as np import torch from PIL import Image, ImageOps -from transformers import BatchFeature + +# DeepseekV4Config is provided by Transformers on both supported versions. +from transformers import BatchFeature, DeepseekV4Config from vllm.config.multimodal import BaseDummyOptions, ImageDummyOptions from vllm.inputs import MultiModalDataDict from vllm.multimodal.inputs import MultiModalFieldConfig, MultiModalKwargsItems @@ -47,16 +49,6 @@ PlaceholderFeaturesInfo, ) -from vllm_ascend.utils import vllm_version_is - -# vLLM #61392 switched DeepseekV4Config to the upstream Transformers class on -# main; the v0.32.0 lane still ships it under -# `vllm.transformers_utils.configs.deepseek_v4`. -if vllm_version_is("0.32.0"): - from vllm.transformers_utils.configs.deepseek_v4 import DeepseekV4Config # type: ignore[import-not-found] -else: - from transformers import DeepseekV4Config - IMAGE_START, IMAGE_PAD, IMAGE, IMAGE_NEW_LINE, IMAGE_END = range(5) COMPRESS_PAD_TO = 4 diff --git a/vllm_ascend/models/deepseek_v4/model.py b/vllm_ascend/models/deepseek_v4/model.py index 81959b79123c..ce28d9bd26b3 100644 --- a/vllm_ascend/models/deepseek_v4/model.py +++ b/vllm_ascend/models/deepseek_v4/model.py @@ -32,7 +32,11 @@ import torch.nn.functional as F import vllm.envs as envs from torch import nn -from transformers import DeepseekV2Config, DeepseekV3Config + +# vLLM #61392 switched DeepseekV4Config to the upstream Transformers class on +# main; the v0.33.0 lane still ships it under +# `vllm.transformers_utils.configs.deepseek_v4`. +from transformers import DeepseekV2Config, DeepseekV3Config, DeepseekV4Config from vllm._aiter_ops import rocm_aiter_ops from vllm.compilation.decorators import support_torch_compile from vllm.config import CacheConfig, ParallelConfig, VllmConfig @@ -97,7 +101,6 @@ enable_custom_op, extract_dsv4_layer_index, get_dsv4_compress_ratio, - vllm_version_is, ) from vllm_ascend.worker.v2.pp_transport import ( PPTransportDataType, @@ -108,14 +111,6 @@ make_empty_intermediate_tensors as make_pp_empty_intermediate_tensors, ) -# vLLM #61392 switched DeepseekV4Config to the upstream Transformers class on -# main; the v0.32.0 lane still ships it under -# `vllm.transformers_utils.configs.deepseek_v4`. -if vllm_version_is("0.32.0"): - from vllm.transformers_utils.configs.deepseek_v4 import DeepseekV4Config # type: ignore[import-not-found] -else: - from transformers import DeepseekV4Config - sequence_parallel_chunk = sp_shard @@ -341,8 +336,7 @@ def __init__( # vLLM main folded `num_hash_layers` into the per-layer `mlp_layer_types`; # judge Hash-MoE per layer (it need not be a contiguous prefix) and fall - # back to the legacy count on the v0.32.0 lane, which has no - # `mlp_layer_types`. + # back to the legacy count for checkpoints without `mlp_layer_types`. if is_draft_layer: self.hash = False else: @@ -702,18 +696,17 @@ def __init__( if config is None: config = vllm_config.model_config.hf_config - if not vllm_version_is("0.32.0"): - # vLLM #61392 folded `compress_ratios` into `layer_types`; the - # Ascend helpers and the KV-store metadata still index the legacy - # field, so restore it. - if getattr(config, "compress_ratios", None) is None: - # `vllm.transformers_utils.deepseek_v4_utils` only exists on - # main (added by #61392), so keep the import lazy. - from vllm.transformers_utils.deepseek_v4_utils import get_compress_ratios - - compress_ratios = get_compress_ratios(config) - if compress_ratios: - config.compress_ratios = list(compress_ratios) + # vLLM #61392 folded `compress_ratios` into `layer_types`; the + # Ascend helpers and the KV-store metadata still index the legacy + # field, so restore it. + if getattr(config, "compress_ratios", None) is None: + # `vllm.transformers_utils.deepseek_v4_utils` only exists on + # main (added by #61392), so keep the import lazy. + from vllm.transformers_utils.deepseek_v4_utils import get_compress_ratios + + compress_ratios = get_compress_ratios(config) + if compress_ratios: + config.compress_ratios = list(compress_ratios) cache_config = vllm_config.cache_config quant_config = vllm_config.quant_config parallel_config = vllm_config.parallel_config diff --git a/vllm_ascend/models/deepseek_v41/cache_config.py b/vllm_ascend/models/deepseek_v41/cache_config.py index b737660f8b96..9c6e4497d562 100644 --- a/vllm_ascend/models/deepseek_v41/cache_config.py +++ b/vllm_ascend/models/deepseek_v41/cache_config.py @@ -6,6 +6,9 @@ import torch from vllm.config import VllmConfig + +# Both supported versions expose planning helpers in kv_cache_planning. +from vllm.v1.core.kv_cache_planning import may_override_num_blocks from vllm.v1.kv_cache_interface import ( CircularBufferSpec, KVCacheConfig, @@ -23,14 +26,6 @@ HardwareCapability, get_current_hardware_profile, ) -from vllm_ascend.utils import vllm_version_is - -# vLLM #61183 moved `may_override_num_blocks` to `kv_cache_planning` on main; -# the v0.32.0 lane still ships it in `kv_cache_utils`. -if vllm_version_is("0.32.0"): - from vllm.v1.core.kv_cache_utils import may_override_num_blocks -else: - from vllm.v1.core.kv_cache_planning import may_override_num_blocks STATE_RING_ROWS = 32 diff --git a/vllm_ascend/models/glm5next/cache_config.py b/vllm_ascend/models/glm5next/cache_config.py index d87a64071b25..1cd24fc7cc25 100644 --- a/vllm_ascend/models/glm5next/cache_config.py +++ b/vllm_ascend/models/glm5next/cache_config.py @@ -14,6 +14,12 @@ from vllm.config import VllmConfig from vllm.model_executor.models.utils import extract_layer_index from vllm.utils.torch_utils import get_dtype_size + +# Both supported versions expose planning helpers in kv_cache_planning. +from vllm.v1.core.kv_cache_planning import ( + create_kv_cache_group_specs, + may_override_num_blocks, +) from vllm.v1.kv_cache_interface import ( KVCacheConfig, KVCacheGroupSpec, @@ -30,20 +36,6 @@ get_kv_cache_compression_ratio, get_storage_block_size, ) -from vllm_ascend.utils import vllm_version_is - -# vLLM #61183 moved these helpers to `kv_cache_planning` on main; the v0.32.0 -# lane still ships them in `kv_cache_utils`. -if vllm_version_is("0.32.0"): - from vllm.v1.core.kv_cache_utils import ( - create_kv_cache_group_specs, - may_override_num_blocks, - ) -else: - from vllm.v1.core.kv_cache_planning import ( - create_kv_cache_group_specs, - may_override_num_blocks, - ) @dataclass(frozen=True) diff --git a/vllm_ascend/models/glm5next/kda.py b/vllm_ascend/models/glm5next/kda.py index d68139b4be3b..5283da0bd42d 100644 --- a/vllm_ascend/models/glm5next/kda.py +++ b/vllm_ascend/models/glm5next/kda.py @@ -35,7 +35,6 @@ from vllm_ascend.models.glm5next.recoverssm_config import use_glm_recoverssm from vllm_ascend.ops.gdn_attn_builder import AscendGDNHostMetadataBackend from vllm_ascend.ops.triton.kda.recoverssm import kda_recoverssm_verify -from vllm_ascend.utils import vllm_version_is class Glm5NextGDNHostMetadataBackend(AscendGDNHostMetadataBackend): @@ -217,8 +216,6 @@ def get_state_dtype( self.cache_config.mamba_ssm_cache_dtype, ) if self.use_recoverssm: - if vllm_version_is("0.32.0"): - return MambaStateDtypeCalculator.append_kda_recoverssm_record(dtypes, self.model_config.dtype) # vLLM main moved KDA RecoverSSM records out of the KV cache and # removed the calculator helper, but Ascend still packs the # float32 correction and activation key/gate records into the page. @@ -240,10 +237,6 @@ def get_state_shape( num_spec=self.num_spec, ) if self.use_recoverssm: - if vllm_version_is("0.32.0"): - return MambaStateShapeCalculator.append_kda_recoverssm_record( - shapes, self.num_heads, self.head_dim, self.tp_size, self.num_spec + 1 - ) # One checkpoint per request plus compact update records, matching # the layout the Ascend commit context allocates from. local_num_heads = divide(self.num_heads, self.tp_size) diff --git a/vllm_ascend/models/glm5next/model.py b/vllm_ascend/models/glm5next/model.py index f6aa39299a9e..f5ef283eb020 100644 --- a/vllm_ascend/models/glm5next/model.py +++ b/vllm_ascend/models/glm5next/model.py @@ -80,7 +80,7 @@ from vllm.sequence import IntermediateTensors from vllm.utils.torch_utils import get_kv_cache_torch_dtype -from vllm_ascend.utils import pad_sequence_parallel_tokens, vllm_version_is +from vllm_ascend.utils import pad_sequence_parallel_tokens from .attention import Glm5NextMLAAttention from .kda import Glm5NextLinearAttention, get_kda_parallel_size @@ -775,13 +775,10 @@ def load_weights(self, weights: Iterable[tuple[Any, ...]]) -> set[str]: params_dict = dict(self.named_parameters()) loaded_params: set[str] = set() - if vllm_version_is("0.32.0"): - _pending_wk_fp8: dict = {} - else: - # Reordering loaders can split an FP8 indexer wk weight/scale pair - # across load_weights() calls; keep the pending buffer on the model. - _pending_wk_fp8 = getattr(self, "_pending_indexer_wk_fp8", {}) - self._pending_indexer_wk_fp8 = _pending_wk_fp8 + # Reordering loaders can split an FP8 indexer wk weight/scale pair + # across load_weights() calls; keep the pending buffer on the model. + _pending_wk_fp8 = getattr(self, "_pending_indexer_wk_fp8", {}) + self._pending_indexer_wk_fp8 = _pending_wk_fp8 for args in weights: name, loaded_weight = args[:2] @@ -938,8 +935,6 @@ def get_mamba_state_dtype_from_config( vllm_config.cache_config.mamba_ssm_cache_dtype, ) if use_glm_recoverssm(vllm_config): - if vllm_version_is("0.32.0"): - return MambaStateDtypeCalculator.append_kda_recoverssm_record(dtypes, vllm_config.model_config.dtype) # vLLM main moved KDA RecoverSSM records out of the KV cache and # removed the calculator helper, but Ascend still packs them in. return (*dtypes, torch.float32, get_kv_cache_torch_dtype("auto", vllm_config.model_config.dtype)) @@ -961,10 +956,6 @@ def get_mamba_state_shape_from_config( num_spec=num_spec, ) if use_glm_recoverssm(vllm_config): - if vllm_version_is("0.32.0"): - return MambaStateShapeCalculator.append_kda_recoverssm_record( - shapes, hf_config.linear_num_heads, hf_config.linear_head_dim, tp_size, num_spec + 1 - ) local_num_heads = divide(hf_config.linear_num_heads, tp_size) spec_query_len = num_spec + 1 return ( diff --git a/vllm_ascend/models/glm5next/mtp.py b/vllm_ascend/models/glm5next/mtp.py index cbe741cedb63..59be61df071d 100644 --- a/vllm_ascend/models/glm5next/mtp.py +++ b/vllm_ascend/models/glm5next/mtp.py @@ -27,7 +27,7 @@ from vllm.utils.torch_utils import direct_register_custom_op from vllm_ascend.ops.triton.linearnorm.fused_eh_norm import fused_eh_norm -from vllm_ascend.utils import is_rot_weight_used, vllm_version_is +from vllm_ascend.utils import is_rot_weight_used from .model import ( Glm5NextDecoderLayer, @@ -346,13 +346,10 @@ def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]: params_dict = dict(self.named_parameters()) loaded_params: set[str] = set() - if vllm_version_is("0.32.0"): - _pending_wk_fp8: dict = {} - else: - # Reordering loaders can split an FP8 indexer wk weight/scale pair - # across load_weights() calls; keep the pending buffer on the model. - _pending_wk_fp8 = getattr(self, "_pending_indexer_wk_fp8", {}) - self._pending_indexer_wk_fp8 = _pending_wk_fp8 + # Reordering loaders can split an FP8 indexer wk weight/scale pair + # across load_weights() calls; keep the pending buffer on the model. + _pending_wk_fp8 = getattr(self, "_pending_indexer_wk_fp8", {}) + self._pending_indexer_wk_fp8 = _pending_wk_fp8 for name, loaded_weight in weights: if "rotary_emb.inv_freq" in name: continue diff --git a/vllm_ascend/models/kimi_k3.py b/vllm_ascend/models/kimi_k3.py index 741713d95677..7262c008f635 100644 --- a/vllm_ascend/models/kimi_k3.py +++ b/vllm_ascend/models/kimi_k3.py @@ -91,7 +91,7 @@ from vllm_ascend.ops.kimi_kda import AscendKimiK3DeltaAttention # type: ignore[import-untyped] from vllm_ascend.ops.linear_op import KimiOProjMMReduceScatterOp from vllm_ascend.quantization.methods.w8a8.w8a8_mxfp8 import AscendW8A8MXFP8DynamicLinearMethod -from vllm_ascend.utils import get_rotation_path, is_950, vllm_version_is +from vllm_ascend.utils import get_rotation_path, is_950 from vllm_ascend.worker.v2.pp_transport import ( PPTransportDataType, add_pp_transport_tensors, @@ -929,14 +929,6 @@ def forward( **kwargs, ) -> torch.Tensor | IntermediateTensors | tuple[torch.Tensor, list[torch.Tensor]]: if self.config.attn_res_block_size is None: - if vllm_version_is("0.32.0"): - return super().forward( - input_ids=input_ids, - positions=positions, - intermediate_tensors=intermediate_tensors, - inputs_embeds=inputs_embeds, - **kwargs, - ) return super().forward( input_ids=input_ids, positions=positions, @@ -1131,15 +1123,11 @@ class AscendKimiLinearForCausalLM(UpstreamKimiLinearForCausalLM, KimiMixtureOfEx def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None: nn.Module.__init__(self) - if vllm_version_is("0.32.0"): - # v0.32.0 predates the AMD specialized-decode hooks we inherit. - pass - else: - from vllm.models.kimi_k3.amd.specialized_decode.runtime import ( - specialized_decode_config, - ) + from vllm.models.kimi_k3.amd.specialized_decode.runtime import ( + specialized_decode_config, + ) - self.init_specialized_decode(specialized_decode_config(vllm_config)) + self.init_specialized_decode(specialized_decode_config(vllm_config)) self.model_config = vllm_config.model_config self.vllm_config = vllm_config self.config = self.model_config.hf_config @@ -1177,19 +1165,17 @@ def set_moe_parameters(self) -> None: def set_dspark_aux_capture_materialized(self, enabled: bool) -> None: self.model.dspark_aux_capture_materialized = enabled - if not vllm_version_is("0.32.0"): + def get_model_state_cls(self): + """Use the Ascend hybrid state instead of the inherited ROCm one. - def get_model_state_cls(self): - """Use the Ascend hybrid state instead of the inherited ROCm one. - - vLLM main lets the AMD Kimi class provide its own model state; that - state builds upstream attention metadata, which is invalid on NPU. - """ - from vllm_ascend.worker.v2.model_states.mamba_hybrid import ( - AscendMambaHybridModelState, - ) + vLLM main lets the AMD Kimi class provide its own model state; that + state builds upstream attention metadata, which is invalid on NPU. + """ + from vllm_ascend.worker.v2.model_states.mamba_hybrid import ( + AscendMambaHybridModelState, + ) - return AscendMambaHybridModelState + return AscendMambaHybridModelState class AscendKimiK3MultiModalProjector(KimiK25MultiModalProjector): diff --git a/vllm_ascend/models/qwen4_exp/cpu_length_sync.py b/vllm_ascend/models/qwen4_exp/cpu_length_sync.py index 079a0fe32c47..cb3bc1852573 100644 --- a/vllm_ascend/models/qwen4_exp/cpu_length_sync.py +++ b/vllm_ascend/models/qwen4_exp/cpu_length_sync.py @@ -24,7 +24,7 @@ def can_skip_qwen_cpu_length_sync(runner: Any) -> bool: # main renamed the QSA side-cache module and its builder/backend; the # release tree still ships qsa_cache.py. - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): import vllm.models.qwen4_exp.common.qsa_cache as qsa_cache # type: ignore[import-not-found] QSAIndexerMetadataBuilder = qsa_cache.QSAMetadataBuilder diff --git a/vllm_ascend/models/qwen4_exp/qsa.py b/vllm_ascend/models/qwen4_exp/qsa.py index b2ac62f5221b..2517a687f89e 100644 --- a/vllm_ascend/models/qwen4_exp/qsa.py +++ b/vllm_ascend/models/qwen4_exp/qsa.py @@ -51,7 +51,7 @@ from .gbsa import GBSA_PAGE_SIZE, qsa_gbsa_attention from .lightning_indexer import qsa_select_paged_tokens_lightning -if vllm_version_is("0.32.0"): +if vllm_version_is("0.33.0"): import vllm.models.qwen4_exp.amd.indexer_qsa as upstream_indexer # type: ignore[import-not-found] import vllm.models.qwen4_exp.common.qsa_cache as qsa_indexer # type: ignore[import-not-found] @@ -64,7 +64,7 @@ # The upstream backend class is renamed per tree; the class definition below # carries the resulting valid-type/misc ignores. -if vllm_version_is("0.32.0"): +if vllm_version_is("0.33.0"): UpstreamQSABackend = upstream_qsa.Qwen4ExpQSAFlashAttentionBackend # type: ignore[attr-defined] else: UpstreamQSABackend = upstream_qsa.Qwen4ExpQSABackend # type: ignore[attr-defined] @@ -266,7 +266,7 @@ def normalize_compressed_keys( first_positions, ) - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): def forward( # type: ignore[misc, override] self, @@ -450,7 +450,7 @@ class AscendQSAImpl: supports_dcp = False supports_pcp = False - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): def __init__(self, *args: object, **kwargs: object) -> None: del kwargs @@ -499,7 +499,7 @@ def do_kv_cache_update( _store_qsa_cache_rows(key_cache, slot_mapping, key) _store_qsa_cache_rows(value_cache, slot_mapping, value) - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): def forward_qsa( self, @@ -716,7 +716,7 @@ def supported_kv_cache_layouts(cls) -> tuple[KVCacheLayout, ...]: # structure, cache specifications and weight mapping in upstream vLLM. upstream_indexer.apply_qsa_rope = apply_qsa_rope upstream_qsa.QSAIndexer = AscendQSAIndexer -if vllm_version_is("0.32.0"): +if vllm_version_is("0.33.0"): upstream_qsa.Qwen4ExpQSAFlashAttentionImpl = AscendQSAImpl # type: ignore[attr-defined] upstream_qsa.Qwen4ExpQSAFlashAttentionBackend = AscendQSABackend # type: ignore[attr-defined] else: @@ -784,7 +784,7 @@ def _run_qsa( raise RuntimeError("Fused QSA preparation requires an output gate") gate.copy_(projected_gate.view_as(gate)) - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): selected = cast( torch.Tensor, self.indexer( # type: ignore[call-arg] @@ -817,7 +817,7 @@ def _run_qsa( # name and signature follow the tree's upstream ABI. impl: Any = self.impl with attention_transfer_window(): - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): impl.forward_qsa( self, query, diff --git a/vllm_ascend/observability/runtime_guard/hooks.py b/vllm_ascend/observability/runtime_guard/hooks.py index 29772c0c334c..873a028a47ad 100644 --- a/vllm_ascend/observability/runtime_guard/hooks.py +++ b/vllm_ascend/observability/runtime_guard/hooks.py @@ -41,13 +41,13 @@ from types import SimpleNamespace from typing import Any +from vllm.distributed.kv_transfer.kv_connector.v1.base import KVConnectorOutput from vllm.distributed.parallel_state import get_tp_group from vllm.v1.outputs import AsyncModelRunnerOutput, ModelRunnerOutput from vllm.v1.worker.gpu.async_utils import AsyncOutput from vllm_ascend.logger import init_logger_ascend from vllm_ascend.observability.runtime_guard.processor import SamplePhaseResult -from vllm_ascend.utils import vllm_version_is logger = init_logger_ascend(__name__) @@ -345,12 +345,6 @@ def get_output(self) -> ModelRunnerOutput: _safe_check_after_sample(self._runner, output) return output - # vLLM main makes ``get_kv_connector_output`` abstract on - # ``AsyncModelRunnerOutput``: it salvages the step's KV output when - # ``get_output`` fails. v0.32.0 neither declares nor calls it, so the - # release lane needs no override. - if not vllm_version_is("0.32.0"): - from vllm.distributed.kv_transfer.kv_connector.v1.base import KVConnectorOutput - - def get_kv_connector_output(self) -> KVConnectorOutput | None: - return self._inner.get_kv_connector_output() + # Both supported versions require get_kv_connector_output on async outputs. + def get_kv_connector_output(self) -> KVConnectorOutput | None: + return self._inner.get_kv_connector_output() diff --git a/vllm_ascend/ops/gdn.py b/vllm_ascend/ops/gdn.py index 60a1ec3a6a52..31e0a3ed15a5 100644 --- a/vllm_ascend/ops/gdn.py +++ b/vllm_ascend/ops/gdn.py @@ -51,7 +51,6 @@ from vllm_ascend.ops.triton.fla.utils import clear_ssm_states from vllm_ascend.ops.triton.mamba.causal_conv1d import causal_conv1d_update_varlen, extract_last_width from vllm_ascend.ops.triton.mamba.state_index import gather_ssm_states, scatter_ssm_states_ -from vllm_ascend.utils import vllm_version_is _PACKED_CONV_WEIGHT_NAME = "ascend_conv1d_weight" @@ -90,21 +89,12 @@ def _pack_conv_weights(conv1d: nn.Module) -> None: .to(device=packed_param.device, dtype=packed_param.dtype) .contiguous() ) - # vLLM main (#62326) keeps the parameter object by default and drops - # `prefer_copy`; v0.32.0 still requires `prefer_copy=True`. - if vllm_version_is("0.32.0"): - replace_parameter( - conv1d, - _PACKED_CONV_WEIGHT_NAME, - packed_weight, - prefer_copy=True, - ) - else: - replace_parameter( - conv1d, - _PACKED_CONV_WEIGHT_NAME, - packed_weight, - ) + # replace_parameter preserves the parameter object on both supported versions. + replace_parameter( + conv1d, + _PACKED_CONV_WEIGHT_NAME, + packed_weight, + ) def initialize_packed_conv_weight(layer: nn.Module) -> None: diff --git a/vllm_ascend/ops/gdn_attn_builder.py b/vllm_ascend/ops/gdn_attn_builder.py index 9cd768ff52d3..c9fd78435fdc 100644 --- a/vllm_ascend/ops/gdn_attn_builder.py +++ b/vllm_ascend/ops/gdn_attn_builder.py @@ -40,7 +40,6 @@ prepare_update_chunk_offsets, ) from vllm_ascend.ops.triton.mamba.gdn_prepare import prepare_gdn -from vllm_ascend.utils import vllm_version_is _GDN_CHUNK_SIZE = 64 # Keep this aligned with solve_tril.LARGE_BLOCK_T in ops/triton/fla/solve_tril.py. @@ -835,16 +834,8 @@ def build( # type: ignore[override] query_start_loc_cpu = m.query_start_loc_cpu mamba_cache_mode = self.vllm_config.cache_config.mamba_cache_mode mamba_block_table = m.block_table_tensor - # vLLM #58737 derives num_reqs from the block table and asserts that - # seq_lens has the same number of rows. Ascend's unpadded() intentionally - # keeps the padded block-table rows, so on vLLM main pass only the real - # request rows. v0.32.0's align path already derives its output rows from - # seq_lens, so the result is unchanged there. - if ( - not vllm_version_is("0.32.0") - and mamba_cache_mode != "none" - and mamba_block_table.shape[0] != m.seq_lens.shape[0] - ): + # Restrict recurrent state lookup to real request rows. + if mamba_cache_mode != "none" and mamba_block_table.shape[0] != m.seq_lens.shape[0]: mamba_block_table = mamba_block_table[: m.seq_lens.shape[0]] block_table_tensor = mamba_get_block_table_tensor( mamba_block_table, diff --git a/vllm_ascend/ops/kimi_kda.py b/vllm_ascend/ops/kimi_kda.py index 1d94f4a13323..40f25667030e 100644 --- a/vllm_ascend/ops/kimi_kda.py +++ b/vllm_ascend/ops/kimi_kda.py @@ -42,7 +42,7 @@ from vllm_ascend.quantization.methods.w8a8.w8a8_mxfp8 import ( AscendW8A8MXFP8DynamicLinearMethod, ) -from vllm_ascend.utils import npu_stream_switch, vllm_version_is +from vllm_ascend.utils import npu_stream_switch _PACKED_CONV_WEIGHT_NAME = "ascend_conv1d_weight" _F_PROJ_SHARD_ID = 1 @@ -435,21 +435,12 @@ def _pack_conv_weights(self) -> None: .to(device=packed_param.device, dtype=packed_param.dtype) .contiguous() ) - # vLLM main (#62326) keeps the parameter object by default and drops - # `prefer_copy`; v0.32.0 still requires `prefer_copy=True`. - if vllm_version_is("0.32.0"): - replace_parameter( - self, - _PACKED_CONV_WEIGHT_NAME, - packed_weight, - prefer_copy=True, - ) - else: - replace_parameter( - self, - _PACKED_CONV_WEIGHT_NAME, - packed_weight, - ) + # replace_parameter preserves the parameter object on both supported versions. + replace_parameter( + self, + _PACKED_CONV_WEIGHT_NAME, + packed_weight, + ) def _run_recurrent( self, diff --git a/vllm_ascend/ops/kimi_mla.py b/vllm_ascend/ops/kimi_mla.py index e3293011196a..45d1b76c84df 100644 --- a/vllm_ascend/ops/kimi_mla.py +++ b/vllm_ascend/ops/kimi_mla.py @@ -15,7 +15,7 @@ class AscendKimiK3MultiHeadLatentAttention(AscendMultiHeadLatentAttention, KimiK so Python runs the Ascend initializer on the replacement instance. """ - if not vllm_version_is("0.32.0"): + if not vllm_version_is("0.33.0"): # vLLM #60110 added this flag and reads it in the upstream # process_weights_after_loading hook. The AMD initializer never runs on # Ascend, so expose the fold as disabled. diff --git a/vllm_ascend/ops/linear.py b/vllm_ascend/ops/linear.py index 0f26ee9404a7..625965909aaa 100644 --- a/vllm_ascend/ops/linear.py +++ b/vllm_ascend/ops/linear.py @@ -42,7 +42,7 @@ from vllm_ascend.device.hardware_profile import HardwareCapability, WeightLayoutPolicy, get_current_hardware_profile from vllm_ascend.ops.linear_op import get_parallel_op, get_replicated_op -from vllm_ascend.utils import maybe_trans_nz, vllm_version_is +from vllm_ascend.utils import maybe_trans_nz from vllm_ascend.weight_switch import WeightSwitchGatherSpec, WeightSwitchMixin @@ -115,10 +115,7 @@ def process_weights_after_loading(self, layer: torch.nn.Module) -> None: # keep the captured graph's weight reference to the updated weight # during RL weight updates. vLLM main (#62326) dropped `prefer_copy` # and keeps the parameter object by default. - if vllm_version_is("0.32.0"): - replace_parameter(layer, "weight_fp32", new_fp32, prefer_copy=True) - else: - replace_parameter(layer, "weight_fp32", new_fp32) + replace_parameter(layer, "weight_fp32", new_fp32) if "conv1d" not in layer.prefix and not skip_weight_nz_conversion: # 310P torch_npu rejects FRACTAL_NZ matmul when the weight-side # matrix has n=1 or k=1. Keep scalar gates such as Qwen MoE's diff --git a/vllm_ascend/ops/triton/docs/prepare_dflash_inputs.md b/vllm_ascend/ops/triton/docs/prepare_dflash_inputs.md index d73d3b4f964f..723f921a8eb4 100644 --- a/vllm_ascend/ops/triton/docs/prepare_dflash_inputs.md +++ b/vllm_ascend/ops/triton/docs/prepare_dflash_inputs.md @@ -3,13 +3,13 @@ ## Description - **Function**: Prepares the metadata and fixed-capacity buffers required by DFlash speculative decoding on Ascend NPU. For each request, the operator converts the current target-model token span into draft-model context KV positions/slots, constructs the next DFlash query tokens and query slots, builds sampling mappings, copies per-request sampling state, and pads graph-visible buffers. -- **Supported vLLM ABI**: vLLM 0.32.0 `prepare_dflash_inputs`, including +- **Supported vLLM ABI**: vLLM 0.33.0 `prepare_dflash_inputs`, including `cp_rank`, `cp_size`, and `cp_interleave` for rank-local DCP KV slots. - **Implementation**: - `vllm_ascend/ops/triton/spec_decode/prepare_dflash_inputs.py` contains the 2-D Triton kernel and launcher `prepare_dflash_inputs_triton`. - `vllm_ascend/worker/v2/spec_decode/dflash/speculator.py` provides the - vLLM 0.32.0 `prepare_dflash_inputs` wrapper. + vLLM 0.33.0 `prepare_dflash_inputs` wrapper. - **Formula**: - Request context range: `ctx_start = query_start_loc[req]`, @@ -97,7 +97,7 @@ ## Constraints - The operator is inference-only and requires Ascend NPU Triton execution. -- The optimized kernel implements the vLLM 0.32.0 DFlash ABI and the same +- The optimized kernel implements the vLLM 0.33.0 DFlash ABI and the same rank-local DCP slot mapping as main's scalar implementation. - Multimodal inputs (including M-RoPE positions) are not supported by this optimized path. It derives KV slots from scalar token positions; multimodal inputs require the target slot mapping and linear token indices (see [#9340](https://github.com/vllm-project/vllm-ascend/pull/9340)). - `input_batch.num_reqs > 0` and `input_batch.num_reqs <= max_num_reqs`. @@ -118,7 +118,7 @@ ## Upstream Compatibility -The worker wrapper preserves the vLLM 0.32.0 positional signature and forwards +The worker wrapper preserves the vLLM 0.33.0 positional signature and forwards DFlash and DCP inputs to the optimized 2-D launcher. The Ascend speculator binds `kv_cache_block_size` from `self.vllm_config.cache_config.block_size` when setting attention and passes it as a keyword-only argument. Multimodal diff --git a/vllm_ascend/ops/triton/sample/categorical_sample.py b/vllm_ascend/ops/triton/sample/categorical_sample.py index 972a5df47585..673d2e07b54f 100644 --- a/vllm_ascend/ops/triton/sample/categorical_sample.py +++ b/vllm_ascend/ops/triton/sample/categorical_sample.py @@ -425,7 +425,7 @@ def _categorical_sample_main( logits_cache_source: torch.Tensor | None = None, logits_cache_row_mapping: torch.Tensor | None = None, ) -> torch.Tensor: - # 0.32.0 has `logits_cache_source` (only watermarking supplies a separate + # 0.33.0 has `logits_cache_source` (only watermarking supplies a separate # source); main adds the per-row mapping for batch-sharded caches. The NPU # kernels support neither. if logits_cache_row_mapping is not None: diff --git a/vllm_ascend/patch/__init__.py b/vllm_ascend/patch/__init__.py index 40a3f139038a..66dce0e664bb 100644 --- a/vllm_ascend/patch/__init__.py +++ b/vllm_ascend/patch/__init__.py @@ -217,7 +217,7 @@ # Why: # GLM-5.3 always generates reasoning. This compatibility fallback # normalizes thinking=False and enable_thinking=False to prevent -# reasoning from leaking into content; v0.32.0 also handles this +# reasoning from leaking into content; v0.33.0 also handles this # upstream through PR #56994. # How: # Detect the GLM-5.3 template using the upstream signature and normalize @@ -258,9 +258,8 @@ # vLLM #44243 has landed in the supported upstream version, so this # override is kept only for the drop exemption of entry 2; remove it # together with entry 2 once upstream exposes the PD role. -# 2. `get_kv_cache_config_from_groups` (in `vllm.v1.core.kv_cache_utils` on -# v0.32.0; moved to `vllm.v1.core.kv_cache_planning` on main by vLLM -# #61183), +# 2. `get_kv_cache_config_from_groups` (in `vllm.v1.core.kv_cache_planning` +# on both supported versions, vLLM #61183), # `HybridKVCacheCoordinator.find_longest_cache_hit` and # `...find_longest_cache_hit_per_group` # Why: @@ -301,22 +300,17 @@ # Future Plan: # Remove this patch once upstream vLLM supports hybrid KV cache + CP for # non-CUDA backends, or exposes a platform hook for this behavior. -# 2. `vllm.v1.core.kv_cache_utils.get_kv_cache_groups`, -# `...get_kv_cache_config_from_groups`, +# 2. `vllm.v1.core.kv_cache_planning.get_kv_cache_config_from_groups`, # `..._max_memory_usage_bytes_from_groups`, `..._pool_bytes_per_block` # Why: -# The v0.32.0 release lane has no pluggable `KVCacheConfigBuilder`, so -# the Ascend DSV4/DSV4.1, GLM-Next, Kimi-K3 DSpark, and TurboQuant -# planning rules must stay module-level monkey patches there. +# Ascend cache layouts need platform-specific materialization and memory +# accounting. # How: -# Keep the planning patches applied from this file. Main resolves -# grouping through `vllm_ascend.core.kv_cache_config_builder`, selected -# by `NPUPlatform.get_kv_cache_config_builder_cls`; its default -# materialization delegates back to these patched functions. -# Related PR (if no, explain why): +# Both supported versions select AscendKVCacheConfigBuilder through +# NPUPlatform. Its default materialization delegates to the patched +# planning functions. +# Related PR: # https://github.com/vllm-project/vllm/pull/53558 -# Future Plan: -# Remove them when vllm-ascend stops supporting v0.32.0. # # ** 11. File: platform/patch_mamba_block_aligned_split.py** # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -729,7 +723,7 @@ # # 3. `xgrammar.GrammarCompiler.compile_json_schema` # Why: -# vLLM #58067 (included in v0.32.0 and verified main) passes +# vLLM #58067 (included in v0.33.0 and verified main) passes # `separators=(",", ":")` when `disable_any_whitespace` is set. The # xgrammar releases shipped with Ascend (0.2.7/0.2.8) mishandle it: the # stricter grammar makes small models loop on `","` until `max_tokens` @@ -1132,22 +1126,9 @@ # fused attention preparation. # # -# ** 11. File: worker/patch_mm_input_norm.py ** -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# 1. `vllm.model_executor.layers.fusion.mm_input_norm.FusedMMInputNorm` -# Why: -# v0.32.0 persists processor-derived normalization buffers, so legacy -# sharded checkpoints fail with missing visual.input_norm.weight/bias. -# Dummy loading can also overwrite these constants. -# How: -# Wrap construction once and register weight/bias as nonpersistent -# buffers, preserving device normalization and strict weight validation. -# Applying this on upstream main with the fix retains the same behavior. -# Related PR: -# https://github.com/vllm-project/vllm/pull/62767 -# Future Plan: -# Remove when all supported vLLM baselines contain commit -# 90c4a1a73eecea0428ee4303ad96c9fdeaac3f80 (or an equivalent backport). +# ** 11. File: worker/patch_mm_input_norm.py (removed) ** +# Both vLLM v0.33.0 and verified main include #62767 and keep the +# processor-derived normalization buffers nonpersistent. # # ** 12. File: worker/patch_ascend_ops.py** # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/vllm_ascend/patch/platform/__init__.py b/vllm_ascend/patch/platform/__init__.py index 52be23ec8d4c..504835973ba3 100644 --- a/vllm_ascend/patch/platform/__init__.py +++ b/vllm_ascend/patch/platform/__init__.py @@ -79,8 +79,7 @@ # # ** File: platform/patch_kv_cache_utils.py ** # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# 1. `vllm.v1.core.kv_cache_utils` (v0.32.0) / -# `vllm.v1.core.kv_cache_planning` (main, vLLM #61183) +# 1. `vllm.v1.core.kv_cache_planning` (both supported versions, vLLM #61183) # Why: # vLLM's generic KV-cache planner cannot represent GLM-Next's cache # topology, where MLA and compressed indexer caches share block IDs while @@ -95,12 +94,10 @@ # Remove this patch when upstream's generic KV-cache layout supports the # Ascend GLM-Next cache topology. # -# On main, Ascend grouping and pool accounting live in -# `vllm_ascend.core.kv_cache_config_builder`, which the platform selects -# through `NPUPlatform.get_kv_cache_config_builder_cls`; its default -# materialization delegates back to the patched planning functions -# applied by this file. The v0.32.0 lane, which has no pluggable -# builder, applies the same rules directly from this file. +# On both supported versions, Ascend grouping and pool accounting live +# in AscendKVCacheConfigBuilder, which the platform selects through +# NPUPlatform.get_kv_cache_config_builder_cls. Its default materialization +# delegates to the patched planning functions in this file. # # ** File: platform/patch_mamba_config.py ** # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/vllm_ascend/patch/platform/patch_balance_schedule.py b/vllm_ascend/patch/platform/patch_balance_schedule.py index 88c4a306ffd3..5ddd915d109d 100644 --- a/vllm_ascend/patch/platform/patch_balance_schedule.py +++ b/vllm_ascend/patch/platform/patch_balance_schedule.py @@ -78,7 +78,6 @@ from vllm.v1.utils import record_function_or_nullcontext from vllm_ascend.ascend_config import init_ascend_config -from vllm_ascend.utils import vllm_version_is def _balance_scheduling_enabled(vllm_config) -> bool: @@ -346,9 +345,7 @@ def schedule(self, throttle_prefills: bool = False) -> SchedulerOutput: break if new_blocks is None: - if not vllm_version_is("0.32.0") and ( - self.policy == SchedulingPolicy.PRIORITY and request.status == RequestStatus.PREEMPTED - ): + if self.policy == SchedulingPolicy.PRIORITY and request.status == RequestStatus.PREEMPTED: # The request was the lowest-priority running request and # preempted itself. The requests after it have higher # priority and may still fit; it was removed from diff --git a/vllm_ascend/patch/platform/patch_kv_cache_coordinator.py b/vllm_ascend/patch/platform/patch_kv_cache_coordinator.py index d7a99ffd773a..a0b8e5d1f8e3 100644 --- a/vllm_ascend/patch/platform/patch_kv_cache_coordinator.py +++ b/vllm_ascend/patch/platform/patch_kv_cache_coordinator.py @@ -35,7 +35,6 @@ ) from vllm_ascend.core.kv_cache_interface import is_prefix_cacheable -from vllm_ascend.utils import vllm_version_is _orig_get_kv_cache_coordinator = vllm.v1.core.kv_cache_coordinator.get_kv_cache_coordinator @@ -151,23 +150,14 @@ def __init__( # type: ignore[misc] self.scheduler_block_size, kv_cache_config, ) - if vllm_version_is("0.32.0"): - self.block_pool = BlockPool( - num_gpu_blocks=kv_cache_config.num_blocks, - enable_caching=enable_caching, - hash_block_size=hash_block_size, - enable_kv_cache_events=enable_kv_cache_events, - metrics_collector=metrics_collector, - ) - else: - self.block_pool = BlockPool( - num_gpu_blocks=kv_cache_config.num_blocks, - enable_caching=enable_caching, - hash_block_size=hash_block_size, - enable_kv_cache_events=enable_kv_cache_events, - metrics_collector=metrics_collector, - num_hash_lookahead_tokens=num_hash_lookahead_tokens, - ) + self.block_pool = BlockPool( + num_gpu_blocks=kv_cache_config.num_blocks, + enable_caching=enable_caching, + hash_block_size=hash_block_size, + enable_kv_cache_events=enable_kv_cache_events, + metrics_collector=metrics_collector, + num_hash_lookahead_tokens=num_hash_lookahead_tokens, + ) # KV cache group indices that get the EAGLE last-block drop. self.eagle_group_ids: set[int] = { # type: ignore[no-redef] @@ -185,8 +175,7 @@ def __init__( # type: ignore[misc] } # vLLM main (#61589) reads this base-class attribute in cache_blocks(); # lookahead hashes clear the drop while keeping the groups flagged. - if not vllm_version_is("0.32.0"): - self.drop_eagle_group_ids = self.eagle_group_ids if use_eagle else set() + self.drop_eagle_group_ids = self.eagle_group_ids if use_eagle else set() extra_mgr_kwargs: dict = {"scheduler_block_size": scheduler_block_size} extra_mgr_kwargs["needs_kv_cache_zeroing"] = kv_cache_config.needs_kv_cache_zeroing @@ -588,10 +577,8 @@ def get_kv_cache_coordinator( # type: ignore[misc] orig_kwargs["scheduler_block_size"] = scheduler_block_size orig_kwargs["num_prefill_lookahead"] = num_prefill_lookahead orig_kwargs["allow_partial_hash_hits"] = allow_partial_hash_hits - # vLLM main (#61589) added lookahead block hashes; v0.32.0's upstream - # coordinator has no such parameter. - if not vllm_version_is("0.32.0"): - orig_kwargs["num_hash_lookahead_tokens"] = num_hash_lookahead_tokens + # Both supported versions accept lookahead hash tokens. + orig_kwargs["num_hash_lookahead_tokens"] = num_hash_lookahead_tokens return _orig_get_kv_cache_coordinator(**orig_kwargs) return AscendHybridKVCacheCoordinator(**hybrid_kwargs) # type: ignore[call-arg] diff --git a/vllm_ascend/patch/platform/patch_kv_cache_utils.py b/vllm_ascend/patch/platform/patch_kv_cache_utils.py index 48c83e03922b..740847f28acf 100644 --- a/vllm_ascend/patch/platform/patch_kv_cache_utils.py +++ b/vllm_ascend/patch/platform/patch_kv_cache_utils.py @@ -6,10 +6,13 @@ from dataclasses import replace from typing import Any +# Both supported versions use the KV-cache planner and builder API from #61183/#42309. +import vllm.v1.core.kv_cache_planning as _kv_cache_planning import vllm.v1.core.kv_cache_utils from vllm.config import VllmConfig from vllm.logger import logger from vllm.utils.math_utils import cdiv, round_up +from vllm.v1.core.kv_cache_planning import _approximate_gcd, may_override_num_blocks from vllm.v1.kv_cache_interface import ( FullAttentionSpec, KVCacheConfig, @@ -52,17 +55,6 @@ from vllm_ascend.quantization.methods.kv_cache.turboquant import cache as tq_cache from vllm_ascend.utils import vllm_version_is -# vLLM #61183 moved the KV-cache planning helpers out of -# `vllm.v1.core.kv_cache_utils` into `vllm.v1.core.kv_cache_planning` on main. -# The v0.32.0 lane still ships them in `kv_cache_utils`, so resolve the live -# module by version and import/patch the planning symbols from there. -if vllm_version_is("0.32.0"): - import vllm.v1.core.kv_cache_utils as _kv_cache_planning - from vllm.v1.core.kv_cache_utils import _approximate_gcd, may_override_num_blocks -else: - import vllm.v1.core.kv_cache_planning as _kv_cache_planning - from vllm.v1.core.kv_cache_planning import _approximate_gcd, may_override_num_blocks - _KIMI_K3_TARGET_LAYER_PREFIX = "language_model.model.layers." _KIMI_K3_DRAFT_LAYER_PREFIX = "model.layers." _orig_resolve_kv_cache_block_sizes = vllm.v1.core.kv_cache_utils.resolve_kv_cache_block_sizes @@ -496,23 +488,6 @@ def _ascend_get_packed_kv_cache_groups( assert _orig_get_packed_kv_cache_groups is not None return _orig_get_packed_kv_cache_groups(vllm_config, kv_cache_spec) groups = _get_kv_cache_groups_uniform_groups(grouped_specs) - # The v0.32.0 lane annotates EAGLE groups on this packed hook, because - # ``get_kv_cache_groups`` returns packed groups before running its own - # annotation. vLLM #42309 drops ``_annotate_eagle_groups``/ - # ``_uses_trailing_mtp_layers`` from main and inlines the annotation into - # ``get_kv_cache_configs`` keyed on ``spec.is_draft``, so only call the API - # on the release lane. - if vllm_version_is("0.32.0"): - _kv_cache_planning._annotate_eagle_groups( - vllm_config, - kv_cache_spec, - groups, - use_trailing_layer_fallback=_kv_cache_planning._uses_trailing_mtp_layers(vllm_config), - ) - _kv_cache_planning._warn_if_unannotated_eagle_mamba( - vllm_config, - groups, - ) return groups @@ -672,85 +647,36 @@ def _ascend_pool_bytes_per_block( # type: ignore[misc] return sum(page_sizes) * num_layer_tuples -# vLLM #42309 threads the platform's ``KVCacheConfigBuilder`` through KV cache -# admission on main, so ``_max_memory_usage_bytes_from_groups`` gained a leading -# ``builder`` argument. The v0.32.0 lane keeps the pre-#42309 two-argument -# signature. -if vllm_version_is("0.32.0"): - - def _ascend_max_memory_usage_bytes_from_groups( - vllm_config: VllmConfig, - kv_cache_groups: list[KVCacheGroupSpec], - ) -> int: - """Keep the pre-#51718 DSV4 admission formula for its shared tuples.""" - if tq_cache.uses_turboquant_groups(kv_cache_groups): - return tq_cache.max_memory_usage(vllm_config, kv_cache_groups) - if _get_glm5_next_cache_layout(kv_cache_groups) is not None: - return get_glm5_next_max_memory_usage(vllm_config, kv_cache_groups) - qwen_bytes = get_qwen4_exp_max_memory_usage(vllm_config, kv_cache_groups) - if qwen_bytes is not None: - return qwen_bytes - if not _is_deepseek_v4_groups(kv_cache_groups): - return _orig_max_memory_usage_bytes_from_groups(vllm_config, kv_cache_groups) - - assert all(isinstance(group.kv_cache_spec, UniformTypeKVCacheSpecs) for group in kv_cache_groups) - full_mla_spec = kv_cache_groups[0].kv_cache_spec - assert isinstance(full_mla_spec, UniformTypeKVCacheSpecs) - layer_tuple_bytes = sum(_page_sizes(full_mla_spec)) - num_layer_tuples = max( - _get_max_layers_per_page_size(group.kv_cache_spec) - for group in kv_cache_groups - if isinstance(group.kv_cache_spec, UniformTypeKVCacheSpecs) - ) - return sum( - num_layer_tuples * group.kv_cache_spec.max_memory_usage_pages(vllm_config) * layer_tuple_bytes - for group in kv_cache_groups - if isinstance(group.kv_cache_spec, UniformTypeKVCacheSpecs) - ) - -else: - - def _ascend_max_memory_usage_bytes_from_groups(*args: Any) -> int: # type: ignore[misc] - """Keep the pre-#51718 DSV4 admission formula for its shared tuples. +def _ascend_max_memory_usage_bytes_from_groups( + builder: Any, + vllm_config: VllmConfig, + kv_cache_groups: list[KVCacheGroupSpec], +) -> int: + """Keep Ascend admission accounting with the upstream builder API.""" + if tq_cache.uses_turboquant_groups(kv_cache_groups): + return tq_cache.max_memory_usage(vllm_config, kv_cache_groups) + if _get_glm5_next_cache_layout(kv_cache_groups) is not None: + return get_glm5_next_max_memory_usage(vllm_config, kv_cache_groups) + qwen_bytes = get_qwen4_exp_max_memory_usage(vllm_config, kv_cache_groups) + if qwen_bytes is not None: + return qwen_bytes + if not _is_deepseek_v4_groups(kv_cache_groups): + return _orig_max_memory_usage_bytes_from_groups(builder, vllm_config, kv_cache_groups) - vLLM #42309 threads a ``KVCacheConfigBuilder`` through KV cache - admission on main, so the call becomes - ``(builder, vllm_config, kv_cache_groups)``, while main checkouts - predating #42309 still call ``(vllm_config, kv_cache_groups)``. - ``vllm_version_is`` cannot separate two main dev builds, so dispatch on - the argument count. - """ - if len(args) == 3: - builder, vllm_config, kv_cache_groups = args - else: - builder = None - vllm_config, kv_cache_groups = args - if tq_cache.uses_turboquant_groups(kv_cache_groups): - return tq_cache.max_memory_usage(vllm_config, kv_cache_groups) - if _get_glm5_next_cache_layout(kv_cache_groups) is not None: - return get_glm5_next_max_memory_usage(vllm_config, kv_cache_groups) - qwen_bytes = get_qwen4_exp_max_memory_usage(vllm_config, kv_cache_groups) - if qwen_bytes is not None: - return qwen_bytes - if not _is_deepseek_v4_groups(kv_cache_groups): - if builder is None: - return _orig_max_memory_usage_bytes_from_groups(vllm_config, kv_cache_groups) - return _orig_max_memory_usage_bytes_from_groups(builder, vllm_config, kv_cache_groups) - - assert all(isinstance(group.kv_cache_spec, UniformTypeKVCacheSpecs) for group in kv_cache_groups) - full_mla_spec = kv_cache_groups[0].kv_cache_spec - assert isinstance(full_mla_spec, UniformTypeKVCacheSpecs) - layer_tuple_bytes = sum(_page_sizes(full_mla_spec)) - num_layer_tuples = max( - _get_max_layers_per_page_size(group.kv_cache_spec) - for group in kv_cache_groups - if isinstance(group.kv_cache_spec, UniformTypeKVCacheSpecs) - ) - return sum( - num_layer_tuples * group.kv_cache_spec.max_memory_usage_pages(vllm_config) * layer_tuple_bytes - for group in kv_cache_groups - if isinstance(group.kv_cache_spec, UniformTypeKVCacheSpecs) - ) + assert all(isinstance(group.kv_cache_spec, UniformTypeKVCacheSpecs) for group in kv_cache_groups) + full_mla_spec = kv_cache_groups[0].kv_cache_spec + assert isinstance(full_mla_spec, UniformTypeKVCacheSpecs) + layer_tuple_bytes = sum(_page_sizes(full_mla_spec)) + num_layer_tuples = max( + _get_max_layers_per_page_size(group.kv_cache_spec) + for group in kv_cache_groups + if isinstance(group.kv_cache_spec, UniformTypeKVCacheSpecs) + ) + return sum( + num_layer_tuples * group.kv_cache_spec.max_memory_usage_pages(vllm_config) * layer_tuple_bytes + for group in kv_cache_groups + if isinstance(group.kv_cache_spec, UniformTypeKVCacheSpecs) + ) def _get_ascend_kv_cache_groups( diff --git a/vllm_ascend/patch/platform/patch_pp_mtp.py b/vllm_ascend/patch/platform/patch_pp_mtp.py index a784fd775ebd..222481ee9f28 100644 --- a/vllm_ascend/patch/platform/patch_pp_mtp.py +++ b/vllm_ascend/patch/platform/patch_pp_mtp.py @@ -228,7 +228,7 @@ def _update_pp_mtp_spec_token_ids(scheduler, scheduler_output, model_runner_outp request.spec_token_ids = [] continue - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): validated = scheduler.structured_output_manager.validate_tokens(request, spec_token_ids[req_index]) else: validated = scheduler.structured_output_manager.trim_spec_tokens(request, spec_token_ids[req_index]) diff --git a/vllm_ascend/patch/platform/patch_speculative_config.py b/vllm_ascend/patch/platform/patch_speculative_config.py index 6bfe6a33de36..7fb7cad3eb99 100644 --- a/vllm_ascend/patch/platform/patch_speculative_config.py +++ b/vllm_ascend/patch/platform/patch_speculative_config.py @@ -10,7 +10,7 @@ from vllm.config.speculative import SpeculativeConfig from vllm.transformers_utils.configs.speculators import SpeculatorsConfig -from vllm_ascend.utils import is_deepseek_v41, is_gqa_pcp_dcp_config, vllm_version_is +from vllm_ascend.utils import is_deepseek_v41, is_gqa_pcp_dcp_config _orig_post_init = SpeculativeConfig.__post_init__ _orig_hf_config_override = SpeculativeConfig.hf_config_override @@ -87,7 +87,7 @@ def _normalize_legacy_qwen3_dspark_config( hf_config: PretrainedConfig, transformers_mtp_overrides: dict[str, Any] | None = None, ) -> PretrainedConfig: - if not vllm_version_is("0.32.0") and transformers_mtp_overrides is not None: + if transformers_mtp_overrides is not None: # The Transformers MTP draft is built from the target config: upstream # applies the overrides and none of the checkpoint rewrites below apply. return _orig_hf_config_override( # type: ignore[call-arg] diff --git a/vllm_ascend/patch/platform/patch_structured_output.py b/vllm_ascend/patch/platform/patch_structured_output.py index c78c366d1555..46ad417c8260 100644 --- a/vllm_ascend/patch/platform/patch_structured_output.py +++ b/vllm_ascend/patch/platform/patch_structured_output.py @@ -163,7 +163,7 @@ def accept_tokens(self: Any, request_id: str, tokens: list[int]) -> bool: def _patch_xgrammar_disable_any_whitespace() -> None: """Ignore xgrammar's ``separators`` argument on both supported vLLM lanes. - vLLM #58067 (present in v0.32.0 and verified main) passes + vLLM #58067 (present in v0.33.0 and verified main) passes ``separators=(",", ":")`` to ``GrammarCompiler.compile_json_schema`` when ``disable_any_whitespace`` is set. The xgrammar releases shipped with Ascend (0.2.7/0.2.8) mishandle it: the resulting grammar lets small models @@ -198,5 +198,5 @@ def compile_json_schema(self: Any, schema: Any, *args: Any, **kwargs: Any) -> An _patch_sampling_params_validation() _patch_structured_output_manager() _patch_outlines_accept_tokens() -# vLLM #58067 is present in both v0.32.0 and verified main. +# vLLM #58067 is present in both v0.33.0 and verified main. _patch_xgrammar_disable_any_whitespace() diff --git a/vllm_ascend/patch/worker/__init__.py b/vllm_ascend/patch/worker/__init__.py index 26e6ce567ea0..3b99659ddaa2 100644 --- a/vllm_ascend/patch/worker/__init__.py +++ b/vllm_ascend/patch/worker/__init__.py @@ -33,7 +33,6 @@ import vllm_ascend.patch.worker.patch_kv_cache_dtype # noqa # Apply before model construction on every device, including 310P. -import vllm_ascend.patch.worker.patch_mm_input_norm # noqa import vllm_ascend.patch.worker.patch_distributed # noqa import vllm_ascend.patch.worker.patch_minimax_m2 # noqa diff --git a/vllm_ascend/patch/worker/patch_attn_utils.py b/vllm_ascend/patch/worker/patch_attn_utils.py index fed8ac8d504a..53ba569016e0 100644 --- a/vllm_ascend/patch/worker/patch_attn_utils.py +++ b/vllm_ascend/patch/worker/patch_attn_utils.py @@ -27,10 +27,10 @@ def _get_ascend_sfa_indexer_backend(_self): # vLLM main (#63384) moved OLMoE to the Transformers backend, whose -# `vllm_attention_forward` bakes a layout-dependent `aten.view`. v0.32.0 still +# `vllm_attention_forward` bakes a layout-dependent `aten.view`. v0.33.0 still # uses the native OLMoE implementation, where this mismatch cannot happen, so # the release lane gets none of this patch. -if not vllm_version_is("0.32.0"): +if not vllm_version_is("0.33.0"): _VLLM_ATTENTION_IMPL = "vllm" @cache diff --git a/vllm_ascend/patch/worker/patch_distributed.py b/vllm_ascend/patch/worker/patch_distributed.py index b6bc4bae8560..b1d31947207e 100644 --- a/vllm_ascend/patch/worker/patch_distributed.py +++ b/vllm_ascend/patch/worker/patch_distributed.py @@ -27,7 +27,7 @@ from vllm_ascend.distributed.device_communicators.npu_communicator import NPUCommunicator from vllm_ascend.patch.worker._hccl_pg_registry import HcclPgKey, HcclPgRegistry, make_hccl_pg_key -from vllm_ascend.utils import create_hccl_pg_options, vllm_version_is +from vllm_ascend.utils import create_hccl_pg_options _HCCL_PG_REGISTRY = HcclPgRegistry() logger = logging.getLogger(__name__) @@ -121,8 +121,7 @@ def __init__( # type: ignore[misc] self.torch_distributed_backend = torch_distributed_backend # vLLM main keeps the CPU group timeout for cpu_all_reduce_; this patch # reimplements GroupCoordinator.__init__ without calling super(). - if not vllm_version_is("0.32.0"): - self.cpu_timeout = get_cpu_distributed_timeout_or_none() + self.cpu_timeout = get_cpu_distributed_timeout_or_none() self._acquired_hccl_keys: list[HcclPgKey] = [] # type: ignore[no-redef] self._unshared_hccl_groups: list[object] = [] # type: ignore[no-redef] self.use_device_communicator = use_device_communicator diff --git a/vllm_ascend/patch/worker/patch_kimi_k25.py b/vllm_ascend/patch/worker/patch_kimi_k25.py index da363ae7a0be..0c72e3401d12 100644 --- a/vllm_ascend/patch/worker/patch_kimi_k25.py +++ b/vllm_ascend/patch/worker/patch_kimi_k25.py @@ -26,8 +26,8 @@ from vllm_ascend.device.hardware_profile import HardwareCapability, get_current_hardware_profile from vllm_ascend.utils import vllm_version_is -if vllm_version_is("0.32.0"): - # 0.32.0 decorates its torch-compiled `get_rope_shape` with a first-call +if vllm_version_is("0.33.0"): + # 0.33.0 decorates its torch-compiled `get_rope_shape` with a first-call # warmup; main removed both the decorator and the compile wrapper. import vllm.model_executor.models.kimi_k25_vit as kimi_k25_vit # type: ignore[import-not-found] @@ -47,7 +47,7 @@ def get_rope_shape(org, interpolation_mode, shape): ) -if vllm_version_is("0.32.0"): +if vllm_version_is("0.33.0"): # Keep the release lane's first-call warmup; the Ascend function is plain, # so on main the decorator no longer exists and nothing is dropped. get_rope_shape = get_rope_shape_decorate(get_rope_shape) diff --git a/vllm_ascend/patch/worker/patch_mm_input_norm.py b/vllm_ascend/patch/worker/patch_mm_input_norm.py deleted file mode 100644 index 2f5a51095c2b..000000000000 --- a/vllm_ascend/patch/worker/patch_mm_input_norm.py +++ /dev/null @@ -1,27 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Ascend project -"""Backport the buffer persistence fix from vLLM #62767 to v0.32.0.""" - -from functools import wraps - -from vllm.model_executor.layers.fusion.mm_input_norm import FusedMMInputNorm - - -def patch_mm_input_norm() -> None: - original_init = FusedMMInputNorm.__init__ - if getattr(original_init, "_ascend_nonpersistent_norm", False): - return - - @wraps(original_init) - def init(self, *args, **kwargs) -> None: - original_init(self, *args, **kwargs) - # These constants come from the processor, not the checkpoint. Keep - # their values/device while excluding them from sharded/dummy loading. - self.register_buffer("weight", self.weight, persistent=False) - self.register_buffer("bias", self.bias, persistent=False) - - init._ascend_nonpersistent_norm = True # type: ignore[attr-defined] - FusedMMInputNorm.__init__ = init - - -patch_mm_input_norm() diff --git a/vllm_ascend/patch/worker/patch_model_runner.py b/vllm_ascend/patch/worker/patch_model_runner.py index 1f88d4fd7779..830d644c5d4c 100644 --- a/vllm_ascend/patch/worker/patch_model_runner.py +++ b/vllm_ascend/patch/worker/patch_model_runner.py @@ -215,7 +215,7 @@ def initialize_kv_cache( # vLLM main carries routed-experts output through the AuxOutput # connector, which the V2 NPUModelRunner relies on via super(). if self.vllm_config.aux_output_config.enabled: - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): self.aux_output_connector = upstream.get_aux_output_connector( # type: ignore[call-arg] self.model, self.vllm_config, kv_cache_config ) diff --git a/vllm_ascend/patch/worker/patch_uva.py b/vllm_ascend/patch/worker/patch_uva.py index 79c6baa4005a..4423a7ed1683 100644 --- a/vllm_ascend/patch/worker/patch_uva.py +++ b/vllm_ascend/patch/worker/patch_uva.py @@ -258,7 +258,7 @@ def copy_chunks_to_uva(self, chunks: Sequence, n: int) -> torch.Tensor: vllm.v1.worker.gpu.buffer_utils.UvaBuffer = UvaBufferWrapper -if not vllm_version_is("0.32.0"): +if not vllm_version_is("0.33.0"): def _copy_chunks_to_uva(self, chunks: Sequence, n: int) -> torch.Tensor: buf = self._next_buf(n) diff --git a/vllm_ascend/platform.py b/vllm_ascend/platform.py index 5b961ff9b381..3a21232df6ac 100644 --- a/vllm_ascend/platform.py +++ b/vllm_ascend/platform.py @@ -65,7 +65,6 @@ refresh_block_size, update_cudagraph_capture_sizes, enable_sp, - vllm_version_is, ) if TYPE_CHECKING: @@ -604,21 +603,20 @@ def check_and_update_config(cls, vllm_config: VllmConfig) -> None: # vLLM #61392 folds `compress_ratios` into `layer_types`/`compress_rates`. # Restore the legacy field before any runner/model/cache component reads # it (e.g. NPUModelRunner.__init__ setting `use_compress`). - if not vllm_version_is("0.32.0"): - from vllm.transformers_utils.deepseek_v4_utils import get_compress_ratios - - seen: set[int] = set() - for config in ( - getattr(vllm_config.model_config, "hf_config", None), - getattr(vllm_config.model_config, "hf_text_config", None), - ): - if config is None or id(config) in seen: - continue - seen.add(id(config)) - if getattr(config, "compress_ratios", None) is None: - ratios = get_compress_ratios(config) - if ratios: - config.compress_ratios = list(ratios) + from vllm.transformers_utils.deepseek_v4_utils import get_compress_ratios + + seen: set[int] = set() + for config in ( + getattr(vllm_config.model_config, "hf_config", None), + getattr(vllm_config.model_config, "hf_text_config", None), + ): + if config is None or id(config) in seen: + continue + seen.add(id(config)) + if getattr(config, "compress_ratios", None) is None: + ratios = get_compress_ratios(config) + if ratios: + config.compress_ratios = list(ratios) _validate_model_runner_config(vllm_config) cls._validate_indexer_pp_config(vllm_config) diff --git a/vllm_ascend/quantization/methods/kv_cache/turboquant/cache.py b/vllm_ascend/quantization/methods/kv_cache/turboquant/cache.py index c19caaafa04f..67022001d237 100644 --- a/vllm_ascend/quantization/methods/kv_cache/turboquant/cache.py +++ b/vllm_ascend/quantization/methods/kv_cache/turboquant/cache.py @@ -11,6 +11,9 @@ from vllm.logger import logger from vllm.utils.math_utils import round_up from vllm.utils.torch_utils import get_dtype_size + +# Both supported versions expose planning helpers in kv_cache_planning. +from vllm.v1.core.kv_cache_planning import may_override_num_blocks from vllm.v1.kv_cache_interface import ( KVCacheGroupSpec, KVCacheSpec, @@ -18,17 +21,8 @@ UniformTypeKVCacheSpecs, ) -from vllm_ascend.utils import vllm_version_is - from . import SLOT_BYTES, TURBOQUANT_CACHE_DTYPE -# vLLM #61183 moved `may_override_num_blocks` to `kv_cache_planning` on main; -# the v0.32.0 lane still ships it in `kv_cache_utils`. -if vllm_version_is("0.32.0"): - from vllm.v1.core.kv_cache_utils import may_override_num_blocks -else: - from vllm.v1.core.kv_cache_planning import may_override_num_blocks - # PA attention's fast copy path requires aligned page starts. Preserve the # integral compact-row stride used by the scatter update path as well. PHYSICAL_STRIDE_ALIGNMENT = 256 diff --git a/vllm_ascend/worker/utils.py b/vllm_ascend/worker/utils.py index 89bc461352e6..aaa0b5d38b92 100644 --- a/vllm_ascend/worker/utils.py +++ b/vllm_ascend/worker/utils.py @@ -59,7 +59,7 @@ def copy_kv_cache_blocks_inplace( # Main keys on that geometry; the release lane keys on (device, address). key = ( (tensor.device, data_ptr) - if vllm_version_is("0.32.0") + if vllm_version_is("0.33.0") else (tensor.device, data_ptr, tuple(tensor.shape), tuple(tensor.stride()), tensor.element_size()) ) if key in seen_tensors: diff --git a/vllm_ascend/worker/v1/model_runner.py b/vllm_ascend/worker/v1/model_runner.py index 5584227654e7..2480a20fed04 100644 --- a/vllm_ascend/worker/v1/model_runner.py +++ b/vllm_ascend/worker/v1/model_runner.py @@ -205,7 +205,6 @@ model_uses_kpool_indexer, set_potential_max_tokens, should_skip_allreduce_across_dp_group, - vllm_version_is, weak_ref_tensor, weak_ref_tensors, ) @@ -263,15 +262,6 @@ from vllm_ascend.sample.rejection_sampler import AscendRejectionSampler -# vLLM #61701 removed Medusa/MLP speculator support on main; the v0.32.0 lane -# still ships `AscendMedusaProposer`. Keep the name for the drafter type union -# on both lanes, but on main never resolve it at runtime: the dispatch below -# short-circuits on the version first, and the config rejects `method="medusa"` -# before a proposer could be constructed. -if vllm_version_is("0.32.0"): - from vllm_ascend.worker.v1.spec_decode.medusa_proposer import AscendMedusaProposer # type: ignore[import-not-found] - - if TYPE_CHECKING: import xgrammar as xgr # type: ignore[import-untyped] from vllm.v1.core.sched.output import GrammarOutput, SchedulerOutput @@ -761,7 +751,6 @@ def _set_up_drafter(self): | AscendDSparkProposer | AscendGemma4Proposer | AscendSuffixDecodingProposer - | AscendMedusaProposer | AscendExtractHiddenStatesProposer | None ) = None @@ -2082,16 +2071,6 @@ def propose_draft_token_ids( self._num_valid_draft_tokens, batch_size, ) - elif vllm_version_is("0.32.0") and isinstance(self.drafter, AscendMedusaProposer): - draft_token_ids = self.drafter.propose( - # Dynamic SD: forward the scheduled K (equals the configured - # maximum when the feature is disabled). - scheduler_output.num_spec_tokens_to_schedule, - valid_sampled_token_ids, - sampling_metadata, - spec_decode_metadata, - sample_hidden_states, - ) elif self.speculative_config.uses_extract_hidden_states(): # Handle extract_hidden_states method assert isinstance(self.drafter, AscendExtractHiddenStatesProposer) diff --git a/vllm_ascend/worker/v1/spec_decode/__init__.py b/vllm_ascend/worker/v1/spec_decode/__init__.py index 7e62fd4f6766..44b8fafec8a2 100644 --- a/vllm_ascend/worker/v1/spec_decode/__init__.py +++ b/vllm_ascend/worker/v1/spec_decode/__init__.py @@ -18,7 +18,6 @@ # -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.v1.spec_decode.dflash2_proposer import AscendDflash2Proposer, is_dflash2_draft from vllm_ascend.worker.v1.spec_decode.dflash_proposer import AscendDflashProposer from vllm_ascend.worker.v1.spec_decode.draft_proposer import AscendDraftModelProposer @@ -37,11 +36,6 @@ from vllm_ascend.worker.v1.spec_decode.step3p5 import AscendStep3p5MTPProposer from vllm_ascend.worker.v1.spec_decode.suffix_proposer import AscendSuffixDecodingProposer -# vLLM #61701 removed Medusa (and MLP speculator) support on main; the v0.32.0 -# lane still ships `AscendMedusaProposer`. -if vllm_version_is("0.32.0"): - from vllm_ascend.worker.v1.spec_decode.medusa_proposer import AscendMedusaProposer - def get_spec_decode_method(method, vllm_config, device, runner): if method == "ngram": @@ -51,11 +45,7 @@ def get_spec_decode_method(method, vllm_config, device, runner): elif method == "suffix": return AscendSuffixDecodingProposer(vllm_config, runner) elif method == "medusa": - if vllm_version_is("0.32.0"): - return AscendMedusaProposer(vllm_config, device) - raise ValueError( - "Medusa speculative decoding was removed in vLLM (vLLM #61701) and is only supported on the v0.32.0 lane." - ) + raise ValueError("Medusa speculative decoding was removed in vLLM (vLLM #61701).") elif method == "dspark": return AscendDSparkProposer(vllm_config, device, runner) elif method == "mtp" and vllm_config.speculative_config.use_gemma4_mtp(): diff --git a/vllm_ascend/worker/v1/spec_decode/llm_base_proposer.py b/vllm_ascend/worker/v1/spec_decode/llm_base_proposer.py index 81df0dfb17e4..aea2d2c8cbf0 100644 --- a/vllm_ascend/worker/v1/spec_decode/llm_base_proposer.py +++ b/vllm_ascend/worker/v1/spec_decode/llm_base_proposer.py @@ -1222,7 +1222,7 @@ def _propose( self.query_start_loc_group[0][: num_reqs_padded + 1].copy_(common_attn_metadata.query_start_loc) self.query_start_loc_group[0][num_reqs_padded + 1 :].fill_(0) common_attn_metadata.query_start_loc = self.query_start_loc_group[0][: num_reqs_padded + 1] - if not vllm_version_is("0.32.0"): + if not vllm_version_is("0.33.0"): # seq_lens/query_start_loc were replaced above; drop cached layouts. common_attn_metadata.invalidate_cached_layout() # type: ignore[attr-defined] @@ -2080,7 +2080,7 @@ def attn_update_stack_num_spec_norm( # sequence length to 1 to minimize their overheads in attention. exceeds_mask = common_attn_metadata.seq_lens[:batch_size] > self.max_model_len common_attn_metadata.seq_lens[:batch_size].masked_fill_(exceeds_mask, 1) - if not vllm_version_is("0.32.0"): + if not vllm_version_is("0.33.0"): # seq_lens was advanced in place above; drop cached layouts. common_attn_metadata.invalidate_cached_layout() # type: ignore[attr-defined] if common_attn_metadata.seq_lens_cpu is not None: diff --git a/vllm_ascend/worker/v2/attn_utils.py b/vllm_ascend/worker/v2/attn_utils.py index 65f049558d7a..8435ee63c596 100644 --- a/vllm_ascend/worker/v2/attn_utils.py +++ b/vllm_ascend/worker/v2/attn_utils.py @@ -131,7 +131,7 @@ if TYPE_CHECKING: from vllm_ascend.worker.v2.pcp_manager import AscendPCPAttentionContext -if vllm_version_is("0.32.0"): +if vllm_version_is("0.33.0"): import vllm.models.qwen4_exp.common.qsa_cache as qsa_cache # type: ignore[import-not-found] QSAMetadataBuilder = qsa_cache.QSAMetadataBuilder @@ -371,13 +371,8 @@ def get_kv_cache_spec(vllm_config: VllmConfig) -> dict[str, KVCacheSpec]: spec = AscendFlashAttentionBackend.customize_spec(spec) if type(spec) is FullAttentionSpec and is_c8_mxfp_kv_quant(vllm_config): spec = mxfp_cache_spec(spec) - # vLLM #42309 annotates EAGLE groups from ``spec.is_draft``, tagged on - # the spec while specs are built. The v0.32.0 lane has no ``is_draft`` - # field and annotates EAGLE groups through the packed hook, so only main - # propagates the flag here; without it no group is flagged as the draft - # model's and the coordinator fallback treats the target groups as - # EAGLE groups too. - if not vllm_version_is("0.32.0") and getattr(attn_module, "is_draft_layer", False): + # Both supported planners identify EAGLE groups through spec.is_draft. + if getattr(attn_module, "is_draft_layer", False): spec = replace(spec, is_draft=True) kv_cache_spec[layer_name] = spec if isinstance(spec, AttentionSpec) and getattr(attn_module, "align_kv_cache_with_mamba", True): diff --git a/vllm_ascend/worker/v2/model_runner.py b/vllm_ascend/worker/v2/model_runner.py index e1cb6b8072af..9c5a0a9fb9d2 100644 --- a/vllm_ascend/worker/v2/model_runner.py +++ b/vllm_ascend/worker/v2/model_runner.py @@ -1126,8 +1126,8 @@ def sample(self, hidden_states, input_batch, grammar_output): grammar_output.structured_output_request_ids, grammar_output.grammar_bitmask, ) - if vllm_version_is("0.32.0"): - # 0.32.0 rejects drafts verified against a permissive grammar + if vllm_version_is("0.33.0"): + # 0.33.0 rejects drafts verified against a permissive grammar # row; main moved that bookkeeping into the scheduler and the # draft-token handler. import vllm.v1.worker.gpu.structured_outputs as structured_outputs # type: ignore[import-not-found] @@ -1145,7 +1145,7 @@ def sample(self, hidden_states, input_batch, grammar_output): # Rejection sampling for spec decoding. assert self.rejection_sampler is not None assert self.speculator is not None - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): sampler_output = self.rejection_sampler( logits, input_batch, @@ -1371,8 +1371,7 @@ def postprocess_sampled( query_start_loc, ) else: - # Main hands non-last PP ranks the drafts received from the last - # rank; 0.32.0 has no such argument, hence the None-only path above. + # Non-last PP ranks receive drafts from the last rank on both versions. super().postprocess_sampled( idx_mapping, sampled_tokens, diff --git a/vllm_ascend/worker/v2/pcp_manager.py b/vllm_ascend/worker/v2/pcp_manager.py index 8531a4c88ed2..402348a85b06 100644 --- a/vllm_ascend/worker/v2/pcp_manager.py +++ b/vllm_ascend/worker/v2/pcp_manager.py @@ -39,7 +39,6 @@ from vllm_ascend.attention.context_parallel.common_cp import is_pcp_decode_sharding_enabled from vllm_ascend.ops.rotary_embedding import update_cos_sin -from vllm_ascend.utils import vllm_version_is from vllm_ascend.worker.v2.attn_utils import build_attn_state from vllm_ascend.worker.v2.input_batch import AscendInputBatch, AscendInputBuffers @@ -117,7 +116,7 @@ def __init__( dcp_world_size=dcp_world_size, dcp_rank=dcp_rank, cp_interleave=cp_interleave, - **({} if vllm_version_is("0.32.0") else {"moe_gathers_tokens": moe_gathers_tokens}), + moe_gathers_tokens=moe_gathers_tokens, ) # PCP supplies its own output buffers to compute_slot_mappings, so their # dtype must match Ascend block-table slots for cache-write operators. @@ -370,45 +369,24 @@ def _finalize_partition( # vLLM main renamed ``PCPManager.prepare_inputs_to_capture`` to # ``prepare_inputs_for_capture_or_profile`` so the capture path also expands # ``is_padding`` to the rows the MoE routes. - if vllm_version_is("0.32.0"): - - def prepare_inputs_to_capture( - self, - input_batch: AscendInputBatch, - ) -> AscendInputBatch: - """Stage ordinary dummies, but partition CPP's global prefill dummy.""" - if not getattr(input_batch, "is_cpp_profile", False): - staged = super().prepare_inputs_to_capture(input_batch) - assert isinstance(staged, AscendInputBatch) - return staged - - # The parent implementation only copies a dummy into PCP-local buffers. - # CPP instead supplies a global prompt, so use the real prefill splitter - # before those buffers are overwritten with the rank-local layout. - return self.partition_batch( - input_batch, - BatchExecutionDescriptor(CUDAGraphMode.NONE, input_batch.num_tokens, None), - ) - else: - - def prepare_inputs_for_capture_or_profile( # type: ignore[misc] - self, - input_batch: AscendInputBatch, - ) -> AscendInputBatch: - """Stage ordinary dummies, but partition CPP's global prefill dummy.""" - if not getattr(input_batch, "is_cpp_profile", False): - staged = super().prepare_inputs_for_capture_or_profile(input_batch) - assert isinstance(staged, AscendInputBatch) - return staged - - # The parent implementation only copies a dummy into PCP-local buffers. - # CPP instead supplies a global prompt, so use the real prefill splitter - # before those buffers are overwritten with the rank-local layout. - return self.partition_batch( - input_batch, - BatchExecutionDescriptor(CUDAGraphMode.NONE, input_batch.num_tokens, None), - ) + def prepare_inputs_for_capture_or_profile( # type: ignore[misc] + self, + input_batch: AscendInputBatch, + ) -> AscendInputBatch: + """Stage ordinary dummies, but partition CPP's global prefill dummy.""" + if not getattr(input_batch, "is_cpp_profile", False): + staged = super().prepare_inputs_for_capture_or_profile(input_batch) + assert isinstance(staged, AscendInputBatch) + return staged + + # The parent implementation only copies a dummy into PCP-local buffers. + # CPP instead supplies a global prompt, so use the real prefill splitter + # before those buffers are overwritten with the rank-local layout. + return self.partition_batch( + input_batch, + BatchExecutionDescriptor(CUDAGraphMode.NONE, input_batch.num_tokens, None), + ) def _pad_hidden_restore_idx(self, global_batch: AscendInputBatch) -> None: """Extend restore indices to the global padded extent. diff --git a/vllm_ascend/worker/v2/spec_decode/dflash/speculator.py b/vllm_ascend/worker/v2/spec_decode/dflash/speculator.py index 6c52900a83cf..19206dbaa4e2 100644 --- a/vllm_ascend/worker/v2/spec_decode/dflash/speculator.py +++ b/vllm_ascend/worker/v2/spec_decode/dflash/speculator.py @@ -126,7 +126,7 @@ def prepare_with_block_size( class AscendDFlashSpeculator(LmheadTPDraftSamplingMixin, DFlashSpeculator): - if not vllm_version_is("0.32.0"): + if not vllm_version_is("0.33.0"): def supports_batch_sharded_draft_logits(self) -> bool: # NPU draft-logits kernels index the cache by request state. diff --git a/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py b/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py index 48254b27bd40..8bfba39797e8 100644 --- a/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py +++ b/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py @@ -64,7 +64,7 @@ class AscendDSparkSpeculator(LmheadTPDraftSamplingMixin, DSparkSpeculator): # override, upstream sampling logic untouched). _lmhead_tp_sample_draft_supported = True - if not vllm_version_is("0.32.0"): + if not vllm_version_is("0.33.0"): def supports_batch_sharded_draft_logits(self) -> bool: # NPU draft-logits kernels index the cache by request state. diff --git a/vllm_ascend/worker/v2/spec_decode/lmhead_tp_utils.py b/vllm_ascend/worker/v2/spec_decode/lmhead_tp_utils.py index c610941bc9cd..1e144cbfbd70 100644 --- a/vllm_ascend/worker/v2/spec_decode/lmhead_tp_utils.py +++ b/vllm_ascend/worker/v2/spec_decode/lmhead_tp_utils.py @@ -6,7 +6,7 @@ import torch -from vllm_ascend.utils import lmhead_tp_enable, lmhead_tp_max_num_logits, lmhead_tp_pad_rows, vllm_version_is +from vllm_ascend.utils import lmhead_tp_enable, lmhead_tp_max_num_logits, lmhead_tp_pad_rows class LmheadTPDraftSamplingMixin: @@ -61,82 +61,22 @@ def _lmhead_tp_validate_draft_sampling(self) -> None: "read the request mapping and write those buffers out of bounds." ) - if vllm_version_is("0.32.0"): - - def sample_draft( - self, - hidden_states: torch.Tensor, - positions: torch.Tensor, - idx_mapping: torch.Tensor, - temperature: torch.Tensor, - seeds: torch.Tensor, - draft_step: torch.Tensor, - draft_logits: torch.Tensor | None, - ): - if not lmhead_tp_enable(): - return super().sample_draft( # type: ignore[misc] - hidden_states, positions, idx_mapping, temperature, seeds, draft_step, draft_logits - ) - if draft_logits is not None: - raise NotImplementedError( - "lmhead TP does not support draft_sample_method='probabilistic': " - "the gumbel path writes into fixed-size draft buffers that cannot " - "hold the group-aligned padding rows." - ) - num_logits = hidden_states.shape[0] - # Shared pad primitive (the runner's sample() pads the target head the - # same way); zero rows carry no draft token and are trimmed back off. - padded = lmhead_tp_pad_rows( - hidden_states, - self._lmhead_tp_max_num_logits(), - "max_num_reqs * (num_speculative_steps + 1)", - ) - out = super().sample_draft( # type: ignore[misc] - padded, positions, idx_mapping, temperature, seeds, draft_step, draft_logits - ) - return out[:num_logits] - - else: - # vLLM #59554 added `num_steps` to `Speculator.sample_draft`; DFlash - # passes it so the draft watermarker can key its draw by the step count. - def sample_draft( # type: ignore[misc] - self, - hidden_states: torch.Tensor, - positions: torch.Tensor, - idx_mapping: torch.Tensor, - temperature: torch.Tensor, - seeds: torch.Tensor, - draft_step: torch.Tensor, - draft_logits: torch.Tensor | None, - num_steps: int = 1, - ): - if not lmhead_tp_enable(): - return super().sample_draft( # type: ignore[misc] - hidden_states, - positions, - idx_mapping, - temperature, - seeds, - draft_step, - draft_logits, - num_steps=num_steps, - ) - if draft_logits is not None: - raise NotImplementedError( - "lmhead TP does not support draft_sample_method='probabilistic': " - "the gumbel path writes into fixed-size draft buffers that cannot " - "hold the group-aligned padding rows." - ) - num_logits = hidden_states.shape[0] - # Shared pad primitive (the runner's sample() pads the target head the - # same way); zero rows carry no draft token and are trimmed back off. - padded = lmhead_tp_pad_rows( + # vLLM #59554 added `num_steps` to `Speculator.sample_draft`; DFlash + # passes it so the draft watermarker can key its draw by the step count. + def sample_draft( # type: ignore[misc] + self, + hidden_states: torch.Tensor, + positions: torch.Tensor, + idx_mapping: torch.Tensor, + temperature: torch.Tensor, + seeds: torch.Tensor, + draft_step: torch.Tensor, + draft_logits: torch.Tensor | None, + num_steps: int = 1, + ): + if not lmhead_tp_enable(): + return super().sample_draft( # type: ignore[misc] hidden_states, - self._lmhead_tp_max_num_logits(), - "max_num_reqs * (num_speculative_steps + 1)", - ) - out = super().sample_draft( # type: ignore[misc] - padded, positions, idx_mapping, temperature, @@ -145,4 +85,28 @@ def sample_draft( # type: ignore[misc] draft_logits, num_steps=num_steps, ) - return out[:num_logits] + if draft_logits is not None: + raise NotImplementedError( + "lmhead TP does not support draft_sample_method='probabilistic': " + "the gumbel path writes into fixed-size draft buffers that cannot " + "hold the group-aligned padding rows." + ) + num_logits = hidden_states.shape[0] + # Shared pad primitive (the runner's sample() pads the target head the + # same way); zero rows carry no draft token and are trimmed back off. + padded = lmhead_tp_pad_rows( + hidden_states, + self._lmhead_tp_max_num_logits(), + "max_num_reqs * (num_speculative_steps + 1)", + ) + out = super().sample_draft( # type: ignore[misc] + padded, + positions, + idx_mapping, + temperature, + seeds, + draft_step, + draft_logits, + num_steps=num_steps, + ) + return out[:num_logits] diff --git a/vllm_ascend/worker/v2/spec_decode/multi_module_mtp/speculator.py b/vllm_ascend/worker/v2/spec_decode/multi_module_mtp/speculator.py index 50abeaf2bf46..737ac8713c04 100644 --- a/vllm_ascend/worker/v2/spec_decode/multi_module_mtp/speculator.py +++ b/vllm_ascend/worker/v2/spec_decode/multi_module_mtp/speculator.py @@ -51,7 +51,7 @@ class AscendMultiModuleMTPSpeculator(MultiModuleMTPSpeculator): UpdatableGraph attention-parameter updates on replay). """ - if not vllm_version_is("0.32.0"): + if not vllm_version_is("0.33.0"): def supports_batch_sharded_draft_logits(self) -> bool: # NPU draft-logits kernels index the cache by request state. diff --git a/vllm_ascend/worker/v2/spec_decode/rejection_sampler_utils.py b/vllm_ascend/worker/v2/spec_decode/rejection_sampler_utils.py index 1023453faa8c..8a4117d42f9e 100644 --- a/vllm_ascend/worker/v2/spec_decode/rejection_sampler_utils.py +++ b/vllm_ascend/worker/v2/spec_decode/rejection_sampler_utils.py @@ -352,7 +352,7 @@ def rejection_sample( # An explicit flag bypasses configuration lookup for standalone callers. if use_fp64: raise NotImplementedError("FP64 rejection sampling is not supported on NPU.") - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): draft_logits_row_mapping = None if draft_logits_num_shards != 1: # vLLM main (#63554) can shard the draft logits cache across TP ranks; @@ -403,14 +403,8 @@ def rejection_sample( num_logits, vocab_size = target_logits.shape has_draft_logits = draft_logits is not None - # vLLM main renamed the `num_speculative_steps` argument of the logits-stats - # kernels to `num_logits` and moved bonus-token detection into - # `_is_bonus_logit`, which masks its look-ahead load with the total logit - # count. Passing `num_speculative_steps` there makes the kernels treat every - # logit after the first one as a bonus token and return early, leaving the - # `new_empty` block-statistics buffers uninitialized. v0.32.0 still expects - # `num_speculative_steps`. - stats_num_logits = num_speculative_steps if vllm_version_is("0.32.0") else num_logits + # Both upstream kernels detect bonus rows using the total logit count. + stats_num_logits = num_logits if draft_logits is None: # When draft_logits is None, create a dummy tensor so that Triton @@ -433,7 +427,7 @@ def rejection_sample( target_local_sumexp = target_logits.new_empty(num_logits, vocab_num_blocks, dtype=torch.float32) draft_local_max = target_logits.new_empty(num_logits, vocab_num_blocks, dtype=torch.float32) draft_local_sumexp = target_logits.new_empty(num_logits, vocab_num_blocks, dtype=torch.float32) - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): _compute_block_stats_kernel[(num_logits, vocab_num_blocks)]( target_local_argmax, target_local_argmax.stride(0), @@ -515,7 +509,7 @@ def rejection_sample( if use_block_verification: cumulative_log_p = target_logits.new_empty(num_logits, dtype=torch.float32) - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): _compute_cumulative_log_p_kernel[(num_reqs,)]( cumulative_log_p, target_logits, @@ -569,7 +563,7 @@ def rejection_sample( if has_draft_logits: local_residual_mass = target_logits.new_empty(num_logits, vocab_num_blocks, dtype=torch.float32) if num_logits > 1: - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): _compute_local_residual_mass_kernel[(num_logits - 1, vocab_num_blocks)]( local_residual_mass, local_residual_mass.stride(0), diff --git a/vllm_ascend/worker/v2/spec_decode/standalone_ar/speculator.py b/vllm_ascend/worker/v2/spec_decode/standalone_ar/speculator.py index 5abf093c097b..b54138945391 100644 --- a/vllm_ascend/worker/v2/spec_decode/standalone_ar/speculator.py +++ b/vllm_ascend/worker/v2/spec_decode/standalone_ar/speculator.py @@ -19,7 +19,7 @@ class AscendStandaloneARSpeculator(StandaloneARSpeculator): - if not vllm_version_is("0.32.0"): + if not vllm_version_is("0.33.0"): def supports_batch_sharded_draft_logits(self) -> bool: # NPU draft-logits kernels index the cache by request state. diff --git a/vllm_ascend/worker/v2/spec_decode/target_dependent_ar/speculator.py b/vllm_ascend/worker/v2/spec_decode/target_dependent_ar/speculator.py index 5b040cc345c5..4b50fd54c4ed 100644 --- a/vllm_ascend/worker/v2/spec_decode/target_dependent_ar/speculator.py +++ b/vllm_ascend/worker/v2/spec_decode/target_dependent_ar/speculator.py @@ -82,7 +82,7 @@ class AscendTargetDependentARSpeculator(LmheadTPDraftSamplingMixin, TargetDepend model_state: "AscendModelState" - if not vllm_version_is("0.32.0"): + if not vllm_version_is("0.33.0"): def supports_batch_sharded_draft_logits(self) -> bool: # NPU draft-logits kernels index the cache by request state. @@ -489,29 +489,18 @@ def _prefill( name: metadata for name, metadata in attn_metadata.items() if name in self.draft_attn_layer_names } - if vllm_version_is("0.32.0"): - super()._prefill( - num_reqs, - num_tokens, - attn_metadata, - slot_mappings, - num_tokens_across_dp, - cudagraph_runtime_mode, - mm_inputs, - ) - else: - # vLLM main forwards `skip_sample` so the drafter KV stays in sync - # without sampling when num_speculative_tokens == 0. - super()._prefill( - num_reqs, - num_tokens, - attn_metadata, - slot_mappings, - num_tokens_across_dp, - cudagraph_runtime_mode, - mm_inputs, - skip_sample, - ) + # vLLM main forwards `skip_sample` so the drafter KV stays in sync + # without sampling when num_speculative_tokens == 0. + super()._prefill( + num_reqs, + num_tokens, + attn_metadata, + slot_mappings, + num_tokens_across_dp, + cudagraph_runtime_mode, + mm_inputs, + skip_sample, + ) def _build_attn_metadata( self, diff --git a/vllm_ascend/worker/worker.py b/vllm_ascend/worker/worker.py index 2f1f180ab8ec..851c351f40b0 100644 --- a/vllm_ascend/worker/worker.py +++ b/vllm_ascend/worker/worker.py @@ -56,6 +56,8 @@ from vllm.utils.mem_constants import GiB_bytes from vllm.utils.mem_utils import MemorySnapshot, format_gib, memory_profiling from vllm.utils.torch_utils import STR_DTYPE_TO_TORCH_DTYPE +from vllm.v1.core.kv_cache_config_builder import get_kv_cache_config_builder +from vllm.v1.core.kv_cache_planning import unify_hybrid_kv_cache_specs from vllm.v1.core.sched.output import GrammarOutput, SchedulerOutput from vllm.v1.kv_cache_interface import ( AttentionSpec, @@ -115,26 +117,14 @@ register_ascend_fla_customop, register_device_print, setup_ascend_local_comm_res, - vllm_version_is, ) -# vLLM #61183 moved the planning helpers on main; v0.32.0 keeps them -# in kv_cache_utils, so importing the main-only module breaks worker startup. -# Main resolves grouping through the platform's `KVCacheConfigBuilder`. -if vllm_version_is("0.32.0"): - from vllm.v1.core.kv_cache_utils import ( - get_kv_cache_groups, - unify_hybrid_kv_cache_specs, - ) -else: - from vllm.v1.core.kv_cache_config_builder import get_kv_cache_config_builder - from vllm.v1.core.kv_cache_planning import unify_hybrid_kv_cache_specs - - def get_kv_cache_groups( - vllm_config: VllmConfig, - kv_cache_spec: dict[str, KVCacheSpec], - ) -> list[KVCacheGroupSpec]: - return get_kv_cache_config_builder(vllm_config).get_kv_cache_groups(vllm_config, kv_cache_spec) + +def get_kv_cache_groups( + vllm_config: VllmConfig, + kv_cache_spec: dict[str, KVCacheSpec], +) -> list[KVCacheGroupSpec]: + return get_kv_cache_config_builder(vllm_config).get_kv_cache_groups(vllm_config, kv_cache_spec) torch._dynamo.trace_rules.clear_lru_cache() # noqa: E402 @@ -1199,22 +1189,16 @@ def get_kv_connector_handshake_metadata( return {(pp_rank, tp_rank): metadata} def get_simple_cpu_offload_num_cpu_blocks(self) -> int | None: - if vllm_version_is("0.32.0"): - # v0.32.0's engine core never issues this RPC, and the upstream - # `._find_simple_cpu_offload_connector` / `get_aligned_num_cpu_blocks` - # helpers do not exist on that lane. - return None - else: - from vllm.distributed.kv_transfer.kv_connector.v1.simple_cpu_offload_connector import ( # noqa: E501 - _find_simple_cpu_offload_connector, - ) + from vllm.distributed.kv_transfer.kv_connector.v1.simple_cpu_offload_connector import ( # noqa: E501 + _find_simple_cpu_offload_connector, + ) - if not has_kv_transfer_group(): - return None - connector = _find_simple_cpu_offload_connector(get_kv_transfer_group()) - if connector is None: - return None - return connector.get_aligned_num_cpu_blocks() + if not has_kv_transfer_group(): + return None + connector = _find_simple_cpu_offload_connector(get_kv_transfer_group()) + if connector is None: + return None + return connector.get_aligned_num_cpu_blocks() def _get_layerwise_kv_cache_memory_info( self, @@ -1396,10 +1380,9 @@ def profile( logger.debug("Starting torch profiler with trace name: %s", trace_name) # Else: profiler already initialized. Restart profiling but keep the # original trace name from the first initialization. - if not vllm_version_is("0.32.0"): - # vLLM main supports per-session profiler kwargs; the release - # wrapper has no slot for them. - self.profiler.set_profiler_kwargs(profiler_kwargs) + # vLLM main supports per-session profiler kwargs; the release + # wrapper has no slot for them. + self.profiler.set_profiler_kwargs(profiler_kwargs) self.profiler.start(delay_iterations=delay_iterations, max_iterations=max_iterations) else: if self.profiler is None: From 616f6d525401fa0f793b9e3e61260de4fe2dd7ba Mon Sep 17 00:00:00 2001 From: zhao-stack <80399320+zhao-stack@users.noreply.github.com> Date: Fri, 6 Nov 2026 21:17:59 +0800 Subject: [PATCH 2/9] test: fix v0.33 compatibility expectations and KV planner calls Keep release-specific Kimi fused-gate coverage and parameter-rebinding assertions: v0.33 lacks the main-only own-storage behavior. Pass the builder to Qwen4 admission tests to match both supported upstream planner APIs. Signed-off-by: zhao-stack <80399320+zhao-stack@users.noreply.github.com> --- tests/ut/attention/test_mla_v1.py | 25 +++++++++---------- tests/ut/attention/test_sfa_v1.py | 20 +++++++-------- .../ut/models/test_qwen4_exp_cache_config.py | 6 +++-- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/tests/ut/attention/test_mla_v1.py b/tests/ut/attention/test_mla_v1.py index e446212cb466..b22f580d05ae 100644 --- a/tests/ut/attention/test_mla_v1.py +++ b/tests/ut/attention/test_mla_v1.py @@ -31,7 +31,7 @@ from vllm_ascend.quantization.methods import AscendW8A8DynamicLinearMethod, AscendW8A8LinearMethod from vllm_ascend.quantization.methods.w8a8.w8a8_mxfp8 import AscendW8A8MXFP8DynamicLinearMethod from vllm_ascend.quantization.methods.w8a8.w8a8fp8_dynamic import AscendW8A8FP8DynamicLinearMethod -from vllm_ascend.utils import ACL_FORMAT_FRACTAL_ND, ACL_FORMAT_FRACTAL_NZ +from vllm_ascend.utils import ACL_FORMAT_FRACTAL_ND, ACL_FORMAT_FRACTAL_NZ, vllm_version_is @pytest.mark.parametrize("num_tokens", [1, 3]) @@ -1949,7 +1949,7 @@ def test_qkv_a_fused_output_gate_disables_mlapo(self, mock_get_current_vllm_conf self.impl.fused_qkv_a_proj.output_sizes = [64, 32, 128] # Only vLLM main builds the three-shard QKV-A-gate projection; release # v0.33.0 keeps a separate gate and a two-shard projection. - gate_fused = True + gate_fused = not vllm_version_is("0.33.0") impl = self._rebuild_impl() @@ -2807,13 +2807,8 @@ def test_process_weights_after_loading_refreshes_prolog_v3_weights(self, mock_fo def test_process_weights_after_loading_rebinds_incompatible_value(self, mock_format_cast): """An incompatible reload must rebind instead of raising from ``copy_``. - ``replace_parameter(..., prefer_copy=True)`` reuses the stored storage - only while shape, dtype and device still match. The hand-rolled - ``copy_`` it replaced was unconditional, so a re-derived value that - stopped being compatible aborted the whole weight-update transaction - with a ``RuntimeError``. That failure mode is the only behaviour this - change alters, so it is the part of the contract the unit tests have to - pin down. + v0.33.0 rebinds an incompatible value; main can copy a smaller value + into the parameter's existing storage. Both must accept the new shape. """ layer = MagicMock(spec=LinearBase) layer.input_size_per_partition = 10 @@ -2843,9 +2838,13 @@ def test_process_weights_after_loading_rebinds_incompatible_value(self, mock_for self.impl.process_weights_after_loading(torch.bfloat16) - # Main copies a smaller value into the parameter's own storage, so - # the address captured by graphs is preserved. - self.assertEqual(self.impl.W_UV.data_ptr(), w_uv_ptr) + if vllm_version_is("0.33.0"): + # A re-derived value that no longer fits rebinds the parameter. + self.assertNotEqual(self.impl.W_UV.data_ptr(), w_uv_ptr) + else: + # Main copies a smaller value into the parameter's own storage, so + # the address captured by graphs is preserved. + self.assertEqual(self.impl.W_UV.data_ptr(), w_uv_ptr) self.assertEqual( self.impl.W_UV.shape, (self.impl.num_heads, self.impl.kv_lora_rank, self.impl.v_head_dim), @@ -3692,7 +3691,7 @@ def test_split_fused_qkv_lora_plain_layout_has_no_gate(): @pytest.mark.skipif( - False, + vllm_version_is("0.33.0"), reason="gate-fused QKV-A layout is vLLM main only", ) def test_split_fused_qkv_lora_peels_kimi_output_gate(): diff --git a/tests/ut/attention/test_sfa_v1.py b/tests/ut/attention/test_sfa_v1.py index 089fc499fff6..e50b2555e811 100644 --- a/tests/ut/attention/test_sfa_v1.py +++ b/tests/ut/attention/test_sfa_v1.py @@ -39,6 +39,7 @@ AscendW8A8LinearMethod, AscendW8A8MXFP8DynamicLinearMethod, ) +from vllm_ascend.utils import vllm_version_is class TestAscendSFABackend(TestBase): @@ -1292,13 +1293,8 @@ def test_process_weights_after_loading_rebinds_incompatible_value( ): """An incompatible reload must rebind instead of raising from ``copy_``. - ``replace_parameter(..., prefer_copy=True)`` reuses the stored storage - only while shape, dtype and device still match. The hand-rolled - ``copy_`` it replaced was unconditional, so a re-derived value that - stopped being compatible aborted the whole weight-update transaction - with a ``RuntimeError``. That failure mode is the only behaviour this - change alters, so it is the part of the contract the unit tests have to - pin down. + v0.33.0 rebinds an incompatible value; main can copy a smaller value + into the parameter's existing storage. Both must accept the new shape. """ layer = self._setup_kv_b_proj() mock_format_cast.return_value = layer.weight @@ -1319,9 +1315,13 @@ def test_process_weights_after_loading_rebinds_incompatible_value( self.impl.process_weights_after_loading(torch.bfloat16) - # Main copies a smaller value into the parameter's own storage, so - # the address captured by graphs is preserved. - self.assertEqual(self.impl.W_UV.data_ptr(), w_uv_ptr) + if vllm_version_is("0.33.0"): + # A re-derived value that no longer fits rebinds the parameter. + self.assertNotEqual(self.impl.W_UV.data_ptr(), w_uv_ptr) + else: + # Main copies a smaller value into the parameter's own storage, so + # the address captured by graphs is preserved. + self.assertEqual(self.impl.W_UV.data_ptr(), w_uv_ptr) self.assertEqual( self.impl.W_UV.shape, (self.impl.local_num_heads, self.impl.kv_lora_rank, self.impl.v_head_dim), diff --git a/tests/ut/models/test_qwen4_exp_cache_config.py b/tests/ut/models/test_qwen4_exp_cache_config.py index 9671a59ce6c5..19f0a3275dc8 100644 --- a/tests/ut/models/test_qwen4_exp_cache_config.py +++ b/tests/ut/models/test_qwen4_exp_cache_config.py @@ -6,6 +6,7 @@ import torch from vllm.config import KVTransferConfig from vllm.model_executor.models import ModelRegistry +from vllm.v1.core.kv_cache_planning import DefaultKVCacheConfigBuilder from vllm.v1.kv_cache_interface import ( CircularBufferSpec, FullAttentionSpec, @@ -543,6 +544,7 @@ def test_qwen4_cache_admission_matches_shared_planner_allocation() -> None: max_in_flight_tokens=4096, ) required_bytes = _ascend_max_memory_usage_bytes_from_groups( + DefaultKVCacheConfigBuilder(), vllm_config, groups, ) @@ -609,7 +611,7 @@ def required_blocks(group_list) -> int: gdn_blocks_each = required_blocks(gdn_groups[:1]) blocks_before = required_blocks(groups) - bytes_before = _ascend_max_memory_usage_bytes_from_groups(vllm_config, groups) + bytes_before = _ascend_max_memory_usage_bytes_from_groups(DefaultKVCacheConfigBuilder(), vllm_config, groups) merged = _merge_mamba_state_groups(groups, 13) @@ -630,7 +632,7 @@ def required_blocks(group_list) -> int: owner.spec.real_page_size_bytes for owner in probe.owners if owner.role == PLE ) - bytes_after = _ascend_max_memory_usage_bytes_from_groups(vllm_config, merged) + bytes_after = _ascend_max_memory_usage_bytes_from_groups(DefaultKVCacheConfigBuilder(), vllm_config, merged) assert bytes_after == blocks_after * pool_block_bytes assert bytes_before - bytes_after == 33 * gdn_blocks_each * pool_block_bytes From cc1ce4f8b97c56bfd03f244168dc0cabd56abef6 Mon Sep 17 00:00:00 2001 From: zhao-stack <80399320+zhao-stack@users.noreply.github.com> Date: Fri, 6 Nov 2026 21:18:00 +0800 Subject: [PATCH 3/9] fix: handle Kimi fused output gate on vLLM v0.33 The AMD Kimi attention inherited by Ascend already constructs KimiK3MergedQKVGateLinear in v0.33. Remove the obsolete release-only two-shard path so preprocessing peels and applies the gate, disables incompatible MLAPO, and preserves the KV shard boundary. Enable the fused-layout regressions for both supported versions. Signed-off-by: zhao-stack <80399320+zhao-stack@users.noreply.github.com> --- tests/ut/attention/test_mla_v1.py | 9 +--- vllm_ascend/attention/mla_v1.py | 90 +++++++++++-------------------- 2 files changed, 33 insertions(+), 66 deletions(-) diff --git a/tests/ut/attention/test_mla_v1.py b/tests/ut/attention/test_mla_v1.py index b22f580d05ae..c5dfec6ee0d0 100644 --- a/tests/ut/attention/test_mla_v1.py +++ b/tests/ut/attention/test_mla_v1.py @@ -1947,9 +1947,8 @@ def test_qkv_a_fused_output_gate_disables_mlapo(self, mock_get_current_vllm_conf """Kimi-K3 fuses its gate as a third QKV-A shard; MLAPO cannot carry it.""" mock_get_current_vllm_config.return_value = self.impl.vllm_config self.impl.fused_qkv_a_proj.output_sizes = [64, 32, 128] - # Only vLLM main builds the three-shard QKV-A-gate projection; release - # v0.33.0 keeps a separate gate and a two-shard projection. - gate_fused = not vllm_version_is("0.33.0") + # Both supported Kimi AMD implementations use the three-shard layout. + gate_fused = True impl = self._rebuild_impl() @@ -3690,10 +3689,6 @@ def test_split_fused_qkv_lora_plain_layout_has_no_gate(): torch.testing.assert_close(kv_no_split, qkv_lora[:, 4:]) -@pytest.mark.skipif( - vllm_version_is("0.33.0"), - reason="gate-fused QKV-A layout is vLLM main only", -) def test_split_fused_qkv_lora_peels_kimi_output_gate(): """A gate-fused layout returns the trailing shard separately from q/kv.""" qkv_lora = torch.arange(15, dtype=torch.float32).reshape(1, 15) diff --git a/vllm_ascend/attention/mla_v1.py b/vllm_ascend/attention/mla_v1.py index 63f502d938a8..093003e65ab1 100644 --- a/vllm_ascend/attention/mla_v1.py +++ b/vllm_ascend/attention/mla_v1.py @@ -87,7 +87,6 @@ enable_sfa, is_pd_decode_recompute_scheduler_enabled, maybe_trans_nz, - vllm_version_is, weak_ref_tensors, ) from vllm_ascend.worker.npu_input_batch import NPUInputBatch @@ -1017,20 +1016,13 @@ def __init__( self.kv_b_proj = kwargs["kv_b_proj"] self.o_proj = kwargs["o_proj"] self.g_proj = kwargs.get("g_proj") - # vLLM main fuses Kimi-K3's output gate into the QKV-A projection as a - # trailing shard, making its per-rank layout ``[q_a | kv_a | gate]`` and - # dropping the standalone ``g_proj``. Release v0.33.0 keeps the separate - # ``g_proj`` and a two-shard projection. - if vllm_version_is("0.33.0"): - self.qkv_a_gate_fused = False - self.use_output_gate = self.g_proj is not None - else: - # The plain MLA projection also only has the two latent shards, so - # the shard count identifies the fused layout without importing the - # Kimi-specific linear class. - fused_output_sizes = getattr(self.fused_qkv_a_proj, "output_sizes", None) - self.qkv_a_gate_fused = fused_output_sizes is not None and len(fused_output_sizes) == 3 - self.use_output_gate = self.g_proj is not None or self.qkv_a_gate_fused + # Both supported Kimi AMD implementations can append an output-gate shard. + # The plain MLA projection also only has the two latent shards, so + # the shard count identifies the fused layout without importing the + # Kimi-specific linear class. + fused_output_sizes = getattr(self.fused_qkv_a_proj, "output_sizes", None) + self.qkv_a_gate_fused = fused_output_sizes is not None and len(fused_output_sizes) == 3 + self.use_output_gate = self.g_proj is not None or self.qkv_a_gate_fused self.use_mla_rope = kwargs.get("use_mla_rope", True) self.vllm_config = get_current_vllm_config() self.use_pcp = self.vllm_config.parallel_config.prefill_context_parallel_size > 1 @@ -3258,53 +3250,33 @@ def mla_preprocess_decode(self, q_c, kv_no_split, kv_cache, attn_metadata, writt current_k_pe=current_k_pe, ) - # vLLM main fuses Kimi-K3's output gate into the trailing shard of the - # QKV-A projection; v0.33.0 never has that shard, so the release lane keeps - # the original two-way ``[q_a | kv_a]`` split. - if vllm_version_is("0.33.0"): + @property + def _fused_qkv_a_kv_end(self) -> int | None: + """End offset of the KV-A shard inside the fused QKV-A projection. - @property - def _fused_qkv_a_kv_end(self) -> int | None: - """v0.33.0 keeps the plain two-shard QKV-A projection.""" + Kimi-K3 appends its output gate after ``[q_a | kv_a]``. ``None`` means + the plain two-shard layout, where the KV-A shard runs to the end. + """ + if not getattr(self, "qkv_a_gate_fused", False): return None + return self.q_lora_rank + self.kv_lora_rank + self.qk_rope_head_dim - def _split_fused_qkv_lora(self, qkv_lora: torch.Tensor): - """Split the plain ``[q_a | kv_a]`` QKV-A projection.""" - q_c, kv_no_split = qkv_lora.split( - [self.q_lora_rank, self.kv_lora_rank + self.qk_rope_head_dim], - dim=-1, - ) - return q_c, kv_no_split, None - - else: - - @property - def _fused_qkv_a_kv_end(self) -> int | None: - """End offset of the KV-A shard inside the fused QKV-A projection. - - Kimi-K3 appends its output gate after ``[q_a | kv_a]``. ``None`` means - the plain two-shard layout, where the KV-A shard runs to the end. - """ - if not getattr(self, "qkv_a_gate_fused", False): - return None - return self.q_lora_rank + self.kv_lora_rank + self.qk_rope_head_dim - - def _split_fused_qkv_lora(self, qkv_lora: torch.Tensor): - """Split the fused QKV-A projection into ``q_c`` and ``kv_no_split``. - - Kimi-K3 appends its output gate as a trailing shard; when that layout is - detected the gate is peeled off first and returned so the caller can - apply it after attention. ``None`` is returned for the plain layout. - """ - gate = None - kv_end = self._fused_qkv_a_kv_end - if kv_end is not None: - qkv_lora, gate = qkv_lora.split([kv_end, qkv_lora.shape[-1] - kv_end], dim=-1) - q_c, kv_no_split = qkv_lora.split( - [self.q_lora_rank, self.kv_lora_rank + self.qk_rope_head_dim], - dim=-1, - ) - return q_c, kv_no_split, gate + def _split_fused_qkv_lora(self, qkv_lora: torch.Tensor): + """Split the fused QKV-A projection into ``q_c`` and ``kv_no_split``. + + Kimi-K3 appends its output gate as a trailing shard; when that layout is + detected the gate is peeled off first and returned so the caller can + apply it after attention. ``None`` is returned for the plain layout. + """ + gate = None + kv_end = self._fused_qkv_a_kv_end + if kv_end is not None: + qkv_lora, gate = qkv_lora.split([kv_end, qkv_lora.shape[-1] - kv_end], dim=-1) + q_c, kv_no_split = qkv_lora.split( + [self.q_lora_rank, self.kv_lora_rank + self.qk_rope_head_dim], + dim=-1, + ) + return q_c, kv_no_split, gate def _mla_preprocess(self, layer_name, hidden_states, kv_cache, attn_metadata): # MLA Preprocess: From 9f2c2e02ecddaa91cdb69a7fc9159d6e4e4b90b0 Mon Sep 17 00:00:00 2001 From: zhao-stack <80399320+zhao-stack@users.noreply.github.com> Date: Fri, 6 Nov 2026 21:18:02 +0800 Subject: [PATCH 4/9] test: select the v0.33 DSpark sampling fixture Signed-off-by: zhao-stack <80399320+zhao-stack@users.noreply.github.com> --- tests/e2e/pull_request/one_card/test_gumbel_sampling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/pull_request/one_card/test_gumbel_sampling.py b/tests/e2e/pull_request/one_card/test_gumbel_sampling.py index 689051a8eed5..d4d291308a17 100644 --- a/tests/e2e/pull_request/one_card/test_gumbel_sampling.py +++ b/tests/e2e/pull_request/one_card/test_gumbel_sampling.py @@ -604,7 +604,7 @@ def test_dspark_uses_ascend_gumbel(self): speculator.temperature = torch.tensor([0.5, 1.5], device=DEVICE) speculator.seeds = torch.tensor([3, 7], dtype=torch.int64, device=DEVICE) speculator._step_cols = torch.arange(2, dtype=torch.int32, device=DEVICE) - if vllm_version_is("0.32.0"): + if vllm_version_is("0.33.0"): # The release tree keeps the raw per-step draft-logits tensor. speculator.draft_logits = torch.zeros(2, 2, 1031, device=DEVICE) draft_logits = speculator.draft_logits From 650ee0fdd3267128182fde5d4452879d5bb60186 Mon Sep 17 00:00:00 2001 From: zhao-stack <80399320+zhao-stack@users.noreply.github.com> Date: Fri, 6 Nov 2026 21:18:05 +0800 Subject: [PATCH 5/9] fix: align rebased PCP contracts with vLLM v0.33 Use the shared PCP input-buffer tuple contract and update newly merged DP sync fixtures to the v0.33 dataclass boundary. Signed-off-by: zhao-stack <80399320+zhao-stack@users.noreply.github.com> --- tests/ut/spec_decode/test_dspark_pcp_dp_sync.py | 2 +- tests/ut/worker/test_mtp_pcp_speculator_v2.py | 2 +- tests/ut/worker/test_pcp_manager_v2.py | 4 +--- vllm_ascend/worker/v2/pcp_manager.py | 10 +++------- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/ut/spec_decode/test_dspark_pcp_dp_sync.py b/tests/ut/spec_decode/test_dspark_pcp_dp_sync.py index 16c5b7186c9f..5ffd2b156896 100644 --- a/tests/ut/spec_decode/test_dspark_pcp_dp_sync.py +++ b/tests/ut/spec_decode/test_dspark_pcp_dp_sync.py @@ -37,7 +37,7 @@ def test_dspark_global_requests_do_not_reuse_local_pcp_dp_capacity(monkeypatch, idx_mapping=torch.arange(draft_reqs), is_prefilling_np=np.zeros(draft_reqs, dtype=np.bool_), ) - sync_kwargs = {} if vllm_version_is("0.32.0") else {"max_query_len": None} + sync_kwargs = {} if vllm_version_is("0.33.0") else {"max_query_len": None} target_sync = DPSyncState( num_tokens_across_dp=torch.tensor([20, 20]), uniform_token_count=5, eager=False, num_reqs=4, **sync_kwargs ) diff --git a/tests/ut/worker/test_mtp_pcp_speculator_v2.py b/tests/ut/worker/test_mtp_pcp_speculator_v2.py index 12b3064e96b2..6c9efa1e6129 100644 --- a/tests/ut/worker/test_mtp_pcp_speculator_v2.py +++ b/tests/ut/worker/test_mtp_pcp_speculator_v2.py @@ -356,7 +356,7 @@ def test_propose_renegotiates_pcp_draft_dp_sync(pcp_enabled, mismatch, dummy_run speculator.pcp_manager = object() if pcp_enabled else None input_batch = object() attn_metadata = {"mtp": _mla_pcp_decode_metadata(4, [4, 8])} - sync_kwargs = {} if vllm_version_is("0.32.0") else {"max_query_len": None} + sync_kwargs = {} if vllm_version_is("0.33.0") else {"max_query_len": None} dp_sync = DPSyncState( num_tokens_across_dp=torch.tensor([64, 64]), uniform_token_count=4, eager=True, num_reqs=16, **sync_kwargs ) diff --git a/tests/ut/worker/test_pcp_manager_v2.py b/tests/ut/worker/test_pcp_manager_v2.py index e080106f18cd..fb5d592f8bca 100644 --- a/tests/ut/worker/test_pcp_manager_v2.py +++ b/tests/ut/worker/test_pcp_manager_v2.py @@ -1371,9 +1371,7 @@ def test_is_target_attn_groups_excludes_draft_only_groups(draft_pcp_size) -> Non def _get_draft_input_buffers(manager, buffers, num_tokens): - """Call the live upstream signature; vLLM main also returns the MoE padding mask.""" - if vllm_version_is("0.32.0"): - return manager.get_draft_input_buffers(buffers) + """Both supported upstream versions return the MoE padding mask.""" return manager.get_draft_input_buffers(buffers, num_tokens)[0] diff --git a/vllm_ascend/worker/v2/pcp_manager.py b/vllm_ascend/worker/v2/pcp_manager.py index 402348a85b06..124b8c8e27b5 100644 --- a/vllm_ascend/worker/v2/pcp_manager.py +++ b/vllm_ascend/worker/v2/pcp_manager.py @@ -586,8 +586,8 @@ def restore_for_sampling( return hidden_states, aux_hidden_states, global_batch def get_draft_input_buffers( - self, input_buffers: InputBuffers, num_tokens: int | None = None - ) -> InputBatch | InputBuffers | tuple[InputBatch | InputBuffers, torch.Tensor]: + self, input_buffers: InputBuffers, num_tokens: int + ) -> tuple[InputBatch | InputBuffers, torch.Tensor]: """Stage rank-local draft prefill inputs at the draft's own addresses. Draft graphs are captured against the speculator's input buffers, @@ -598,9 +598,7 @@ def get_draft_input_buffers( """ local_batch = self.draft_prefill_batch if local_batch is None: - if vllm_version_is("0.32.0"): - return input_buffers - return super().get_draft_input_buffers(input_buffers, num_tokens) # type: ignore[call-arg] + return super().get_draft_input_buffers(input_buffers, num_tokens) num_staged_tokens = local_batch.num_tokens_after_padding self._draft_input_ids_stash[:num_staged_tokens].copy_(input_buffers.input_ids[:num_staged_tokens]) self._draft_positions_stash[:num_staged_tokens].copy_(input_buffers.positions[:num_staged_tokens]) @@ -609,8 +607,6 @@ def get_draft_input_buffers( input_buffers.input_ids[:num_staged_tokens].copy_(local_batch.input_ids[:num_staged_tokens]) input_buffers.positions[:num_staged_tokens].copy_(local_batch.positions[:num_staged_tokens]) input_buffers.is_padding[:num_staged_tokens].copy_(local_batch.is_padding[:num_staged_tokens]) - if vllm_version_is("0.32.0"): - return input_buffers return input_buffers, local_batch.is_padding def restore_draft_prefill( From ee0f953cabc4a0cec11c0bc33dba182cd6afd04f Mon Sep 17 00:00:00 2001 From: zhao-stack <80399320+zhao-stack@users.noreply.github.com> Date: Fri, 6 Nov 2026 21:18:06 +0800 Subject: [PATCH 6/9] fix: align DSpark dummy metadata with effective draft requests vLLM v0.33 trims DP dummy draft requests while preserving the padded target InputBatch. Scope that effective count around drafting and use it for sequence/query metadata and initial DCP preparation. Preserve the target batch and restore the count on exit; reject invalid graph capacity. Local production-method CPU UT reproduced the 32-to-19 mismatch before the fix. Afterward, 50 tests passed against each supported upstream metadata implementation. Forward/NPU boundaries were mocked; full CPU imports and NPU E2E remain unverified. Test evidence stays outside this commit as requested. Signed-off-by: zhao-stack <80399320+zhao-stack@users.noreply.github.com> --- .../v2/spec_decode/dspark/speculator.py | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py b/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py index 8bfba39797e8..8289ec858c49 100644 --- a/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py +++ b/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py @@ -16,6 +16,7 @@ # This file is a part of the vllm-ascend project. # from collections.abc import Mapping, Sequence +from contextlib import contextmanager from typing import Any, cast import numpy as np @@ -296,12 +297,25 @@ def _prepare_draft_dcp_metadata_inputs( max_model_len=self.max_model_len, ) + @contextmanager + def _draft_metadata_request_count(self, num_reqs: int): + previous = getattr(self, "_draft_metadata_num_reqs", None) + self._draft_metadata_num_reqs = num_reqs + try: + yield + finally: + self._draft_metadata_num_reqs = previous + # Graph capture builds metadata from the padded request shape. def build_draft_attn_metadatas(self, num_reqs_padded, seq_lens_cpu_upper_bound): assert self.input_batch is not None + num_reqs = getattr(self, "_draft_metadata_num_reqs", None) + if num_reqs is None: + num_reqs = self.input_batch.num_reqs + assert 0 <= num_reqs <= num_reqs_padded, "draft requests exceed graph capacity" num_tokens_padded = num_reqs_padded * self.num_query_per_req seq_lens_cpu, is_prefilling = self._prepare_draft_dcp_metadata_inputs( - self.input_batch.num_reqs, num_reqs_padded, self.num_query_per_req + num_reqs, num_reqs_padded, self.num_query_per_req ) with ( build_attn_metadata_wrapper(), @@ -322,7 +336,7 @@ def build_draft_attn_metadatas(self, num_reqs_padded, seq_lens_cpu_upper_bound): num_reqs=num_reqs_padded, ) attn_metadata = self._build_uniform_attn_metadata( - num_reqs=self.input_batch.num_reqs, + num_reqs=num_reqs, batch_desc=batch_desc, num_query_per_req=self.num_query_per_req, seq_lens_cpu_upper_bound=seq_lens_cpu_upper_bound, @@ -432,15 +446,22 @@ def propose( # TODO: Remove this guard once main2main includes upstream vLLM # #54856 (facd9a74a1), which resets the profiling DP counts. sync_state = None + # Upstream trims DP dummy draft requests before selecting its graph, + # while input_batch still describes the padded target batch. Replay + # metadata must use the same count without mutating the target batch. + num_draft_reqs = input_batch.num_reqs + if dummy_run and sync_state is not None: + num_draft_reqs = min(num_draft_reqs, sync_state.num_reqs) seq_lens_cpu = None is_prefilling = torch.from_numpy(self.input_batch.is_prefilling_np) if self.use_dcp and self.attn_architecture in ("GQA", "MLA") and not (dummy_run and skip_attn_for_dummy_run): # DSpark drafts one block with a fixed step; zero unused request slots # before upstream selects the padded batch size and slices this view. seq_lens_cpu, is_prefilling = self._prepare_draft_dcp_metadata_inputs( - input_batch.num_reqs, self.max_num_reqs, self.num_query_per_req + num_draft_reqs, self.max_num_reqs, self.num_query_per_req ) with ( + self._draft_metadata_request_count(num_draft_reqs), build_attn_metadata_wrapper(), build_attn_metadata_factory( self.input_buffers.positions, From 70fd0324bbbeb9769eb9594977db87f4eea1faac Mon Sep 17 00:00:00 2001 From: zhao-stack <80399320+zhao-stack@users.noreply.github.com> Date: Fri, 6 Nov 2026 21:18:10 +0800 Subject: [PATCH 7/9] fix: declare nullable DSpark metadata request count Initialize the scoped draft metadata request count as int | None so mypy accepts restoring its absent value. This fixes the Python 3.10, 3.11 and 3.12 pre-commit assignment error without changing draft request-count behavior. Signed-off-by: zhao-stack <80399320+zhao-stack@users.noreply.github.com> --- vllm_ascend/worker/v2/spec_decode/dspark/speculator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py b/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py index 8289ec858c49..8b6946d6d171 100644 --- a/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py +++ b/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py @@ -76,6 +76,7 @@ def __init__(self, vllm_config: VllmConfig, device: torch.device): super().__init__(vllm_config, device) self._lmhead_tp_validate_draft_sampling() self.input_batch: InputBatch | None = None + self._draft_metadata_num_reqs: int | None = None self.attn_architecture: str | None = None self.use_flashmla: bool = False self._init_dcp() From 72af94ac1a9e0de2fd064a022db2049d63c371a7 Mon Sep 17 00:00:00 2001 From: zhao-stack <80399320+zhao-stack@users.noreply.github.com> Date: Fri, 6 Nov 2026 21:18:12 +0800 Subject: [PATCH 8/9] docs: note when to remove DSpark replay metadata helpers Record the tiling dependency and why replay metadata rebuilding currently needs the effective draft request count. Signed-off-by: zhao-stack <80399320+zhao-stack@users.noreply.github.com> --- vllm_ascend/worker/v2/spec_decode/dspark/speculator.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py b/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py index 8b6946d6d171..70c124f2b377 100644 --- a/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py +++ b/vllm_ascend/worker/v2/spec_decode/dspark/speculator.py @@ -298,6 +298,9 @@ def _prepare_draft_dcp_metadata_inputs( max_model_len=self.max_model_len, ) + # TODO: Remove this helper and build_draft_attn_metadatas once tiling + # eliminates replay-time metadata rebuilding. The rebuild currently needs + # this count because it cannot access the effective num_reqs from upstream propose(). @contextmanager def _draft_metadata_request_count(self, num_reqs: int): previous = getattr(self, "_draft_metadata_num_reqs", None) From a526e0f0bb4eb1cc786d42adf82d5452e51f78b7 Mon Sep 17 00:00:00 2001 From: zhao-stack <80399320+zhao-stack@users.noreply.github.com> Date: Mon, 9 Nov 2026 10:24:24 +0800 Subject: [PATCH 9/9] test: complete DSpark proposal batch request count Provide num_reqs in the PCP synchronization fixture to match InputBatch's required fields after draft metadata request count alignment. Preserve all parameter combinations and assertions. Signed-off-by: zhao-stack <80399320+zhao-stack@users.noreply.github.com> --- tests/ut/spec_decode/test_dspark_pcp_dp_sync.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ut/spec_decode/test_dspark_pcp_dp_sync.py b/tests/ut/spec_decode/test_dspark_pcp_dp_sync.py index 5ffd2b156896..79cf45397d97 100644 --- a/tests/ut/spec_decode/test_dspark_pcp_dp_sync.py +++ b/tests/ut/spec_decode/test_dspark_pcp_dp_sync.py @@ -87,7 +87,7 @@ def test_dspark_syncs_finished_proposals_only_without_upstream_hook( spec.vllm_config = SimpleNamespace(parallel_config=SimpleNamespace()) spec.draft_logits = torch.arange(24, dtype=torch.float32).reshape(6, 2, 2) if probabilistic else None original_logits = spec.draft_logits.clone() if probabilistic else None - batch = SimpleNamespace(idx_mapping=torch.tensor([4, 1]), is_prefilling_np=np.zeros(2, dtype=np.bool_)) + batch = SimpleNamespace(num_reqs=2, idx_mapping=torch.tensor([4, 1]), is_prefilling_np=np.zeros(2, dtype=np.bool_)) local_tokens = torch.tensor([[9, 8], [7, 6]]) shared_tokens = torch.tensor([[1, 2], [3, 4]]) shared_logits = torch.full((2, 2, 2), 0.5)