@@ -890,31 +890,48 @@ def get_max_concurrency_for_kv_cache_config(
890890 return max_concurrency
891891
892892
893- def may_override_num_blocks (
894- vllm_config : VllmConfig , num_blocks : int , suppress_log : bool = False
895- ) -> int :
893+ def may_override_num_blocks (vllm_config : VllmConfig , num_blocks : int ) -> int :
896894 """
897895 Override the number of kv cache blocks if `num_gpu_blocks_override` is set.
896+ The override is logged once, at the call site in `get_kv_cache_configs`.
898897 """
899898 if vllm_config .cache_config .num_gpu_blocks_override is not None :
900- num_gpu_blocks_override = vllm_config .cache_config .num_gpu_blocks_override
901- if not suppress_log :
902- logger .info (
903- "Overriding num_gpu_blocks=%d with num_gpu_blocks_override=%d" ,
904- num_blocks ,
905- num_gpu_blocks_override ,
906- )
907- num_blocks = num_gpu_blocks_override
908-
899+ num_blocks = vllm_config .cache_config .num_gpu_blocks_override
909900 return num_blocks
910901
911902
903+ def _pool_bytes_per_block (kv_cache_groups : list [KVCacheGroupSpec ]) -> int :
904+ """
905+ Bytes consumed by one block in the worker's shared KV cache pool, mirroring
906+ the divisor used by `get_kv_cache_config_from_groups` to convert
907+ `available_memory` into `num_blocks`. Used to compute the effective KV cache
908+ capacity once `num_gpu_blocks_override` is applied.
909+ """
910+ if len (kv_cache_groups ) == 1 and isinstance (
911+ kv_cache_groups [0 ].kv_cache_spec , UniformTypeKVCacheSpecs
912+ ):
913+ return kv_cache_groups [0 ].kv_cache_spec .page_size_bytes
914+ if all (
915+ isinstance (g .kv_cache_spec , UniformTypeKVCacheSpecs ) for g in kv_cache_groups
916+ ):
917+ # DeepseekV4: shared layout sized by the largest per-page-size bucket.
918+ full_mla_spec = cast (UniformTypeKVCacheSpecs , kv_cache_groups [0 ].kv_cache_spec )
919+ layer_tuple_page_bytes = sum (full_mla_spec .get_page_sizes ())
920+ num_layer_tuples = max (
921+ cast (UniformTypeKVCacheSpecs , g .kv_cache_spec ).get_num_layer_tuples ()
922+ for g in kv_cache_groups
923+ )
924+ return layer_tuple_page_bytes * num_layer_tuples
925+ group_size = max (len (g .layer_names ) for g in kv_cache_groups )
926+ page_size = get_uniform_page_size ([g .kv_cache_spec for g in kv_cache_groups ])
927+ return page_size * group_size
928+
929+
912930def get_num_blocks (
913931 vllm_config : VllmConfig ,
914932 num_layers : int ,
915933 available_memory : int ,
916934 page_size : int ,
917- suppress_log : bool = False ,
918935) -> int :
919936 """
920937 Get the number of kv cache blocks.
@@ -924,15 +941,10 @@ def get_num_blocks(
924941 num_layers: The number of layers
925942 available_memory: Memory available for KV cache in bytes.
926943 page_size: The page size of the KV cache.
927- suppress_log: Whether to suppress override log messages. Used when creating a
928- temporary/dummy KV cache config, e.g. during CG memory profiling
929944 """
930945 num_blocks = int (available_memory // page_size // num_layers )
931946 num_blocks = max (num_blocks , 0 )
932- num_blocks = may_override_num_blocks (
933- vllm_config , num_blocks , suppress_log = suppress_log
934- )
935- return num_blocks
947+ return may_override_num_blocks (vllm_config , num_blocks )
936948
937949
938950def get_uniform_page_size (kv_cache_specs : Iterable [KVCacheSpec ]) -> int :
@@ -1220,7 +1232,6 @@ def get_kv_cache_config_from_groups(
12201232 vllm_config : VllmConfig ,
12211233 kv_cache_groups : list [KVCacheGroupSpec ],
12221234 available_memory : int ,
1223- suppress_log : bool = False ,
12241235) -> KVCacheConfig :
12251236 """
12261237 Generate the KV cache configuration from the KV cache groups and spec
@@ -1252,9 +1263,7 @@ def get_kv_cache_config_from_groups(
12521263 num_blocks = (
12531264 available_memory // kv_cache_groups [0 ].kv_cache_spec .page_size_bytes
12541265 )
1255- num_blocks = may_override_num_blocks (
1256- vllm_config , num_blocks , suppress_log = suppress_log
1257- )
1266+ num_blocks = may_override_num_blocks (vllm_config , num_blocks )
12581267 per_layer_specs = kv_cache_groups [0 ].kv_cache_spec .kv_cache_specs
12591268 kv_cache_tensors = [
12601269 KVCacheTensor (
@@ -1288,11 +1297,7 @@ def get_kv_cache_config_from_groups(
12881297 )
12891298 assert group_size > 0 , "group_size must be greater than 0"
12901299 num_blocks = get_num_blocks (
1291- vllm_config ,
1292- group_size ,
1293- available_memory ,
1294- page_size ,
1295- suppress_log = suppress_log ,
1300+ vllm_config , group_size , available_memory , page_size
12961301 )
12971302 kv_cache_tensors = []
12981303 for i in range (group_size ):
@@ -1688,36 +1693,24 @@ def _report_kv_cache_config(
16881693 vllm_config: The global VllmConfig
16891694 kv_cache_config: The resolved KV cache configuration
16901695 """
1691- min_block_size = min (
1692- [group .kv_cache_spec .block_size for group in kv_cache_config .kv_cache_groups ]
1693- )
1694-
1695- # Log the KV cache size and maximum concurrency.
1696- num_tokens = (
1697- kv_cache_config .num_blocks
1698- // len (kv_cache_config .kv_cache_groups )
1699- * min_block_size
1700- )
1701- dcp_size = vllm_config .parallel_config .decode_context_parallel_size
1702- pcp_size = vllm_config .parallel_config .prefill_context_parallel_size
1703- if pcp_size * dcp_size > 1 :
1704- num_tokens *= pcp_size * dcp_size
1705- logger .info (
1706- "Multiplying the GPU KV cache size by the cp_world_size %d "
1707- "(pcp_world_size %d * dcp_world_size %d)." ,
1708- pcp_size * dcp_size ,
1709- pcp_size ,
1710- dcp_size ,
1711- )
1712- num_tokens_str = f"{ num_tokens :,} "
1713- logger .info_once ("GPU KV cache size: %s tokens" , num_tokens_str )
1714- max_model_len_str = f"{ vllm_config .model_config .max_model_len :,} "
1696+ max_model_len = vllm_config .model_config .max_model_len
17151697 max_concurrency = get_max_concurrency_for_kv_cache_config (
17161698 vllm_config , kv_cache_config
17171699 )
1700+
1701+ # GPU KV cache size in tokens = max_concurrency * max_model_len: the total
1702+ # tokens of context the pool can hold at peak utilization. Sourcing this
1703+ # from the concurrency calculation handles hybrid layouts correctly: SWA /
1704+ # chunked-local groups have a per-request block count that's capped by
1705+ # their window, so a naive `num_blocks // num_groups * block_size` formula
1706+ # underestimates capacity for these models. DCP/PCP sharding is already
1707+ # accounted for in each spec's `max_memory_usage_bytes`.
1708+ num_tokens = int (max_concurrency * max_model_len )
1709+
1710+ logger .info_once ("GPU KV cache size: %s tokens" , f"{ num_tokens :,} " )
17181711 logger .info_once (
17191712 "Maximum concurrency for %s tokens per request: %.2fx" ,
1720- max_model_len_str ,
1713+ f" { max_model_len :, } " ,
17211714 max_concurrency ,
17221715 )
17231716
@@ -1988,6 +1981,28 @@ def get_kv_cache_configs(
19881981 for worker_spec in kv_cache_specs
19891982 ]
19901983
1984+ # If `num_gpu_blocks_override` is set, the cache size that will actually
1985+ # be allocated is decoupled from the profiled `available_memory`:
1986+ # `may_override_num_blocks` in `get_kv_cache_config_from_groups` clamps
1987+ # `num_blocks` to the override. Reflect that in `available_memory` here so
1988+ # auto-fit, the admission check, and the per-worker config builder all
1989+ # plan against the same effective capacity.
1990+ override = vllm_config .cache_config .num_gpu_blocks_override
1991+ if override is not None :
1992+ adjusted_memory : list [int ] = []
1993+ for groups , avail_mem in zip (projected_groups_per_worker , available_memory ):
1994+ if not groups :
1995+ adjusted_memory .append (avail_mem )
1996+ continue
1997+ bytes_per_block = _pool_bytes_per_block (groups )
1998+ logger .info (
1999+ "Overriding num_gpu_blocks=%d with num_gpu_blocks_override=%d" ,
2000+ avail_mem // bytes_per_block ,
2001+ override ,
2002+ )
2003+ adjusted_memory .append (override * bytes_per_block )
2004+ available_memory = adjusted_memory
2005+
19912006 if vllm_config .model_config .original_max_model_len == - 1 :
19922007 _auto_fit_max_model_len (
19932008 vllm_config , projected_groups_per_worker , available_memory
0 commit comments