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 14, 05:30 UTC
Allow users to specify kv cache memory size (#21489)
Signed-off-by: Boyuan Feng <boyuan@meta.com> Signed-off-by: Harry Mellor <19981378+hmellor@users.noreply.github.com> Co-authored-by: Harry Mellor <19981378+hmellor@users.noreply.github.com>
Boyuan Feng committed
Sep 11, 2025 at 06:41 UTC
94e6b2d55f7fd539f01591c7521ec104b25f4e68
10 files changed
+236
-47
vllm/config/cache.py
+9
@@ -113,6 +113,15 @@ class CacheConfig:
113
necessary for implementing this optimization in some models (e.g. Gemma3n)
114
"""
115
116
+ kv_cache_memory_bytes: Optional[int] = None
117
+ """Size of KV Cache per GPU in bytes. By default, this is set to None
118
+ and vllm can automatically infer the kv cache size based on
119
+ gpu_memory_utilization. However, users may want to manually specify
120
+ the kv cache memory size. kv_cache_memory_bytes allows more fine-grain
121
+ control of how much memory gets used when compared with using
122
+ gpu_memory_memory_utilization. Note that kv_cache_memory_bytes
123
+ (when not-None) ignores gpu_memory_utilization"""
124
+
125
def compute_hash(self) -> str:
126
"""
127
WARNING: Whenever a new field is added to this config,
vllm/engine/arg_utils.py
+11
-1
@@ -227,8 +227,14 @@ def _compute_kwargs(cls: ConfigType) -> dict[str, Any]:
227
elif contains_type(type_hints, int):
228
kwargs[name]["type"] = int
229
# Special case for large integers
230
- if name in {"max_model_len", "max_num_batched_tokens"}:
230
+ human_readable_ints = {
231
+ "max_model_len",
232
+ "max_num_batched_tokens",
233
+ "kv_cache_memory_bytes",
234
+ }
235
+ if name in human_readable_ints:
236
kwargs[name]["type"] = human_readable_int
237
+ kwargs[name]["help"] += f"\n\n{human_readable_int.__doc__}"
238
elif contains_type(type_hints, float):
239
kwargs[name]["type"] = float
240
elif (contains_type(type_hints, dict)
@@ -335,6 +341,7 @@ class EngineArgs:
341
swap_space: float = CacheConfig.swap_space
342
cpu_offload_gb: float = CacheConfig.cpu_offload_gb
343
gpu_memory_utilization: float = CacheConfig.gpu_memory_utilization
344
+ kv_cache_memory_bytes: Optional[int] = CacheConfig.kv_cache_memory_bytes
345
max_num_batched_tokens: Optional[
346
int] = SchedulerConfig.max_num_batched_tokens
347
max_num_partial_prefills: int = SchedulerConfig.max_num_partial_prefills
@@ -734,6 +741,8 @@ class EngineArgs:
741
cache_group.add_argument("--block-size", **cache_kwargs["block_size"])
742
cache_group.add_argument("--gpu-memory-utilization",
743
**cache_kwargs["gpu_memory_utilization"])
744
+ cache_group.add_argument("--kv-cache-memory-bytes",
745
+ **cache_kwargs["kv_cache_memory_bytes"])
746
cache_group.add_argument("--swap-space", **cache_kwargs["swap_space"])
747
cache_group.add_argument("--kv-cache-dtype",
748
**cache_kwargs["cache_dtype"])
@@ -1174,6 +1183,7 @@ class EngineArgs:
1183
cache_config = CacheConfig(
1184
block_size=self.block_size,
1185
gpu_memory_utilization=self.gpu_memory_utilization,
1186
+ kv_cache_memory_bytes=self.kv_cache_memory_bytes,
1187
swap_space=self.swap_space,
1188
cache_dtype=self.kv_cache_dtype,
1189
is_attention_free=model_config.is_attention_free,
vllm/engine/llm_engine.py
+2
-1
@@ -278,7 +278,8 @@ class LLMEngine:
278
self.cache_config.block_size,
279
"gpu_memory_utilization":
280
self.cache_config.gpu_memory_utilization,
281
-
281
+ "kv_cache_memory_bytes":
282
+ self.cache_config.kv_cache_memory_bytes,
283
# Quantization
284
"quantization":
285
self.model_config.quantization,
vllm/entrypoints/llm.py
+10
@@ -110,6 +110,14 @@ class LLM:
110
values will increase the KV cache size and thus improve the model's
111
throughput. However, if the value is too high, it may cause out-of-
112
memory (OOM) errors.
113
+ kv_cache_memory_bytes: Size of KV Cache per GPU in bytes. By default,
114
+ this is set to None and vllm can automatically infer the kv cache
115
+ size based on gpu_memory_utilization. However, users may want to
116
+ manually specify the kv cache memory size. kv_cache_memory_bytes
117
+ allows more fine-grain control of how much memory gets used when
118
+ compared with using gpu_memory_memory_utilization. Note that
119
+ kv_cache_memory_bytes (when not-None) ignores
120
+ gpu_memory_utilization
121
swap_space: The size (GiB) of CPU memory per GPU to use as swap space.
122
This can be used for temporarily storing the states of the requests
123
when their `best_of` sampling parameters are larger than 1. If all
@@ -184,6 +192,7 @@ class LLM:
192
hf_overrides: Optional[HfOverrides] = None,
193
mm_processor_kwargs: Optional[dict[str, Any]] = None,
194
override_pooler_config: Optional[PoolerConfig] = None,
195
+ kv_cache_memory_bytes: Optional[int] = None,
196
compilation_config: Optional[Union[int, dict[str, Any],
197
CompilationConfig]] = None,
198
logits_processors: Optional[list[Union[str,
@@ -251,6 +260,7 @@ class LLM:
260
tokenizer_revision=tokenizer_revision,
261
seed=seed,
262
gpu_memory_utilization=gpu_memory_utilization,
263
+ kv_cache_memory_bytes=kv_cache_memory_bytes,
264
swap_space=swap_space,
265
cpu_offload_gb=cpu_offload_gb,
266
enforce_eager=enforce_eager,
vllm/utils/__init__.py
+4
-1
@@ -2791,7 +2791,10 @@ def memory_profiling(
2791
result.torch_peak_increase = diff_profile.torch_peak
2792
result.non_torch_increase = diff_from_create.non_torch_memory
2793
result.profile_time = diff_profile.timestamp
2794
- result.non_kv_cache_memory = result.non_torch_increase + result.torch_peak_increase + result.weights_memory # noqa
2794
+
2795
+ non_torch_memory = result.non_torch_increase
2796
+ peak_activation_memory = result.torch_peak_increase
2797
+ result.non_kv_cache_memory = non_torch_memory + peak_activation_memory + result.weights_memory # noqa
2798
2799
2800
# Adapted from: https://github.com/sgl-project/sglang/blob/v0.4.1/python/sglang/srt/utils.py#L630 # noqa: E501
vllm/v1/utils.py
+2
-1
@@ -355,7 +355,8 @@ def report_usage_stats(
355
vllm_config.cache_config.block_size,
356
"gpu_memory_utilization":
357
vllm_config.cache_config.gpu_memory_utilization,
358
-
358
+ "kv_cache_memory_bytes":
359
+ vllm_config.cache_config.kv_cache_memory_bytes,
360
# Quantization
361
"quantization":
362
vllm_config.model_config.quantization,
vllm/v1/worker/gpu_model_runner.py
+3
-2
@@ -3041,12 +3041,12 @@ class GPUModelRunner(LoRAModelRunnerMixin, KVConnectorModelRunnerMixin):
3041
self.encoder_cache.clear()
3042
gc.collect()
3043
3044
- def capture_model(self) -> None:
3044
+ def capture_model(self) -> int:
3045
if self.compilation_config.cudagraph_mode == CUDAGraphMode.NONE:
3046
logger.warning(
3047
"Skipping CUDA graph capture. To turn on CUDA graph capture, "
3048
"ensure `cudagraph_mode` was not manually set to `NONE`")
3049
- return
3049
+ return 0
3050
else:
3051
self.initialize_cudagraph_capture()
3052
@@ -3117,6 +3117,7 @@ class GPUModelRunner(LoRAModelRunnerMixin, KVConnectorModelRunnerMixin):
3117
# This usually takes 5~20 seconds.
3118
logger.info("Graph capturing finished in %.0f secs, took %.2f GiB",
3119
elapsed_time, cuda_graph_size / (1 << 30))
3120
+ return cuda_graph_size
3121
3122
def _capture_cudagraphs(self, compilation_cases: list[int],
3123
cudagraph_runtime_mode: CUDAGraphMode,
vllm/v1/worker/gpu_worker.py
+77
-7
@@ -231,18 +231,40 @@ class Worker(WorkerBase):
231
You may limit the usage of GPU memory
232
by adjusting the `gpu_memory_utilization` parameter.
233
"""
234
+ GiB = lambda b: b / GiB_bytes
235
+ if kv_cache_memory_bytes := self.cache_config.kv_cache_memory_bytes:
236
+ # still need a profile run which compiles the model for
237
+ # max_num_batched_tokens
238
+ self.model_runner.profile_run()
239
+
240
+ msg = (
241
+ f"Initial free memory {GiB(self.init_snapshot.free_memory)} "
242
+ f"GiB, reserved {GiB(kv_cache_memory_bytes):.2f}GiB memory for "
243
+ "KV Cache as specified by kv_cache_memory_bytes config and "
244
+ "skipped memory profiling. This does does not respect the "
245
+ "gpu_memory_utilization config. Only use kv_cache_memory_bytes "
246
+ "config when you want manual control of KV cache memory "
247
+ "size. If OOM'ed, check the difference of initial free "
248
+ "memory between the current run and the previous run "
249
+ "where kv_cache_memory_bytes is suggested and update it "
250
+ "correspondingly.")
251
+ logger.info(msg)
252
+ return kv_cache_memory_bytes
253
+
254
torch.cuda.empty_cache()
255
torch.cuda.reset_peak_memory_stats()
236
- GiB = lambda b: b / GiB_bytes
256
257
# Execute a forward pass with dummy inputs to profile the memory usage
258
# of the model.
259
with memory_profiling(
260
self.init_snapshot,
242
- weights_memory=int(
243
- self.model_runner.model_memory_usage)) as profile_result:
261
+ weights_memory=int(self.model_runner.model_memory_usage),
262
+ ) as profile_result:
263
self.model_runner.profile_run()
264
265
+ self.non_torch_memory = profile_result.non_torch_increase
266
+ self.peak_activation_memory = profile_result.torch_peak_increase
267
+
268
free_gpu_memory = profile_result.after_profile.free_memory
269
# NOTE(woosuk): Here we assume that the other processes using the same
270
# GPU did not change their memory usage during the profiling.
@@ -254,7 +276,7 @@ class Worker(WorkerBase):
276
"release GPU memory while vLLM is profiling during initialization. "
277
"To fix this, ensure consistent GPU memory allocation or "
278
"isolate vLLM in its own container.")
257
- available_kv_cache_memory = self.requested_memory \
279
+ self.available_kv_cache_memory_bytes = self.requested_memory \
280
- profile_result.non_kv_cache_memory
281
282
unrequested_memory = self.init_snapshot.free_memory \
@@ -274,10 +296,10 @@ class Worker(WorkerBase):
296
)
297
logger.debug(profile_result)
298
logger.info("Available KV cache memory: %.2f GiB",
277
- GiB(available_kv_cache_memory))
299
+ GiB(self.available_kv_cache_memory_bytes))
300
gc.collect()
301
280
- return int(available_kv_cache_memory)
302
+ return int(self.available_kv_cache_memory_bytes)
303
304
def get_kv_cache_spec(self) -> dict[str, KVCacheSpec]:
305
return self.model_runner.get_kv_cache_spec()
@@ -317,8 +339,56 @@ class Worker(WorkerBase):
339
# cuda graph capture.
340
kernel_warmup(self)
341
342
+ cuda_graph_memory_bytes = 0
343
if not self.model_config.enforce_eager:
321
- self.model_runner.capture_model()
344
+ cuda_graph_memory_bytes = self.model_runner.capture_model()
345
+
346
+ if (self.cache_config.kv_cache_memory_bytes is None
347
+ and hasattr(self, "peak_activation_memory")):
348
+ # Suggests optimal kv cache memory size if we rely on
349
+ # memory_profiling to guess the kv cache memory size which
350
+ # provides peak_activation_memory and a few other memory
351
+ # consumption. `memory_profiling` does not consider
352
+ # CUDAGraph memory size and may not utilize all gpu memory.
353
+ # Users may want fine-grained control to specify kv cache
354
+ # memory size.
355
+ GiB = lambda b: round(b / GiB_bytes, 2)
356
+
357
+ # empirically observed that the memory profiling may
358
+ # slightly underestimate the memory consumption.
359
+ # So leave a small buffer (=150MiB) to avoid OOM.
360
+ redundancy_buffer_memory = 150 * (1 << 20)
361
+ non_kv_cache_memory = (self.model_runner.model_memory_usage +
362
+ self.peak_activation_memory +
363
+ self.non_torch_memory +
364
+ cuda_graph_memory_bytes)
365
+ kv_cache_memory_bytes_to_gpu_limit = (
366
+ self.init_snapshot.free_memory - non_kv_cache_memory -
367
+ redundancy_buffer_memory)
368
+ kv_cache_memory_bytes_to_requested_limit = (
369
+ int(self.requested_memory) - non_kv_cache_memory -
370
+ redundancy_buffer_memory)
371
+
372
+ msg = (
373
+ f"Free memory on device "
374
+ f"({GiB(self.init_snapshot.free_memory)}/"
375
+ f"{GiB(self.init_snapshot.total_memory)} GiB) on startup. "
376
+ f"Desired GPU memory utilization is "
377
+ f"({self.cache_config.gpu_memory_utilization}, "
378
+ f"{GiB(self.requested_memory)} GiB). "
379
+ f"Actual usage is {GiB(self.model_runner.model_memory_usage)} "
380
+ f"GiB for weight, {GiB(self.peak_activation_memory)} GiB "
381
+ f"for peak activation, {GiB(self.non_torch_memory)} GiB "
382
+ f"for non-torch memory, and {GiB(cuda_graph_memory_bytes)} "
383
+ f"GiB for CUDAGraph memory. Replace gpu_memory_utilization "
384
+ f"config with `--kv-cache-memory="
385
+ f"{kv_cache_memory_bytes_to_requested_limit}` to fit into "
386
+ f"requested memory, or `--kv-cache-memory="
387
+ f"{kv_cache_memory_bytes_to_gpu_limit}` to fully "
388
+ f"utilize gpu memory. Current kv cache memory in use is "
389
+ f"{int(self.available_kv_cache_memory_bytes)} bytes.")
390
+
391
+ logger.info(msg)
392
393
# Warm up sampler and preallocate memory buffer for logits and other
394
# sampling related tensors of max possible shape to avoid memory
vllm/worker/model_runner.py
+4
-2
@@ -1337,8 +1337,9 @@ class GPUModelRunnerBase(ModelRunnerBase[TModelInputForGPU]):
1337
return self.lora_manager.list_adapters()
1338
1339
@torch.inference_mode()
1340
- def capture_model(self, kv_caches: List[List[torch.Tensor]]) -> None:
1341
- """Cuda graph capture a model.
1340
+ def capture_model(self, kv_caches: List[List[torch.Tensor]]) -> int:
1341
+ """Cuda graph capture a model and return cudagraph memory
1342
+ consumption in bytes.
1343
1344
Note that CUDA graph's performance gain is negligible if number
1345
of batched tokens are larger than 200. And since CUDA graph
@@ -1505,6 +1506,7 @@ class GPUModelRunnerBase(ModelRunnerBase[TModelInputForGPU]):
1506
# This usually takes < 10 seconds.
1507
logger.info("Graph capturing finished in %.0f secs, took %.2f GiB",
1508
elapsed_time, cuda_graph_size / GiB_bytes)
1509
+ return cuda_graph_size
1510
1511
def _update_inputs_to_capture_for_enc_dec_model(self,
1512
capture_inputs: Dict[str,
vllm/worker/worker.py
+114
-32
@@ -229,6 +229,67 @@ class Worker(LocalOrDistributedWorkerBase):
229
self.model_runner.save_tensorized_model(
230
tensorizer_config=tensorizer_config, )
231
232
+ @torch.inference_mode()
233
+ def determine_available_kv_cache_memory(self,
234
+ total_gpu_memory: int) -> float:
235
+ if kv_cache_memory_bytes := self.cache_config.kv_cache_memory_bytes:
236
+ # still need a profile run which compiles the model for
237
+ # max_num_batched_tokens
238
+ self.model_runner.profile_run()
239
+
240
+ GiB = lambda b: b / GiB_bytes
241
+ msg = (
242
+ f"Initial free memory "
243
+ f"{GiB(self.baseline_snapshot.free_memory):.2f} "
244
+ f"GiB, reserved {GiB(kv_cache_memory_bytes):.2f}GiB memory for "
245
+ "KV Cache as specified by kv_cache_memory_bytes config and "
246
+ "skipped memory profiling. This does does not respect the "
247
+ "gpu_memory_utilization config. Only use kv_cache_memory_bytes "
248
+ "config when you want manual control of KV cache memory "
249
+ "size. If OOM'ed, check the difference of initial free "
250
+ "memory between the current run and the previous run "
251
+ "where kv_cache_memory_bytes is suggested and update it "
252
+ "correspondingly.")
253
+ logger.info(msg)
254
+ return self.cache_config.kv_cache_memory_bytes
255
+
256
+ # Execute a forward pass with dummy inputs to profile the memory usage
257
+ # of the model.
258
+ with memory_profiling(
259
+ self.baseline_snapshot,
260
+ weights_memory=self.model_runner.model_memory_usage) as result:
261
+ self.model_runner.profile_run()
262
+
263
+ self.non_torch_memory = result.non_torch_increase
264
+ self.peak_activation_memory = result.torch_peak_increase
265
+
266
+ self._assert_memory_footprint_increased_during_profiling()
267
+
268
+ self.requested_memory = total_gpu_memory * \
269
+ self.cache_config.gpu_memory_utilization
270
+
271
+ self.available_kv_cache_memory = (self.requested_memory -
272
+ result.non_kv_cache_memory)
273
+
274
+ msg = (f"Memory profiling takes {result.profile_time:.2f} seconds\n"
275
+ "the current vLLM instance can use "
276
+ "total_gpu_memory "
277
+ f"({(total_gpu_memory / GiB_bytes):.2f}GiB)"
278
+ " x gpu_memory_utilization "
279
+ f"({self.cache_config.gpu_memory_utilization:.2f})"
280
+ f" = {(self.requested_memory / GiB_bytes):.2f}GiB\n"
281
+ "model weights take "
282
+ f"{(result.weights_memory / GiB_bytes):.2f}GiB;"
283
+ " non_torch_memory takes "
284
+ f"{(result.non_torch_increase / GiB_bytes):.2f}GiB;"
285
+ " PyTorch activation peak memory takes "
286
+ f"{(result.torch_peak_increase / GiB_bytes):.2f}GiB;"
287
+ " the rest of the memory reserved for KV Cache is "
288
+ f"{(self.available_kv_cache_memory / GiB_bytes):.2f}GiB.")
289
+
290
+ logger.info(msg)
291
+ return self.available_kv_cache_memory
292
+
293
@torch.inference_mode()
294
def determine_num_available_blocks(self) -> Tuple[int, int]:
295
"""Profiles the peak memory usage of the model to determine how many
@@ -248,20 +309,8 @@ class Worker(LocalOrDistributedWorkerBase):
309
torch.cuda.reset_peak_memory_stats()
310
311
free_memory_pre_profile, total_gpu_memory = torch.cuda.mem_get_info()
251
-
252
- # Execute a forward pass with dummy inputs to profile the memory usage
253
- # of the model.
254
- with memory_profiling(
255
- self.baseline_snapshot,
256
- weights_memory=self.model_runner.model_memory_usage) as result:
257
- self.model_runner.profile_run()
258
-
259
- self._assert_memory_footprint_increased_during_profiling()
260
-
261
- memory_for_current_instance = total_gpu_memory * \
262
- self.cache_config.gpu_memory_utilization
263
- available_kv_cache_memory = (memory_for_current_instance -
264
- result.non_kv_cache_memory)
312
+ available_kv_cache_memory = self.determine_available_kv_cache_memory(
313
+ total_gpu_memory)
314
315
# Calculate the number of blocks that can be allocated with the
316
# profiled peak memory.
@@ -276,23 +325,6 @@ class Worker(LocalOrDistributedWorkerBase):
325
num_gpu_blocks = max(num_gpu_blocks, 0)
326
num_cpu_blocks = max(num_cpu_blocks, 0)
327
279
- msg = (f"Memory profiling takes {result.profile_time:.2f} seconds\n"
280
- "the current vLLM instance can use "
281
- "total_gpu_memory "
282
- f"({(total_gpu_memory / GiB_bytes):.2f}GiB)"
283
- " x gpu_memory_utilization "
284
- f"({self.cache_config.gpu_memory_utilization:.2f})"
285
- f" = {(memory_for_current_instance / GiB_bytes):.2f}GiB\n"
286
- "model weights take "
287
- f"{(result.weights_memory / GiB_bytes):.2f}GiB;"
288
- " non_torch_memory takes "
289
- f"{(result.non_torch_increase / GiB_bytes):.2f}GiB;"
290
- " PyTorch activation peak memory takes "
291
- f"{(result.torch_peak_increase / GiB_bytes):.2f}GiB;"
292
- " the rest of the memory reserved for KV Cache is "
293
- f"{(available_kv_cache_memory / GiB_bytes):.2f}GiB.")
294
-
295
- logger.info(msg)
328
# Final cleanup
329
gc.collect()
330
@@ -382,8 +414,58 @@ class Worker(LocalOrDistributedWorkerBase):
414
for size in sorted(warmup_sizes, reverse=True):
415
logger.info("Compile and warming up model for size %d", size)
416
self.model_runner._dummy_run(size)
417
+
418
+ cuda_graph_memory_bytes = 0
419
if not self.model_config.enforce_eager:
386
- self.model_runner.capture_model(self.gpu_cache)
420
+ cuda_graph_memory_bytes = self.model_runner.capture_model(
421
+ self.gpu_cache)
422
+
423
+ if (self.cache_config.kv_cache_memory_bytes is None
424
+ and hasattr(self, "peak_activation_memory")):
425
+ # Suggests optimal kv cache memory size if we rely on
426
+ # memory_profiling to guess the kv cache memory size which
427
+ # provides peak_activation_memory and a few other memory
428
+ # consumption. `memory_profiling` does not consider
429
+ # CUDAGraph memory size and may not utilize all gpu memory.
430
+ # Users may want fine-grained control to specify kv cache
431
+ # memory size.
432
+ GiB = lambda b: round(b / GiB_bytes, 2)
433
+ non_kv_cache_memory = (self.model_runner.model_memory_usage +
434
+ self.peak_activation_memory +
435
+ self.non_torch_memory +
436
+ cuda_graph_memory_bytes)
437
+
438
+ # empirically observed that the memory profiling may
439
+ # slightly underestimate the memory consumption.
440
+ # So leave a small buffer (=150MiB) to avoid OOM.
441
+ redundancy_buffer_memory = 150 * (1 << 20)
442
+ kv_cache_memory_bytes_to_gpu_limit = (
443
+ self.baseline_snapshot.free_memory - non_kv_cache_memory -
444
+ redundancy_buffer_memory)
445
+ kv_cache_memory_bytes_to_requested_limit = (
446
+ int(self.requested_memory) - non_kv_cache_memory -
447
+ redundancy_buffer_memory)
448
+
449
+ msg = (
450
+ f"Free memory on device "
451
+ f"({GiB(self.baseline_snapshot.free_memory)}/"
452
+ f"{GiB(self.baseline_snapshot.total_memory)} GiB) on startup. "
453
+ f"Desired GPU memory utilization is "
454
+ f"({self.cache_config.gpu_memory_utilization}, "
455
+ f"{GiB(self.requested_memory)} GiB). "
456
+ f"Actual usage is {GiB(self.model_runner.model_memory_usage)} "
457
+ f"GiB for weight, {GiB(self.peak_activation_memory)} GiB "
458
+ f"for peak activation, {GiB(self.non_torch_memory)} GiB "
459
+ f"for non-torch memory, and {GiB(cuda_graph_memory_bytes)} "
460
+ f"GiB for CUDAGraph memory. Replace gpu_memory_utilization "
461
+ f"config with `--kv-cache-memory="
462
+ f"{kv_cache_memory_bytes_to_requested_limit}` to fit into "
463
+ f"requested memory, or `--kv-cache-memory="
464
+ f"{kv_cache_memory_bytes_to_gpu_limit}` to fully "
465
+ f"utilize gpu memory. Current kv cache memory in use is "
466
+ f"{int(self.available_kv_cache_memory)} bytes.")
467
+ logger.info(msg)
468
+
469
# Reset the seed to ensure that the random state is not affected by
470
# the model initialization and profiling.
471
set_random_seed(self.model_config.seed)