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 15, 13:30 UTC
Improve configs - `CacheConfig` (#16835)
Signed-off-by: Harry Mellor <19981378+hmellor@users.noreply.github.com>
Harry Mellor committed
Apr 20, 2025 at 05:25 UTC
4b07d36891510ab43677695d2dbb098937eaa5e1
3 files changed
+123
-157
vllm/config.py
+69
-51
@@ -1245,22 +1245,70 @@ class ModelConfig:
1245
or getattr(self.hf_config, "is_matryoshka", False))
1246
1247
1248
+BlockSize = Literal[8, 16, 32, 64, 128]
1249
+CacheDType = Literal["auto", "fp8", "fp8_e4m3", "fp8_e5m2"]
1250
+PrefixCachingHashAlgo = Literal["builtin", "sha256"]
1251
+
1252
+
1253
+@config
1254
+@dataclass
1255
class CacheConfig:
1249
- """Configuration for the KV cache.
1256
+ """Configuration for the KV cache."""
1257
1251
- Args:
1252
- block_size: Size of a cache block in number of tokens.
1253
- gpu_memory_utilization: Fraction of GPU memory to use for the
1254
- vLLM execution.
1255
- swap_space: Size of the CPU swap space per GPU (in GiB).
1256
- cache_dtype: Data type for kv cache storage.
1257
- is_attention_free: Whether the model is attention-free.
1258
- num_gpu_blocks_override: Number of GPU blocks to use. This overrides the
1259
- profiled num_gpu_blocks if specified. Does nothing if None.
1260
- sliding_window: Sliding window size for the KV cache.
1261
- enable_prefix_caching: Whether to enable prefix caching.
1262
- cpu_offload_gb: Size of the CPU offload buffer in GiB.
1258
+ block_size: Optional[BlockSize] = None
1259
+ """Size of a contiguous cache block in number of tokens. This is ignored on
1260
+ neuron devices and set to `--max-model-len`. On CUDA devices, only block
1261
+ sizes up to 32 are supported. On HPU devices, block size defaults to 128.
1262
+ """
1263
+ gpu_memory_utilization: float = 0.9
1264
+ """The fraction of GPU memory to be used for the model executor, which can
1265
+ range from 0 to 1. For example, a value of 0.5 would imply 50% GPU memory
1266
+ utilization. If unspecified, will use the default value of 0.9. This is a
1267
+ per-instance limit, and only applies to the current vLLM instance. It does
1268
+ not matter if you have another vLLM instance running on the same GPU. For
1269
+ example, if you have two vLLM instances running on the same GPU, you can
1270
+ set the GPU memory utilization to 0.5 for each instance."""
1271
+ swap_space: float = 4
1272
+ """Size of the CPU swap space per GPU (in GiB)."""
1273
+ cache_dtype: CacheDType = "auto"
1274
+ """Data type for kv cache storage. If "auto", will use model data type.
1275
+ CUDA 11.8+ supports fp8 (=fp8_e4m3) and fp8_e5m2. ROCm (AMD GPU) supports
1276
+ fp8 (=fp8_e4m3)."""
1277
+ is_attention_free: bool = False
1278
+ """Whether the model is attention-free. This is primarily set in
1279
+ `ModelConfig` and that value should be manually duplicated here."""
1280
+ num_gpu_blocks_override: Optional[int] = None
1281
+ """Number of GPU blocks to use. This overrides the profiled `num_gpu_blocks`
1282
+ if specified. Does nothing if `None`. Used for testing preemption."""
1283
+ sliding_window: Optional[int] = None
1284
+ """Sliding window size for the KV cache. This is primarily set in
1285
+ `ModelConfig` and that value should be manually duplicated here."""
1286
+ enable_prefix_caching: Optional[bool] = None
1287
+ """Whether to enable prefix caching. Disabled by default for V0. Enabled by
1288
+ default for V1."""
1289
+ prefix_caching_hash_algo: PrefixCachingHashAlgo = "builtin"
1290
+ """Set the hash algorithm for prefix caching:\n
1291
+ - "builtin" is Python's built-in hash.\n
1292
+ - "sha256" is collision resistant but with certain overheads."""
1293
+ cpu_offload_gb: float = 0
1294
+ """The space in GiB to offload to CPU, per GPU. Default is 0, which means
1295
+ no offloading. Intuitively, this argument can be seen as a virtual way to
1296
+ increase the GPU memory size. For example, if you have one 24 GB GPU and
1297
+ set this to 10, virtually you can think of it as a 34 GB GPU. Then you can
1298
+ load a 13B model with BF16 weight, which requires at least 26GB GPU memory.
1299
+ Note that this requires fast CPU-GPU interconnect, as part of the model is
1300
+ loaded from CPU memory to GPU memory on the fly in each model forward pass.
1301
"""
1302
+ calculate_kv_scales: bool = False
1303
+ """This enables dynamic calculation of `k_scale` and `v_scale` when
1304
+ kv_cache_dtype is fp8. If `False`, the scales will be loaded from the model
1305
+ checkpoint if available. Otherwise, the scales will default to 1.0."""
1306
+
1307
+ # Will be set after profiling.
1308
+ num_gpu_blocks: Optional[int] = field(default=None, init=False)
1309
+ """The number of blocks to allocate for GPU memory."""
1310
+ num_cpu_blocks: Optional[int] = field(default=None, init=False)
1311
+ """The number of blocks to allocate for CPU memory."""
1312
1313
def compute_hash(self) -> str:
1314
"""
@@ -1281,43 +1329,13 @@ class CacheConfig:
1329
usedforsecurity=False).hexdigest()
1330
return hash_str
1331
1284
- def __init__(
1285
- self,
1286
- block_size: int,
1287
- gpu_memory_utilization: float,
1288
- swap_space: float,
1289
- cache_dtype: str,
1290
- is_attention_free: bool = False,
1291
- num_gpu_blocks_override: Optional[int] = None,
1292
- sliding_window: Optional[int] = None,
1293
- enable_prefix_caching: bool = False,
1294
- prefix_caching_hash_algo: str = "builtin",
1295
- cpu_offload_gb: float = 0,
1296
- calculate_kv_scales: Optional[bool] = None,
1297
- ) -> None:
1298
- self.block_size = block_size
1299
- self.gpu_memory_utilization = gpu_memory_utilization
1300
- self.swap_space_bytes = swap_space * GiB_bytes
1301
- self.num_gpu_blocks_override = num_gpu_blocks_override
1302
- self.cache_dtype = cache_dtype
1303
- self.is_attention_free = is_attention_free
1304
- self.sliding_window = sliding_window
1305
- self.enable_prefix_caching = enable_prefix_caching
1306
- self.prefix_caching_hash_algo = prefix_caching_hash_algo
1307
- self.cpu_offload_gb = cpu_offload_gb
1308
- self.calculate_kv_scales = calculate_kv_scales
1332
+ def __post_init__(self) -> None:
1333
+ self.swap_space_bytes = self.swap_space * GiB_bytes
1334
+
1335
self._verify_args()
1336
self._verify_cache_dtype()
1337
self._verify_prefix_caching()
1338
1313
- # Will be set after profiling.
1314
- self.num_gpu_blocks: Optional[int] = None
1315
- self.num_cpu_blocks: Optional[int] = None
1316
-
1317
- # Set calculate_kv_scales to False if the value is unset.
1318
- if self.calculate_kv_scales is None:
1319
- self.calculate_kv_scales = False
1320
-
1339
def metrics_info(self):
1340
# convert cache_config to dict(key: str, value: str) for prometheus
1341
# metrics info
@@ -1336,7 +1354,7 @@ class CacheConfig:
1354
def _verify_cache_dtype(self) -> None:
1355
if self.cache_dtype == "auto":
1356
pass
1339
- elif self.cache_dtype in ("fp8", "fp8_e4m3", "fp8_e5m2"):
1357
+ elif self.cache_dtype in get_args(CacheDType):
1358
logger.info(
1359
"Using fp8 data type to store kv cache. It reduces the GPU "
1360
"memory footprint and boosts the performance. "
@@ -1354,12 +1372,12 @@ class CacheConfig:
1372
"Prefix caching is not supported with sliding window. "
1373
"Run with --disable-sliding-window to use prefix caching.")
1374
1357
- if self.enable_prefix_caching and self.prefix_caching_hash_algo not in (
1358
- "builtin", "sha256"):
1375
+ if (self.enable_prefix_caching and self.prefix_caching_hash_algo
1376
+ not in get_args(PrefixCachingHashAlgo)):
1377
raise ValueError(
1378
"Unknown prefix caching hash algorithm: "
1361
- f"{self.prefix_caching_hash_algo}. Must be either "
1362
- "'builtin' or 'sha256'.")
1379
+ f"{self.prefix_caching_hash_algo}. Must be one of "
1380
+ f"{get_args(PrefixCachingHashAlgo)}.")
1381
1382
def verify_with_parallel_config(
1383
self,
vllm/engine/arg_utils.py
+53
-105
@@ -16,16 +16,16 @@ from typing_extensions import TypeIs
16
17
import vllm.envs as envs
18
from vllm import version
19
-from vllm.config import (CacheConfig, CompilationConfig, Config, ConfigFormat,
20
- DecodingConfig, Device, DeviceConfig,
21
- DistributedExecutorBackend, HfOverrides,
19
+from vllm.config import (BlockSize, CacheConfig, CacheDType, CompilationConfig,
20
+ Config, ConfigFormat, DecodingConfig, Device,
21
+ DeviceConfig, DistributedExecutorBackend, HfOverrides,
22
KVTransferConfig, LoadConfig, LoadFormat, LoRAConfig,
23
ModelConfig, ModelImpl, MultiModalConfig,
24
ObservabilityConfig, ParallelConfig, PoolerConfig,
25
- PoolType, PromptAdapterConfig, SchedulerConfig,
26
- SchedulerPolicy, SpeculativeConfig, TaskOption,
27
- TokenizerPoolConfig, VllmConfig, get_attr_docs,
28
- get_field)
25
+ PoolType, PrefixCachingHashAlgo, PromptAdapterConfig,
26
+ SchedulerConfig, SchedulerPolicy, SpeculativeConfig,
27
+ TaskOption, TokenizerPoolConfig, VllmConfig,
28
+ get_attr_docs, get_field)
29
from vllm.executor.executor_base import ExecutorBase
30
from vllm.logger import init_logger
31
from vllm.model_executor.layers.quantization import QUANTIZATION_METHODS
@@ -138,7 +138,7 @@ class EngineArgs:
138
load_format: str = LoadConfig.load_format
139
config_format: ConfigFormat = ConfigFormat.AUTO
140
dtype: str = 'auto'
141
- kv_cache_dtype: str = 'auto'
141
+ kv_cache_dtype: CacheDType = CacheConfig.cache_dtype
142
seed: Optional[int] = None
143
max_model_len: Optional[int] = None
144
# Note: Specifying a custom executor backend by passing a class
@@ -154,15 +154,16 @@ class EngineArgs:
154
enable_expert_parallel: bool = ParallelConfig.enable_expert_parallel
155
max_parallel_loading_workers: Optional[
156
int] = ParallelConfig.max_parallel_loading_workers
157
- block_size: Optional[int] = None
158
- enable_prefix_caching: Optional[bool] = None
159
- prefix_caching_hash_algo: str = "builtin"
157
+ block_size: Optional[BlockSize] = CacheConfig.block_size
158
+ enable_prefix_caching: Optional[bool] = CacheConfig.enable_prefix_caching
159
+ prefix_caching_hash_algo: PrefixCachingHashAlgo = \
160
+ CacheConfig.prefix_caching_hash_algo
161
disable_sliding_window: bool = False
162
disable_cascade_attn: bool = False
163
use_v2_block_manager: bool = True
163
- swap_space: float = 4 # GiB
164
- cpu_offload_gb: float = 0 # GiB
165
- gpu_memory_utilization: float = 0.90
164
+ swap_space: float = CacheConfig.swap_space
165
+ cpu_offload_gb: float = CacheConfig.cpu_offload_gb
166
+ gpu_memory_utilization: float = CacheConfig.gpu_memory_utilization
167
max_num_batched_tokens: Optional[
168
int] = SchedulerConfig.max_num_batched_tokens
169
max_num_partial_prefills: int = SchedulerConfig.max_num_partial_prefills
@@ -211,7 +212,8 @@ class EngineArgs:
212
num_scheduler_steps: int = SchedulerConfig.num_scheduler_steps
213
multi_step_stream_outputs: bool = SchedulerConfig.multi_step_stream_outputs
214
ray_workers_use_nsight: bool = ParallelConfig.ray_workers_use_nsight
214
- num_gpu_blocks_override: Optional[int] = None
215
+ num_gpu_blocks_override: Optional[
216
+ int] = CacheConfig.num_gpu_blocks_override
217
num_lookahead_slots: int = SchedulerConfig.num_lookahead_slots
218
model_loader_extra_config: dict = \
219
get_field(LoadConfig, "model_loader_extra_config")
@@ -250,7 +252,7 @@ class EngineArgs:
252
enable_sleep_mode: bool = False
253
model_impl: str = "auto"
254
253
- calculate_kv_scales: Optional[bool] = None
255
+ calculate_kv_scales: bool = CacheConfig.calculate_kv_scales
256
257
additional_config: Optional[Dict[str, Any]] = None
258
enable_reasoning: Optional[bool] = None
@@ -306,12 +308,19 @@ class EngineArgs:
308
cls_docs = get_attr_docs(cls)
309
kwargs = {}
310
for field in fields(cls):
309
- name = field.name
311
+ # Get the default value of the field
312
default = field.default
311
- # This will only be True if default is MISSING
313
if field.default_factory is not MISSING:
314
default = field.default_factory()
314
- kwargs[name] = {"default": default, "help": cls_docs[name]}
315
+
316
+ # Get the help text for the field
317
+ name = field.name
318
+ help = cls_docs[name]
319
+ # Escape % for argparse
320
+ help = help.replace("%", "%%")
321
+
322
+ # Initialise the kwargs dictionary for the field
323
+ kwargs[name] = {"default": default, "help": help}
324
325
# Make note of if the field is optional and get the actual
326
# type of the field if it is
@@ -319,6 +328,8 @@ class EngineArgs:
328
field_type = get_args(
329
field.type)[0] if optional else field.type
330
331
+ # Set type, action and choices for the field depending on the
332
+ # type of the field
333
if can_be_type(field_type, bool):
334
# Creates --no-<name> and --<name> flags
335
kwargs[name]["action"] = argparse.BooleanOptionalAction
@@ -463,14 +474,6 @@ class EngineArgs:
474
'* "bfloat16" for a balance between precision and range.\n'
475
'* "float" is shorthand for FP32 precision.\n'
476
'* "float32" for FP32 precision.')
466
- parser.add_argument(
467
- '--kv-cache-dtype',
468
- type=str,
469
- choices=['auto', 'fp8', 'fp8_e5m2', 'fp8_e4m3'],
470
- default=EngineArgs.kv_cache_dtype,
471
- help='Data type for kv cache storage. If "auto", will use model '
472
- 'data type. CUDA 11.8+ supports fp8 (=fp8_e4m3) and fp8_e5m2. '
473
- 'ROCm (AMD GPU) supports fp8 (=fp8_e4m3)')
477
parser.add_argument('--max-model-len',
478
type=human_readable_int,
479
default=EngineArgs.max_model_len,
@@ -544,33 +547,30 @@ class EngineArgs:
547
parallel_group.add_argument(
548
'--disable-custom-all-reduce',
549
**parallel_kwargs["disable_custom_all_reduce"])
547
- # KV cache arguments
548
- parser.add_argument('--block-size',
549
- type=int,
550
- default=EngineArgs.block_size,
551
- choices=[8, 16, 32, 64, 128],
552
- help='Token block size for contiguous chunks of '
553
- 'tokens. This is ignored on neuron devices and '
554
- 'set to ``--max-model-len``. On CUDA devices, '
555
- 'only block sizes up to 32 are supported. '
556
- 'On HPU devices, block size defaults to 128.')
550
558
- parser.add_argument(
559
- "--enable-prefix-caching",
560
- action=argparse.BooleanOptionalAction,
561
- default=EngineArgs.enable_prefix_caching,
562
- help="Enables automatic prefix caching. "
563
- "Use ``--no-enable-prefix-caching`` to disable explicitly.",
564
- )
565
- parser.add_argument(
566
- "--prefix-caching-hash-algo",
567
- type=str,
568
- choices=["builtin", "sha256"],
569
- default=EngineArgs.prefix_caching_hash_algo,
570
- help="Set the hash algorithm for prefix caching. "
571
- "Options are 'builtin' (Python's built-in hash) or 'sha256' "
572
- "(collision resistant but with certain overheads).",
551
+ # KV cache arguments
552
+ cache_kwargs = get_kwargs(CacheConfig)
553
+ cache_group = parser.add_argument_group(
554
+ title="CacheConfig",
555
+ description=CacheConfig.__doc__,
556
)
557
+ cache_group.add_argument('--block-size', **cache_kwargs["block_size"])
558
+ cache_group.add_argument('--gpu-memory-utilization',
559
+ **cache_kwargs["gpu_memory_utilization"])
560
+ cache_group.add_argument('--swap-space', **cache_kwargs["swap_space"])
561
+ cache_group.add_argument('--kv-cache-dtype',
562
+ **cache_kwargs["cache_dtype"])
563
+ cache_group.add_argument('--num-gpu-blocks-override',
564
+ **cache_kwargs["num_gpu_blocks_override"])
565
+ cache_group.add_argument("--enable-prefix-caching",
566
+ **cache_kwargs["enable_prefix_caching"])
567
+ cache_group.add_argument("--prefix-caching-hash-algo",
568
+ **cache_kwargs["prefix_caching_hash_algo"])
569
+ cache_group.add_argument('--cpu-offload-gb',
570
+ **cache_kwargs["cpu_offload_gb"])
571
+ cache_group.add_argument('--calculate-kv-scales',
572
+ **cache_kwargs["calculate_kv_scales"])
573
+
574
parser.add_argument('--disable-sliding-window',
575
action='store_true',
576
help='Disables sliding window, '
@@ -588,43 +588,6 @@ class EngineArgs:
588
type=int,
589
default=EngineArgs.seed,
590
help='Random seed for operations.')
591
- parser.add_argument('--swap-space',
592
- type=float,
593
- default=EngineArgs.swap_space,
594
- help='CPU swap space size (GiB) per GPU.')
595
- parser.add_argument(
596
- '--cpu-offload-gb',
597
- type=float,
598
- default=0,
599
- help='The space in GiB to offload to CPU, per GPU. '
600
- 'Default is 0, which means no offloading. Intuitively, '
601
- 'this argument can be seen as a virtual way to increase '
602
- 'the GPU memory size. For example, if you have one 24 GB '
603
- 'GPU and set this to 10, virtually you can think of it as '
604
- 'a 34 GB GPU. Then you can load a 13B model with BF16 weight, '
605
- 'which requires at least 26GB GPU memory. Note that this '
606
- 'requires fast CPU-GPU interconnect, as part of the model is '
607
- 'loaded from CPU memory to GPU memory on the fly in each '
608
- 'model forward pass.')
609
- parser.add_argument(
610
- '--gpu-memory-utilization',
611
- type=float,
612
- default=EngineArgs.gpu_memory_utilization,
613
- help='The fraction of GPU memory to be used for the model '
614
- 'executor, which can range from 0 to 1. For example, a value of '
615
- '0.5 would imply 50%% GPU memory utilization. If unspecified, '
616
- 'will use the default value of 0.9. This is a per-instance '
617
- 'limit, and only applies to the current vLLM instance.'
618
- 'It does not matter if you have another vLLM instance running '
619
- 'on the same GPU. For example, if you have two vLLM instances '
620
- 'running on the same GPU, you can set the GPU memory utilization '
621
- 'to 0.5 for each instance.')
622
- parser.add_argument(
623
- '--num-gpu-blocks-override',
624
- type=int,
625
- default=None,
626
- help='If specified, ignore GPU profiling result and use this number'
627
- ' of GPU blocks. Used for testing preemption.')
591
parser.add_argument(
592
'--max-logprobs',
593
type=int,
@@ -994,15 +957,6 @@ class EngineArgs:
957
help="Enable sleep mode for the engine. "
958
"(only cuda platform is supported)")
959
997
- parser.add_argument(
998
- '--calculate-kv-scales',
999
- action='store_true',
1000
- help='This enables dynamic calculation of '
1001
- 'k_scale and v_scale when kv-cache-dtype is fp8. '
1002
- 'If calculate-kv-scales is false, the scales will '
1003
- 'be loaded from the model checkpoint if available. '
1004
- 'Otherwise, the scales will default to 1.0.')
1005
-
960
parser.add_argument(
961
"--additional-config",
962
type=json.loads,
@@ -1625,9 +1579,7 @@ class EngineArgs:
1579
self.enable_prefix_caching = False
1580
1581
# VLLM_V0 only supports builtin hash algo for prefix caching.
1628
- if self.prefix_caching_hash_algo is None:
1629
- self.prefix_caching_hash_algo = "builtin"
1630
- elif self.prefix_caching_hash_algo == "sha256":
1582
+ if self.prefix_caching_hash_algo == "sha256":
1583
raise ValueError(
1584
"sha256 is not supported for prefix caching in V0 engine. "
1585
"Please use 'builtin'.")
@@ -1646,10 +1598,6 @@ class EngineArgs:
1598
if self.enable_prefix_caching is None:
1599
self.enable_prefix_caching = True
1600
1649
- # if using prefix caching, we must set a hash algo
1650
- if self.enable_prefix_caching and self.prefix_caching_hash_algo is None:
1651
- self.prefix_caching_hash_algo = "builtin"
1652
-
1601
# V1 should use the new scheduler by default.
1602
# Swap it only if this arg is set to the original V0 default
1603
if self.scheduler_cls == EngineArgs.scheduler_cls:
vllm/platforms/neuron.py
+1
-1
@@ -50,7 +50,7 @@ class NeuronPlatform(Platform):
50
if cache_config:
51
# neuron needs block_size = max_model_len
52
vllm_config.cache_config.block_size = \
53
- vllm_config.model_config.max_model_len
53
+ vllm_config.model_config.max_model_len # type: ignore
54
55
@classmethod
56
def is_pin_memory_available(cls) -> bool: