@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / aaefc58ee0
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 8, 00:00 UTC

[CI] Revert PRs 34818 and 33600 (#34979)

Lucas Wilkinson committed Feb 20, 2026 at 16:25 UTC aaefc58ee0f023ec7bd3671ca83aae1b8a8f271d
16 files changed +242 -294
tests/models/multimodal/processing/test_tensor_schema.py
+1 -4
@@ -13,7 +13,6 @@ import torch.nn as nn
13 from PIL import Image
14
15 from vllm.config import ModelConfig, VllmConfig, set_current_vllm_config
16 -from vllm.config.cache import CacheConfig
16 from vllm.config.multimodal import (
17 AudioDummyOptions,
18 BaseDummyOptions,
@@ -132,9 +131,7 @@ def initialize_dummy_model(
131 ):
132 temp_file = tempfile.mkstemp()[1]
133 current_device = torch.get_default_device()
135 - vllm_config = VllmConfig(
136 - model_config=model_config, cache_config=CacheConfig(block_size=16)
137 - )
134 + vllm_config = VllmConfig(model_config=model_config)
135 with set_current_vllm_config(vllm_config=vllm_config):
136 init_distributed_environment(
137 world_size=1,
tests/models/utils.py
+2 -7
@@ -457,9 +457,6 @@ def dummy_hf_overrides(
457 # Kimi uses `num_expert_group` instead of `n_group`.
458 if n_group is None:
459 n_group = getattr(text_config, "num_expert_group", None)
460 - # InternS1Pro uses `router_n_groups` instead of `n_group`.
461 - if n_group is None:
462 - n_group = getattr(text_config, "router_n_groups", None)
460 num_experts = n_group * 2 if n_group is not None else 2
461
462 # we use three layers for Gemma-3n to check
@@ -489,14 +486,12 @@ def dummy_hf_overrides(
486 # Only set MoE related config when the model has MoE layers.
487 # Otherwise all models detected as MoE by _get_transformers_backend_cls.
488 if model_arch_config.num_experts > 0:
492 - orig_topk = getattr(text_config, "num_experts_per_tok", 2)
493 - topk = min(orig_topk, 2)
489 update_dict.update(
490 {
491 "num_experts": num_experts,
497 - "num_experts_per_tok": topk,
492 + "num_experts_per_tok": 2,
493 # Kimi uses `num_experts_per_token`.
499 - "num_experts_per_token": topk,
494 + "num_experts_per_token": 2,
495 "num_local_experts": num_experts,
496 # Otherwise there will not be any expert layers
497 "first_k_dense_replace": 0,
tests/v1/spec_decode/test_eagle.py
+1 -1
@@ -78,7 +78,7 @@ def _create_proposer(
78 device = current_platform.device_type
79 vllm_config = VllmConfig(
80 model_config=model_config,
81 - cache_config=CacheConfig(block_size=16),
81 + cache_config=CacheConfig(),
82 speculative_config=speculative_config,
83 device_config=DeviceConfig(device=device),
84 parallel_config=ParallelConfig(),
vllm/config/cache.py
+7 -4
@@ -19,6 +19,7 @@ else:
19
20 logger = init_logger(__name__)
21
22 +BlockSize = Literal[1, 8, 16, 32, 64, 128, 256]
23 CacheDType = Literal[
24 "auto",
25 "bfloat16",
@@ -38,11 +39,13 @@ KVOffloadingBackend = Literal["native", "lmcache"]
39 class CacheConfig:
40 """Configuration for the KV cache."""
41
41 - block_size: SkipValidation[int] = None # type: ignore[assignment]
42 - """Size of a contiguous cache block in number of tokens.
42 + block_size: SkipValidation[BlockSize] = None # type: ignore[assignment]
43 + """Size of a contiguous cache block in number of tokens. On CUDA devices,
44 + only block sizes up to 32 are supported.
45
44 - This is None until the platform sets it. Always an int by the time
45 - the engine starts."""
46 + This config has no static default. If left unspecified by the user, it will
47 + be set in `Platform.check_and_update_config()` based on the current
48 + platform."""
49 gpu_memory_utilization: float = Field(default=0.9, gt=0, le=1)
50 """The fraction of GPU memory to be used for the model executor, which can
51 range from 0 to 1. For example, a value of 0.5 would imply 50% GPU memory
vllm/config/vllm.py
+46 -51
@@ -915,6 +915,32 @@ class VllmConfig:
915 )
916 current_platform.check_and_update_config(self)
917
918 + # If DCP, ensure the block size is right.
919 + if self.parallel_config.decode_context_parallel_size > 1:
920 + if self.parallel_config.dcp_kv_cache_interleave_size > 1 and (
921 + self.parallel_config.cp_kv_cache_interleave_size
922 + != self.parallel_config.dcp_kv_cache_interleave_size
923 + ):
924 + self.parallel_config.cp_kv_cache_interleave_size = (
925 + self.parallel_config.dcp_kv_cache_interleave_size
926 + )
927 + logger.warning_once(
928 + "cp_kv_cache_interleave_size is overridden by dcp_kv_cache"
929 + "_interleave_size. And dcp-kv-cache-interleave-size will be "
930 + "deprecated when PCP is fully supported."
931 + )
932 + assert (
933 + self.parallel_config.cp_kv_cache_interleave_size
934 + <= self.cache_config.block_size
935 + and self.cache_config.block_size
936 + % self.parallel_config.cp_kv_cache_interleave_size
937 + == 0
938 + ), (
939 + f"Block_size({self.cache_config.block_size}) should be greater "
940 + "than or equal to and divisible by cp_kv_cache_interleave_size "
941 + f"({self.parallel_config.cp_kv_cache_interleave_size})."
942 + )
943 +
944 # Do this after all the updates to compilation_config.mode
945 effective_dp_size = (
946 self.parallel_config.data_parallel_size
@@ -1082,6 +1108,26 @@ class VllmConfig:
1108 # Default to enable HMA if not explicitly disabled by user or logic above.
1109 self.scheduler_config.disable_hybrid_kv_cache_manager = False
1110
1111 + if self.cache_config.mamba_cache_mode == "align":
1112 + assert (
1113 + self.cache_config.block_size
1114 + <= self.scheduler_config.max_num_batched_tokens
1115 + ), (
1116 + "In Mamba cache align mode, block_size "
1117 + f"({self.cache_config.block_size}) must be <= "
1118 + "max_num_batched_tokens "
1119 + f"({self.scheduler_config.max_num_batched_tokens})."
1120 + )
1121 + if self.scheduler_config.long_prefill_token_threshold > 0:
1122 + assert (
1123 + self.scheduler_config.long_prefill_token_threshold
1124 + >= self.cache_config.block_size
1125 + )
1126 + assert not self.scheduler_config.disable_chunked_mm_input, (
1127 + "Chunked MM input is required because we need the flexibility to "
1128 + "schedule a multiple of block_size tokens even if they are in the "
1129 + "middle of a mm input"
1130 + )
1131 if self.compilation_config.debug_dump_path:
1132 self.compilation_config.debug_dump_path = (
1133 self.compilation_config.debug_dump_path.absolute().expanduser()
@@ -1442,57 +1488,6 @@ class VllmConfig:
1488 f"compilation_config={self.compilation_config!r}"
1489 )
1490
1445 - def validate_block_size(self) -> None:
1446 - """Validate block_size against DCP and mamba constraints.
1447 -
1448 - Called after Platform.update_block_size_for_backend() has
1449 - finalised block_size, so that the checks see the real value
1450 - rather than the initial None sentinel.
1451 - """
1452 - block_size = self.cache_config.block_size
1453 - assert block_size is not None, (
1454 - "validate_block_size called before block_size was set"
1455 - )
1456 -
1457 - # DCP interleave-size compatibility
1458 - if self.parallel_config.decode_context_parallel_size > 1:
1459 - if self.parallel_config.dcp_kv_cache_interleave_size > 1 and (
1460 - self.parallel_config.cp_kv_cache_interleave_size
1461 - != self.parallel_config.dcp_kv_cache_interleave_size
1462 - ):
1463 - self.parallel_config.cp_kv_cache_interleave_size = (
1464 - self.parallel_config.dcp_kv_cache_interleave_size
1465 - )
1466 - logger.warning_once(
1467 - "cp_kv_cache_interleave_size is overridden by dcp_kv_cache"
1468 - "_interleave_size. And dcp-kv-cache-interleave-size will be "
1469 - "deprecated when PCP is fully supported."
1470 - )
1471 - assert (
1472 - self.parallel_config.cp_kv_cache_interleave_size <= block_size
1473 - and block_size % self.parallel_config.cp_kv_cache_interleave_size == 0
1474 - ), (
1475 - f"Block_size({block_size}) should be greater "
1476 - "than or equal to and divisible by cp_kv_cache_interleave_size "
1477 - f"({self.parallel_config.cp_kv_cache_interleave_size})."
1478 - )
1479 -
1480 - # Mamba cache align-mode constraints
1481 - if self.cache_config.mamba_cache_mode == "align":
1482 - assert block_size <= self.scheduler_config.max_num_batched_tokens, (
1483 - "In Mamba cache align mode, block_size "
1484 - f"({block_size}) must be <= "
1485 - "max_num_batched_tokens "
1486 - f"({self.scheduler_config.max_num_batched_tokens})."
1487 - )
1488 - if self.scheduler_config.long_prefill_token_threshold > 0:
1489 - assert self.scheduler_config.long_prefill_token_threshold >= block_size
1490 - assert not self.scheduler_config.disable_chunked_mm_input, (
1491 - "Chunked MM input is required because we need the flexibility "
1492 - "to schedule a multiple of block_size tokens even if they are "
1493 - "in the middle of a mm input"
1494 - )
1495 -
1491 @model_validator(mode="after")
1492 def validate_mamba_block_size(self) -> "VllmConfig":
1493 if self.model_config is None:
vllm/engine/arg_utils.py
+2 -1
@@ -59,6 +59,7 @@ from vllm.config import (
59 get_attr_docs,
60 )
61 from vllm.config.cache import (
62 + BlockSize,
63 CacheDType,
64 KVOffloadingBackend,
65 MambaCacheMode,
@@ -430,7 +431,7 @@ class EngineArgs:
431 max_parallel_loading_workers: int | None = (
432 ParallelConfig.max_parallel_loading_workers
433 )
433 - block_size: int = None # type: ignore[assignment]
434 + block_size: BlockSize = CacheConfig.block_size
435 enable_prefix_caching: bool | None = None
436 prefix_caching_hash_algo: PrefixCachingHashAlgo = (
437 CacheConfig.prefix_caching_hash_algo
vllm/model_executor/layers/attention/chunked_local_attention.py
+5 -6
@@ -30,8 +30,9 @@ from vllm.v1.kv_cache_interface import (
30 def create_chunked_local_attention_backend(
31 underlying_attn_backend: AttentionBackend,
32 attention_chunk_size: int,
33 + block_size: int,
34 ) -> type[AttentionBackend]:
34 - prefix = f"ChunkedLocalAttention_{attention_chunk_size}_"
35 + prefix = f"ChunkedLocalAttention_{attention_chunk_size}_{block_size}_"
36
37 underlying_builder = underlying_attn_backend.get_builder_cls()
38 assert issubclass(underlying_builder, AttentionMetadataBuilder)
@@ -54,9 +55,7 @@ def create_chunked_local_attention_backend(
55 fast_build: bool = False,
56 ):
57 cm, make_virtual_batches_block_table = make_local_attention_virtual_batches(
57 - attention_chunk_size,
58 - common_attn_metadata,
59 - self.kv_cache_spec.block_size,
58 + attention_chunk_size, common_attn_metadata, block_size
59 )
60 metadata = super().build(common_prefix_len, cm, fast_build)
61 metadata.make_virtual_batches_block_table = make_virtual_batches_block_table
@@ -98,13 +97,13 @@ class ChunkedLocalAttention(Attention):
97 block_size = cache_config.block_size
98 else:
99 kv_cache_dtype = "auto"
101 - block_size = None
100 + block_size = 16
101
102 underlying_attn_backend = get_attn_backend(
103 head_size, dtype, kv_cache_dtype, block_size
104 )
105 attn_backend = create_chunked_local_attention_backend(
107 - underlying_attn_backend, attention_chunk_size
106 + underlying_attn_backend, attention_chunk_size, block_size
107 )
108
109 super().__init__(
vllm/model_executor/layers/attention/mla_attention.py
+5 -12
@@ -407,24 +407,17 @@ class MLAAttention(nn.Module, AttentionLayerBase):
407 )
408
409 # Attributes for forward_impl method
410 - self._vllm_config = get_current_vllm_config()
411 - self._chunked_prefill_workspace_size: int | None = None
410 + self.chunked_prefill_workspace_size = (
411 + MLACommonMetadataBuilder.determine_chunked_prefill_workspace_size(
412 + get_current_vllm_config()
413 + )
414 + )
415 self._decode_concat_quant_fp8_op = _DecodeConcatQuantFP8(
416 static=True,
417 group_shape=GroupShape.PER_TENSOR,
418 compile_native=True,
419 )
420
418 - @property
419 - def chunked_prefill_workspace_size(self) -> int:
420 - if self._chunked_prefill_workspace_size is None:
421 - self._chunked_prefill_workspace_size = (
422 - MLACommonMetadataBuilder.determine_chunked_prefill_workspace_size(
423 - self._vllm_config
424 - )
425 - )
426 - return self._chunked_prefill_workspace_size
427 -
421 def forward(
422 self,
423 q: torch.Tensor,
vllm/platforms/cuda.py
+163 -167
@@ -163,12 +163,122 @@ class CudaPlatformBase(Platform):
163
164 @classmethod
165 def check_and_update_config(cls, vllm_config: "VllmConfig") -> None:
166 + from vllm.v1.attention.backends.registry import AttentionBackendEnum
167 +
168 parallel_config = vllm_config.parallel_config
169 model_config = vllm_config.model_config
170
171 if parallel_config.worker_cls == "auto":
172 parallel_config.worker_cls = "vllm.v1.worker.gpu_worker.Worker"
173
174 + cache_config = vllm_config.cache_config
175 + if cache_config and cache_config.block_size is None:
176 + cache_config.block_size = 16
177 +
178 + # TODO(lucas): handle this more gracefully
179 + # Note: model_config may be None during testing
180 + # Note: block_size is initialized in
181 + # HybridAttentionMambaModelConfig.verify_and_update_config
182 + # for models with both attention and mamba,
183 + # and doesn't need to be reinitialized here
184 + if (
185 + model_config is not None
186 + and model_config.use_mla
187 + and cache_config.block_size is not None
188 + ):
189 + use_sparse = hasattr(vllm_config.model_config.hf_config, "index_topk")
190 + # If `--attention-config.backend` is not set and we are using MLA,
191 + # then we default to FlashMLA backend for non-blackwell GPUs,
192 + # else we default to CutlassMLA. For each case, we force the
193 + # required block_size.
194 + use_flashmla = False
195 + use_cutlass_mla = False
196 + use_flashinfer_mla = False
197 + use_flashmla_sparse = False
198 + use_flashinfer_mla_sparse = False
199 +
200 + from vllm.v1.attention.ops.flashmla import is_flashmla_dense_supported
201 +
202 + if vllm_config.attention_config.backend is None:
203 + # Default case
204 + hf_text_config = model_config.hf_text_config
205 + qk_nope_head_dim = getattr(hf_text_config, "qk_nope_head_dim", 1)
206 + if (
207 + cls.is_device_capability_family(100)
208 + and not use_sparse
209 + and qk_nope_head_dim == 128
210 + ):
211 + # Blackwell => Force FlashInfer MLA (unless sparse, i.e. DSv3.2)
212 + # and only if qk_nope_head_dim == 128 (kernel constraint)
213 + use_flashinfer_mla = True
214 + # Set the backend in AttentionConfig so it's used during
215 + # backend selection
216 + vllm_config.attention_config.backend = (
217 + AttentionBackendEnum.FLASHINFER_MLA
218 + )
219 + elif cls.is_device_capability_family(100) and not use_sparse:
220 + # Fall back to CUTLASS_MLA as 2nd priority on Blackwell
221 + use_cutlass_mla = True
222 + elif is_flashmla_dense_supported()[0]:
223 + # Non-Blackwell with FlashMLA support
224 + use_flashmla = True
225 + else:
226 + # Fallback: will use Triton MLA or other compatible backend
227 + pass
228 + else:
229 + # Forced case
230 + backend = vllm_config.attention_config.backend
231 + use_flashmla = backend == AttentionBackendEnum.FLASHMLA
232 + use_cutlass_mla = backend == AttentionBackendEnum.CUTLASS_MLA
233 + use_flashinfer_mla = backend == AttentionBackendEnum.FLASHINFER_MLA
234 + use_flashmla_sparse = backend == AttentionBackendEnum.FLASHMLA_SPARSE
235 + use_flashinfer_mla_sparse = (
236 + backend == AttentionBackendEnum.FLASHINFER_MLA_SPARSE
237 + )
238 +
239 + if (
240 + use_flashmla
241 + and is_flashmla_dense_supported()[0]
242 + and cache_config.block_size % 64 != 0
243 + ):
244 + cache_config.block_size = 64
245 + logger.info("Forcing kv cache block size to 64 for FlashMLA backend.")
246 +
247 + if use_cutlass_mla and cache_config.block_size % 128 != 0:
248 + cache_config.block_size = 128
249 + logger.info(
250 + "Forcing kv cache block size to 128 for CUTLASS_MLA backend."
251 + )
252 +
253 + if (
254 + use_flashinfer_mla
255 + and cache_config.block_size != 32
256 + and cache_config.block_size % 64 != 0
257 + ):
258 + cache_config.block_size = 64
259 + logger.info(
260 + "Forcing kv cache block size to 64 for FlashInferMLA backend."
261 + )
262 +
263 + if use_sparse:
264 + if not (use_flashmla_sparse or use_flashinfer_mla_sparse):
265 + use_flashmla_sparse = True
266 +
267 + if use_flashmla_sparse and cache_config.block_size != 64:
268 + cache_config.block_size = 64
269 + logger.info(
270 + "Forcing kv cache block size to 64 for FlashMLASparse backend."
271 + )
272 + elif use_flashinfer_mla_sparse and cache_config.block_size not in (
273 + 32,
274 + 64,
275 + ):
276 + cache_config.block_size = 64
277 + logger.info(
278 + "Forcing kv cache block size to 64 for FlashInferMLASparse "
279 + "backend."
280 + )
281 +
282 scheduler_config = vllm_config.scheduler_config
283 # Note: model_config may be None during testing
284 if (
@@ -183,49 +293,6 @@ class CudaPlatformBase(Platform):
293 )
294 scheduler_config.disable_chunked_mm_input = True
295
186 - @classmethod
187 - def update_block_size_for_backend(cls, vllm_config: "VllmConfig") -> None:
188 - cache_config = vllm_config.cache_config
189 - if cache_config.block_size is not None:
190 - # User specified --block-size; keep it.
191 - return
192 -
193 - model_config = vllm_config.model_config
194 - # model_config may be None during testing.
195 - # Skip hybrid models — their block_size is managed by
196 - # HybridAttentionMambaModelConfig.
197 - if model_config is None or model_config.is_hybrid:
198 - cache_config.block_size = 16
199 - return
200 -
201 - from vllm.config.vllm import (
202 - get_layers_from_vllm_config,
203 - set_current_vllm_config,
204 - )
205 - from vllm.model_executor.layers.attention_layer_base import (
206 - AttentionLayerBase,
207 - )
208 -
209 - attn_layers = get_layers_from_vllm_config(
210 - vllm_config,
211 - AttentionLayerBase,
212 - )
213 - if not attn_layers:
214 - cache_config.block_size = 16
215 - return
216 -
217 - first_layer = next(iter(attn_layers.values()))
218 - backend_cls = first_layer.get_attn_backend()
219 - with set_current_vllm_config(vllm_config):
220 - preferred = backend_cls.get_preferred_block_size(16)
221 - if preferred != 16:
222 - logger.info(
223 - "Setting kv cache block size to %d for %s backend.",
224 - preferred,
225 - backend_cls.get_name(),
226 - )
227 - cache_config.block_size = preferred
228 -
296 @classmethod
297 def get_current_memory_usage(
298 cls, device: torch.types.Device | None = None
@@ -242,10 +309,10 @@ class CudaPlatformBase(Platform):
309 num_heads: int | None = None,
310 ) -> tuple[
311 list[tuple["AttentionBackendEnum", int]],
245 - dict["AttentionBackendEnum", tuple[int, list[str]]],
312 + dict["AttentionBackendEnum", list[str]],
313 ]:
314 valid_backends_priorities = []
248 - invalid_reasons: dict[AttentionBackendEnum, tuple[int, list[str]]] = {}
315 + invalid_reasons = {}
316
317 backend_priorities = _get_backend_priorities(
318 attn_selector_config.use_mla,
@@ -262,155 +329,84 @@ class CudaPlatformBase(Platform):
329 except ImportError:
330 invalid_reasons_i = ["ImportError"]
331 if invalid_reasons_i:
265 - invalid_reasons[backend] = (priority, invalid_reasons_i)
332 + invalid_reasons[backend] = invalid_reasons_i
333 else:
334 valid_backends_priorities.append((backend, priority))
335
336 return valid_backends_priorities, invalid_reasons
337
338 @classmethod
272 - def select_attention_backend(
339 + def get_attn_backend_cls(
340 cls,
274 - selected_backend: "AttentionBackendEnum | None",
341 + selected_backend: "AttentionBackendEnum",
342 attn_selector_config: "AttentionSelectorConfig",
276 - device_capability: "DeviceCapability",
277 - raise_on_invalid: bool = True,
343 num_heads: int | None = None,
279 - ) -> "AttentionBackendEnum | None":
280 - """Select the best attention backend for the given configuration.
281 -
282 - Args:
283 - selected_backend: User-specified backend, or None for auto-selection
284 - attn_selector_config: Configuration for attention selection
285 - device_capability: Device capability info
286 - raise_on_invalid: If True, raise ValueError when no valid backend
287 - num_heads: Number of attention heads per GPU, used for backend
288 - priority ordering on Blackwell GPUs
289 -
290 - Returns:
291 - The selected backend enum, or None if no valid backend found
292 - and raise_on_invalid is False
293 - """
344 + ) -> str:
345 + device_capability = cls.get_device_capability()
346 + assert device_capability is not None
347 +
348 + attn_selector_config = attn_selector_config._replace(block_size=None)
349 # First try checking just the selected backend, if there is one.
350 if selected_backend is not None:
351 try:
352 backend_class = selected_backend.get_class()
298 - validation_errors = backend_class.validate_configuration(
353 + invalid_reasons = backend_class.validate_configuration(
354 device_capability=device_capability,
355 **attn_selector_config._asdict(),
356 )
357 except ImportError:
303 - validation_errors = ["ImportError"]
304 - if validation_errors:
305 - if raise_on_invalid:
306 - raise ValueError(
307 - f"Selected backend {selected_backend} is not valid for "
308 - f"this configuration. Reason: {validation_errors}"
309 - )
310 - return None
311 - return selected_backend
358 + invalid_reasons = ["ImportError"]
359 + if invalid_reasons:
360 + raise ValueError(
361 + f"Selected backend {selected_backend} is not valid for "
362 + f"this configuration. Reason: {invalid_reasons}"
363 + )
364 + else:
365 + logger.info("Using %s backend.", selected_backend)
366 + return selected_backend.get_path()
367
313 - # No selected backend, so find the best valid one.
368 + # No selected backend or the selected backend is invalid,
369 + # so we try finding a valid backend.
370 valid_backends_priorities, invalid_reasons = cls.get_valid_backends(
371 device_capability=device_capability,
372 attn_selector_config=attn_selector_config,
373 num_heads=num_heads,
374 )
319 -
375 + reasons_str = (
376 + "{"
377 + + ", ".join(
378 + f"{backend.name}: [{', '.join(reasons)}]"
379 + for backend, reasons in invalid_reasons.items()
380 + )
381 + + "}"
382 + )
383 + config_str = attn_selector_config.__repr__()
384 + logger.debug_once(
385 + f"Some attention backends are not valid for {cls.device_name} with "
386 + f"{config_str}. Reasons: {reasons_str}."
387 + )
388 if len(valid_backends_priorities) == 0:
321 - if raise_on_invalid:
322 - reasons_str = (
323 - "{"
324 - + ", ".join(
325 - f"{backend.name}: [{', '.join(reasons)}]"
326 - for backend, (_, reasons) in invalid_reasons.items()
327 - )
328 - + "}"
329 - )
330 - config_str = attn_selector_config.__repr__()
331 - raise ValueError(
332 - f"No valid attention backend found for {cls.device_name} "
333 - f"with {config_str}. Reasons: {reasons_str}."
334 - )
335 - return None
336 -
337 - # Select the one with the highest priority (lowest index).
338 - sorted_backends = sorted(valid_backends_priorities, key=lambda x: x[1])
339 - chosen_backend, chosen_priority = sorted_backends[0]
340 -
341 - # If the user specified --block-size (but not --attention-backend),
342 - # check whether that constraint precluded any higher-priority backends.
343 - if attn_selector_config.block_size is not None:
344 - excluded = [
345 - backend
346 - for backend, (priority, reasons) in invalid_reasons.items()
347 - if priority < chosen_priority
348 - and reasons == ["block_size not supported"]
349 - ]
350 - if excluded:
351 - names = ", ".join(b.name for b in excluded)
352 - logger.warning(
353 - "--block-size %d excluded higher-priority backend(s) "
354 - "%s. Using %s instead, which may result in reduced "
355 - "performance. Consider removing --block-size to "
356 - "auto-select the optimal block size.",
357 - attn_selector_config.block_size,
358 - names,
359 - chosen_backend.name,
360 - )
361 -
362 - return chosen_backend
363 -
364 - @classmethod
365 - def get_attn_backend_cls(
366 - cls,
367 - selected_backend: "AttentionBackendEnum | None",
368 - attn_selector_config: "AttentionSelectorConfig",
369 - num_heads: int | None = None,
370 - ) -> str:
371 - device_capability = cls.get_device_capability()
372 - assert device_capability is not None
389 + raise ValueError(
390 + f"No valid attention backend found for {cls.device_name} "
391 + f"with {config_str}. Reasons: {reasons_str}."
392 + )
393
374 - chosen_backend = cls.select_attention_backend(
375 - selected_backend=selected_backend,
376 - attn_selector_config=attn_selector_config,
377 - num_heads=num_heads,
378 - device_capability=device_capability,
379 - raise_on_invalid=True,
394 + # We have found some valid backends. Select the one with the
395 + # highest priority.
396 + sorted_indices = sorted(
397 + range(len(valid_backends_priorities)),
398 + key=lambda i: valid_backends_priorities[i][1],
399 + )
400 + selected_index = sorted_indices[0]
401 + selected_backend = valid_backends_priorities[selected_index][0]
402 + logger.info_once(
403 + "Using %s attention backend out of potential backends: %s.",
404 + selected_backend.name,
405 + "[" + ", ".join(f"'{b[0].name}'" for b in valid_backends_priorities) + "]",
406 + scope="local",
407 )
381 - assert chosen_backend is not None # raise_on_invalid=True guarantees this
382 -
383 - # Log the selection
384 - if selected_backend is not None:
385 - logger.info("Using %s backend.", chosen_backend)
386 - else:
387 - # Get all valid backends for logging
388 - valid_backends_priorities, invalid_reasons = cls.get_valid_backends(
389 - device_capability=device_capability,
390 - attn_selector_config=attn_selector_config,
391 - num_heads=num_heads,
392 - )
393 - reasons_str = (
394 - "{"
395 - + ", ".join(
396 - f"{backend.name}: [{', '.join(reasons)}]"
397 - for backend, (_, reasons) in invalid_reasons.items()
398 - )
399 - + "}"
400 - )
401 - config_str = attn_selector_config.__repr__()
402 - logger.debug_once(
403 - f"Some attention backends are not valid for {cls.device_name} with "
404 - f"{config_str}. Reasons: {reasons_str}."
405 - )
406 - logger.info_once(
407 - "Using %s attention backend out of potential backends: %s",
408 - chosen_backend.name,
409 - tuple(backend.name for backend, _ in valid_backends_priorities),
410 - scope="local",
411 - )
408
413 - return chosen_backend.get_path()
409 + return selected_backend.get_path()
410
411 @classmethod
412 def get_supported_vit_attn_backends(cls) -> list["AttentionBackendEnum"]:
vllm/platforms/interface.py
-7
@@ -406,13 +406,6 @@ class Platform:
406 """
407 pass
408
409 - @classmethod
410 - def update_block_size_for_backend(cls, vllm_config: "VllmConfig") -> None:
411 - """
412 - Ensure block_size is compatible with the attention backend.
413 - """
414 - pass
415 -
409 @classmethod
410 def verify_model_arch(cls, model_arch: str) -> None:
411 """
vllm/v1/attention/backend.py
+7 -12
@@ -4,7 +4,7 @@
4 from abc import ABC, abstractmethod
5 from dataclasses import dataclass, replace
6 from enum import Enum
7 -from typing import TYPE_CHECKING, Any, ClassVar, Generic, Protocol, TypeVar
7 +from typing import TYPE_CHECKING, Any, ClassVar, Generic, Protocol, TypeVar, get_args
8
9 import numpy as np
10 import torch
@@ -144,9 +144,15 @@ class AttentionBackend(ABC):
144
145 @classmethod
146 def supports_block_size(cls, block_size: int | None) -> bool:
147 + from vllm.config.cache import BlockSize
148 +
149 if block_size is None:
150 return True
151
152 + valid_sizes = get_args(BlockSize)
153 + if block_size not in valid_sizes:
154 + return False
155 +
156 supported_kernel_block_sizes = cls.get_supported_kernel_block_sizes()
157 if not supported_kernel_block_sizes:
158 return True
@@ -161,17 +167,6 @@ class AttentionBackend(ABC):
167 return True
168 return False
169
164 - @classmethod
165 - def get_preferred_block_size(cls, default_block_size: int = 16) -> int:
166 - supported_sizes = cls.get_supported_kernel_block_sizes()
167 - if not supported_sizes:
168 - return default_block_size
169 -
170 - if cls.supports_block_size(default_block_size):
171 - return default_block_size
172 -
173 - return min(s.base if isinstance(s, MultipleOf) else s for s in supported_sizes)
174 -
170 @classmethod
171 def is_mla(cls) -> bool:
172 return False
vllm/v1/engine/core.py
+1 -8
@@ -114,14 +114,7 @@ class EngineCore:
114 num_gpu_blocks, num_cpu_blocks, kv_cache_config = self._initialize_kv_caches(
115 vllm_config
116 )
117 - if kv_cache_config.kv_cache_groups:
118 - vllm_config.cache_config.block_size = min(
119 - g.kv_cache_spec.block_size for g in kv_cache_config.kv_cache_groups
120 - )
121 - elif vllm_config.cache_config.block_size is None:
122 - # Attention-free models (encoder-only, SSM) — use default.
123 - vllm_config.cache_config.block_size = 16
124 - vllm_config.validate_block_size()
117 +
118 vllm_config.cache_config.num_gpu_blocks = num_gpu_blocks
119 vllm_config.cache_config.num_cpu_blocks = num_cpu_blocks
120 self.collective_rpc("initialize_cache", args=(num_gpu_blocks, num_cpu_blocks))
vllm/v1/executor/multiproc_executor.py
-4
@@ -41,7 +41,6 @@ from vllm.distributed.parallel_state import (
41 )
42 from vllm.envs import enable_envs_cache
43 from vllm.logger import init_logger
44 -from vllm.platforms import current_platform
44 from vllm.tracing import instrument, maybe_init_worker_tracer
45 from vllm.utils.network_utils import (
46 get_distributed_init_method,
@@ -580,9 +579,6 @@ class WorkerProc:
579 self._init_message_queues(input_shm_handle, vllm_config)
580 self.worker.load_model()
581
583 - # Set block size based on the attention backends
584 - current_platform.update_block_size_for_backend(vllm_config)
585 -
582 # Enable environment variable cache (e.g. assume no more
583 # environment variable overrides after this point)
584 enable_envs_cache()
vllm/v1/executor/ray_executor.py
-5
@@ -385,11 +385,6 @@ class RayDistributedExecutor(Executor):
385 self.collective_rpc("init_device")
386 self.collective_rpc("load_model")
387
388 - def _update_block_size(worker):
389 - current_platform.update_block_size_for_backend(worker.vllm_config)
390 -
391 - self.collective_rpc(_update_block_size)
392 -
388 for pp_rank in range(self.parallel_config.pipeline_parallel_size):
389 self.pp_tp_workers.append([])
390 for tp_rank in range(self.parallel_config.tensor_parallel_size):
vllm/v1/executor/uniproc_executor.py
-2
@@ -12,7 +12,6 @@ import torch.distributed as dist
12
13 import vllm.envs as envs
14 from vllm.logger import init_logger
15 -from vllm.platforms import current_platform
15 from vllm.utils.network_utils import get_distributed_init_method, get_ip, get_open_port
16 from vllm.v1.core.sched.output import GrammarOutput, SchedulerOutput
17 from vllm.v1.engine import ReconfigureDistributedRequest, ReconfigureRankType
@@ -47,7 +46,6 @@ class UniProcExecutor(Executor):
46 self.driver_worker.init_worker(all_kwargs=[kwargs])
47 self.driver_worker.init_device()
48 self.driver_worker.load_model()
50 - current_platform.update_block_size_for_backend(self.vllm_config)
49
50 def _distributed_args(self) -> tuple[str, int, int]:
51 """Return (distributed_init_method, rank, local_rank)."""
vllm/v1/worker/gpu_model_runner.py
+2 -3
@@ -513,7 +513,6 @@ class GPUModelRunner(
513 custom_logitsprocs: Sequence[str | type[LogitsProcessor]] = (
514 tuple(logits_processors) if logits_processors is not None else ()
515 )
516 - placeholder_block_size = self.cache_config.block_size or 16
516 self.input_batch = InputBatch(
517 max_num_reqs=self.max_num_reqs,
518 # We need to use the encoder length for encoder-decoer
@@ -523,8 +522,8 @@ class GPUModelRunner(
522 device=self.device,
523 pin_memory=self.pin_memory,
524 vocab_size=self.model_config.get_vocab_size(),
526 - block_sizes=[placeholder_block_size],
527 - kernel_block_sizes=[placeholder_block_size],
525 + block_sizes=[self.cache_config.block_size],
526 + kernel_block_sizes=[self.cache_config.block_size],
527 is_spec_decode=bool(self.vllm_config.speculative_config),
528 logitsprocs=build_logitsprocs(
529 self.vllm_config,