main
py 609 lines 20.8 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """Unit tests for native offloading specs and their factory."""
4
5 from typing import Any
6 from unittest.mock import MagicMock
7
8 import pytest
9
10 from vllm.v1.kv_offload.base import (
11 CanonicalKVCaches,
12 OffloadingHistogramMetadata,
13 OffloadingManager,
14 OffloadingSpec,
15 OffloadingWorker,
16 )
17 from vllm.v1.kv_offload.config import (
18 OffloadingCacheConfig,
19 OffloadingConfig,
20 OffloadingGroupConfig,
21 OffloadingModelConfig,
22 OffloadingParallelConfig,
23 )
24 from vllm.v1.kv_offload.cpu.shared_offload_region import SharedOffloadRegion
25 from vllm.v1.kv_offload.cpu.spec import CPUOffloadingSpec
26 from vllm.v1.kv_offload.factory import OffloadingSpecFactory
27 from vllm.v1.kv_offload.tiering.spec import TieringOffloadingSpec
28
29
30 @pytest.fixture(autouse=True)
31 def restore_registry():
32 original = dict(OffloadingSpecFactory._registry)
33 yield
34 OffloadingSpecFactory._registry = original
35
36
37 def _make_offloading_config(
38 *,
39 spec_name: str | None = "CPUOffloadingSpec",
40 cpu_bytes_to_use: int | None = 65536,
41 worker_kv_bytes_per_block: int = 8,
42 groups: tuple[OffloadingGroupConfig, ...] | None = None,
43 tokens_per_hash: int = 16,
44 blocks_per_chunk: int = 1,
45 rank: int = 0,
46 world_size: int = 1,
47 tp_size: int | None = None,
48 pp_size: int = 1,
49 pcp_size: int = 1,
50 dcp_size: int = 1,
51 data_parallel_index: int = 0,
52 data_parallel_size: int = 1,
53 data_parallel_rank_local: int | None = None,
54 is_parallelism_agnostic: bool = False,
55 replicated_layout: bool = False,
56 extra_config: dict[str, Any] | None = None,
57 ) -> OffloadingConfig:
58 normalized_extra_config = dict(extra_config or {})
59 if spec_name is not None:
60 normalized_extra_config["spec_name"] = spec_name
61 if cpu_bytes_to_use is not None:
62 normalized_extra_config["cpu_bytes_to_use"] = cpu_bytes_to_use
63
64 if groups is None:
65 groups = (OffloadingGroupConfig(16, ("layer",), 0),)
66
67 return OffloadingConfig(
68 groups=groups,
69 worker_kv_bytes_per_block=worker_kv_bytes_per_block,
70 enable_kv_cache_events=False,
71 extra_config=normalized_extra_config,
72 engine_id="test-engine",
73 model=OffloadingModelConfig(name="test-model", dtype="float16"),
74 cache=OffloadingCacheConfig(
75 tokens_per_hash=tokens_per_hash,
76 blocks_per_chunk=blocks_per_chunk,
77 ),
78 parallel=OffloadingParallelConfig(
79 rank=rank,
80 world_size=world_size,
81 tp_size=world_size if tp_size is None else tp_size,
82 pp_size=pp_size,
83 pcp_size=pcp_size,
84 dcp_size=dcp_size,
85 data_parallel_index=data_parallel_index,
86 data_parallel_size=data_parallel_size,
87 data_parallel_rank_local=data_parallel_rank_local,
88 is_parallelism_agnostic=is_parallelism_agnostic,
89 ),
90 replicated_layout=replicated_layout,
91 )
92
93
94 def _create_spec(**kwargs: Any) -> OffloadingSpec:
95 return OffloadingSpecFactory.create_spec(_make_offloading_config(**kwargs))
96
97
98 class SingleArgExternalOffloadingSpec(OffloadingSpec):
99 def get_manager(self) -> OffloadingManager:
100 raise NotImplementedError
101
102 def get_worker(self, kv_caches: CanonicalKVCaches) -> OffloadingWorker:
103 raise NotImplementedError
104
105
106 def test_pre_registered_specs_can_be_imported():
107 for name in OffloadingSpecFactory._registry:
108 cls = OffloadingSpecFactory._registry[name]()
109 assert issubclass(cls, OffloadingSpec)
110
111
112 def test_cpu_spec_registered():
113 cls = OffloadingSpecFactory._registry["CPUOffloadingSpec"]()
114 assert cls is CPUOffloadingSpec
115
116
117 def test_tiering_spec_registered():
118 cls = OffloadingSpecFactory._registry["TieringOffloadingSpec"]()
119 assert cls is TieringOffloadingSpec
120
121
122 def test_get_spec_cls_returns_registered_class():
123 spec_cls = OffloadingSpecFactory.get_spec_cls(
124 _make_offloading_config().extra_config
125 )
126 assert spec_cls is CPUOffloadingSpec
127
128
129 def test_get_spec_cls_defaults_to_cpu():
130 spec_cls = OffloadingSpecFactory.get_spec_cls(
131 _make_offloading_config(spec_name=None).extra_config
132 )
133 assert spec_cls is CPUOffloadingSpec
134
135
136 def test_create_cpu_offloading_spec():
137 spec = _create_spec()
138 assert isinstance(spec, CPUOffloadingSpec)
139 assert spec.num_chunks > 0
140
141
142 def test_cpu_spec_sizes_normalized_worker_layout():
143 # The CPU spec now rounds the offloaded row up to the mmap page size
144 # (matching the shared region), so kv_bytes_per_chunk picks up padding
145 # while cpu_page_size_per_worker stays the un-padded per-worker slot.
146 alignment = SharedOffloadRegion.BLOCK_SIZE_ALIGNMENT
147 spec = _create_spec(
148 cpu_bytes_to_use=alignment * 3,
149 worker_kv_bytes_per_block=16,
150 blocks_per_chunk=2,
151 world_size=6,
152 tp_size=3,
153 pp_size=2,
154 )
155
156 assert isinstance(spec, CPUOffloadingSpec)
157 assert spec.cpu_page_size_per_worker == 32
158 assert spec.kv_bytes_per_chunk == alignment
159 assert spec.num_chunks == 3
160
161
162 def test_cpu_spec_zero_worker_bytes_produces_empty_cache():
163 spec = _create_spec(worker_kv_bytes_per_block=0, world_size=4)
164
165 assert isinstance(spec, CPUOffloadingSpec)
166 assert spec.cpu_page_size_per_worker == 0
167 assert spec.kv_bytes_per_chunk == 0
168 assert spec.num_chunks == 0
169
170
171 def test_tiering_spec_aligns_row_size():
172 alignment = SharedOffloadRegion.BLOCK_SIZE_ALIGNMENT
173 spec = _create_spec(
174 spec_name="TieringOffloadingSpec",
175 cpu_bytes_to_use=alignment * 3,
176 worker_kv_bytes_per_block=16,
177 blocks_per_chunk=2,
178 world_size=6,
179 tp_size=3,
180 pp_size=2,
181 )
182
183 assert isinstance(spec, TieringOffloadingSpec)
184 assert spec.cpu_page_size_per_worker == 32
185 assert spec.kv_bytes_per_chunk == alignment
186 assert spec.num_chunks == 3
187
188
189 @pytest.mark.parametrize("world_size", [2, 4, 8])
190 def test_tiering_spec_replicated_sizing_removes_world_factor(world_size: int):
191 worker_kv_bytes_per_block = SharedOffloadRegion.BLOCK_SIZE_ALIGNMENT
192 spec = _create_spec(
193 spec_name="TieringOffloadingSpec",
194 cpu_bytes_to_use=worker_kv_bytes_per_block * 8,
195 worker_kv_bytes_per_block=worker_kv_bytes_per_block,
196 world_size=world_size,
197 replicated_layout=True,
198 )
199
200 assert isinstance(spec, TieringOffloadingSpec)
201 assert spec.replicated_layout is True
202 assert spec.cpu_page_size_per_worker == worker_kv_bytes_per_block
203 assert spec.kv_bytes_per_chunk == worker_kv_bytes_per_block
204 assert spec.num_chunks == 8
205
206
207 def test_tiering_spec_create_worker_uses_single_slot_for_replicated_layout(monkeypatch):
208 import vllm.v1.kv_offload.tiering.spec as tiering_spec_module
209
210 worker_kv_bytes_per_block = SharedOffloadRegion.BLOCK_SIZE_ALIGNMENT
211 spec = _create_spec(
212 spec_name="TieringOffloadingSpec",
213 cpu_bytes_to_use=worker_kv_bytes_per_block * 8,
214 worker_kv_bytes_per_block=worker_kv_bytes_per_block,
215 world_size=4,
216 replicated_layout=True,
217 )
218 assert isinstance(spec, TieringOffloadingSpec)
219
220 region = MagicMock()
221 region_calls: list[dict[str, Any]] = []
222 worker_calls: list[dict[str, Any]] = []
223
224 def fake_region_ctor(**kwargs):
225 region_calls.append(kwargs)
226 return region
227
228 def fake_worker_ctor(**kwargs):
229 worker_calls.append(kwargs)
230 return MagicMock()
231
232 monkeypatch.setattr(tiering_spec_module, "SharedOffloadRegion", fake_region_ctor)
233 monkeypatch.setattr(tiering_spec_module, "CPUOffloadingWorker", fake_worker_ctor)
234 monkeypatch.setattr(
235 tiering_spec_module.torch.accelerator, "current_device_index", lambda: 5
236 )
237
238 kv_caches = MagicMock()
239 spec.create_worker(kv_caches)
240
241 assert region_calls[0]["rank"] == 0
242 assert region_calls[0]["kv_bytes_per_chunk"] == worker_kv_bytes_per_block
243 assert worker_calls[0]["kv_caches"] is kv_caches
244 assert worker_calls[0]["mmap_region"] is region
245
246
247 def test_tiering_spec_create_worker_folds_device_index_for_sharded_layout(monkeypatch):
248 import vllm.v1.kv_offload.tiering.spec as tiering_spec_module
249
250 spec = _create_spec(
251 spec_name="TieringOffloadingSpec",
252 worker_kv_bytes_per_block=4096,
253 world_size=4,
254 )
255 assert isinstance(spec, TieringOffloadingSpec)
256
257 region_calls: list[dict[str, Any]] = []
258
259 def fake_region_ctor(**kwargs):
260 region_calls.append(kwargs)
261 return MagicMock()
262
263 monkeypatch.setattr(tiering_spec_module, "SharedOffloadRegion", fake_region_ctor)
264 monkeypatch.setattr(tiering_spec_module, "CPUOffloadingWorker", MagicMock())
265 monkeypatch.setattr(
266 tiering_spec_module.torch.accelerator,
267 "current_device_index",
268 lambda: 5,
269 )
270
271 spec.create_worker(MagicMock())
272
273 assert region_calls[0]["rank"] == 1
274
275
276 @pytest.mark.parametrize("world_size", [2, 4, 8])
277 def test_cpu_spec_replicated_sizing_on_shared_region(monkeypatch, world_size: int):
278 # On CUDA the default spec honors
279 # replicated layout: a single MLA copy (num_copies=1), matching tiering.
280 import vllm.v1.kv_offload.cpu.spec as cpu_spec_module
281
282 monkeypatch.setattr(cpu_spec_module.current_platform, "is_cuda_alike", lambda: True)
283 monkeypatch.setattr(cpu_spec_module.current_platform, "is_rocm", lambda: False)
284 worker_kv_bytes_per_block = SharedOffloadRegion.BLOCK_SIZE_ALIGNMENT
285 spec = _create_spec(
286 cpu_bytes_to_use=worker_kv_bytes_per_block * 8,
287 worker_kv_bytes_per_block=worker_kv_bytes_per_block,
288 world_size=world_size,
289 replicated_layout=True,
290 )
291
292 assert isinstance(spec, CPUOffloadingSpec)
293 assert spec.replicated_layout is True
294 assert spec.cpu_page_size_per_worker == worker_kv_bytes_per_block
295 assert spec.kv_bytes_per_chunk == worker_kv_bytes_per_block
296 assert spec.num_chunks == 8
297
298
299 @pytest.mark.parametrize("rocm", [False, True], ids=["non-cuda-alike", "rocm"])
300 @pytest.mark.parametrize("world_size", [2, 4, 8])
301 def test_cpu_spec_replicated_disabled_without_shared_region(
302 monkeypatch, world_size: int, rocm: bool
303 ):
304 # Data-loss guard: platforms without shared regions keep a private pinned
305 # tensor (no shared medium), so replicated layout MUST stay off. Otherwise
306 # the rank-0 writer gate would ack rank>0 stores without writing, leaving
307 # those private buffers empty and corrupting subsequent loads.
308 import vllm.v1.kv_offload.cpu.spec as cpu_spec_module
309
310 monkeypatch.setattr(cpu_spec_module.current_platform, "is_cuda_alike", lambda: rocm)
311 monkeypatch.setattr(cpu_spec_module.current_platform, "is_rocm", lambda: rocm)
312 worker_kv_bytes_per_block = SharedOffloadRegion.BLOCK_SIZE_ALIGNMENT
313 spec = _create_spec(
314 cpu_bytes_to_use=worker_kv_bytes_per_block * world_size * 2,
315 worker_kv_bytes_per_block=worker_kv_bytes_per_block,
316 world_size=world_size,
317 replicated_layout=True,
318 )
319
320 assert isinstance(spec, CPUOffloadingSpec)
321 assert spec.replicated_layout is False
322 assert spec.cpu_page_size_per_worker == worker_kv_bytes_per_block
323 assert spec.kv_bytes_per_chunk == worker_kv_bytes_per_block * world_size
324 assert spec.num_chunks == 2
325
326
327 @pytest.mark.parametrize("config_replicated", [True, False])
328 @pytest.mark.parametrize(
329 ("cuda_alike", "rocm", "shared_region"),
330 [(True, False, True), (True, True, False), (False, False, False)],
331 ids=["cuda", "rocm", "non-cuda-alike"],
332 )
333 def test_cpu_spec_replicated_layout_truth_matrix(
334 monkeypatch,
335 cuda_alike: bool,
336 rocm: bool,
337 shared_region: bool,
338 config_replicated: bool,
339 ):
340 # replicated_layout is enabled iff the config gate passes AND the deployment
341 # actually allocates on the shared region.
342 import vllm.v1.kv_offload.cpu.spec as cpu_spec_module
343
344 monkeypatch.setattr(
345 cpu_spec_module.current_platform, "is_cuda_alike", lambda: cuda_alike
346 )
347 monkeypatch.setattr(cpu_spec_module.current_platform, "is_rocm", lambda: rocm)
348 worker_kv_bytes_per_block = SharedOffloadRegion.BLOCK_SIZE_ALIGNMENT
349 spec = _create_spec(
350 cpu_bytes_to_use=worker_kv_bytes_per_block * 8,
351 worker_kv_bytes_per_block=worker_kv_bytes_per_block,
352 world_size=4,
353 replicated_layout=config_replicated,
354 )
355
356 assert isinstance(spec, CPUOffloadingSpec)
357 assert spec.replicated_layout is (shared_region and config_replicated)
358
359
360 def test_cpu_spec_create_worker_uses_mmap_on_cuda(monkeypatch):
361 import vllm.v1.kv_offload.cpu.spec as cpu_spec_module
362
363 worker_kv_bytes_per_block = SharedOffloadRegion.BLOCK_SIZE_ALIGNMENT
364 spec = _create_spec(
365 cpu_bytes_to_use=worker_kv_bytes_per_block * 8,
366 worker_kv_bytes_per_block=worker_kv_bytes_per_block,
367 world_size=4,
368 )
369 assert isinstance(spec, CPUOffloadingSpec)
370
371 region = MagicMock()
372 region_calls: list[dict[str, Any]] = []
373 worker_calls: list[dict[str, Any]] = []
374
375 def fake_region_ctor(**kwargs):
376 region_calls.append(kwargs)
377 return region
378
379 def fake_worker_ctor(**kwargs):
380 worker_calls.append(kwargs)
381 return MagicMock()
382
383 monkeypatch.setattr(cpu_spec_module.current_platform, "is_cuda_alike", lambda: True)
384 monkeypatch.setattr(cpu_spec_module.current_platform, "is_rocm", lambda: False)
385 monkeypatch.setattr(cpu_spec_module, "SharedOffloadRegion", fake_region_ctor)
386 monkeypatch.setattr(cpu_spec_module, "CPUOffloadingWorker", fake_worker_ctor)
387 monkeypatch.setattr(
388 cpu_spec_module.torch.accelerator, "current_device_index", lambda: 5
389 )
390
391 kv_caches = MagicMock()
392 spec.create_worker(kv_caches)
393
394 assert region_calls[0]["engine_id"] == "test-engine"
395 assert region_calls[0]["kv_bytes_per_chunk"] == worker_kv_bytes_per_block * 4
396 assert worker_calls[0]["kv_caches"] is kv_caches
397 assert worker_calls[0]["mmap_region"] is region
398
399
400 @pytest.mark.parametrize("rocm", [False, True], ids=["non-cuda-alike", "rocm"])
401 def test_cpu_spec_create_worker_uses_tensor_path_without_shared_region(
402 monkeypatch, rocm
403 ):
404 import vllm.v1.kv_offload.cpu.spec as cpu_spec_module
405
406 spec = _create_spec(worker_kv_bytes_per_block=4096, world_size=4)
407 assert isinstance(spec, CPUOffloadingSpec)
408
409 region_calls: list[dict[str, Any]] = []
410 worker_calls: list[dict[str, Any]] = []
411
412 def fake_region_ctor(**kwargs):
413 region_calls.append(kwargs)
414 return MagicMock()
415
416 def fake_worker_ctor(**kwargs):
417 worker_calls.append(kwargs)
418 return MagicMock()
419
420 monkeypatch.setattr(cpu_spec_module.current_platform, "is_cuda_alike", lambda: rocm)
421 monkeypatch.setattr(cpu_spec_module.current_platform, "is_rocm", lambda: rocm)
422 monkeypatch.setattr(cpu_spec_module, "SharedOffloadRegion", fake_region_ctor)
423 monkeypatch.setattr(cpu_spec_module, "CPUOffloadingWorker", fake_worker_ctor)
424
425 spec.create_worker(MagicMock())
426
427 # ROCm and non-CUDA-alike platforms use the per-rank pinned-tensor path.
428 assert region_calls == []
429 assert worker_calls[0]["mmap_region"] is None
430
431
432 def test_cpu_spec_create_worker_skips_mmap_for_empty_cache(monkeypatch):
433 import vllm.v1.kv_offload.cpu.spec as cpu_spec_module
434
435 # worker_kv_bytes_per_block=0 yields num_chunks=0; a zero-byte region cannot
436 # be mmap'd, so even on CUDA this must fall back to the tensor path.
437 spec = _create_spec(worker_kv_bytes_per_block=0, world_size=4)
438 assert isinstance(spec, CPUOffloadingSpec)
439 assert spec.num_chunks == 0
440
441 region_calls: list[dict[str, Any]] = []
442 worker_calls: list[dict[str, Any]] = []
443
444 monkeypatch.setattr(cpu_spec_module.current_platform, "is_cuda_alike", lambda: True)
445 monkeypatch.setattr(cpu_spec_module.current_platform, "is_rocm", lambda: False)
446 monkeypatch.setattr(
447 cpu_spec_module,
448 "SharedOffloadRegion",
449 lambda **kwargs: region_calls.append(kwargs),
450 )
451 monkeypatch.setattr(
452 cpu_spec_module,
453 "CPUOffloadingWorker",
454 lambda **kwargs: worker_calls.append(kwargs),
455 )
456
457 spec.create_worker(MagicMock())
458
459 assert region_calls == []
460 assert worker_calls[0]["mmap_region"] is None
461
462
463 @pytest.mark.parametrize(
464 ("replicated_layout", "device_index", "world_size", "expected_rank"),
465 [
466 (True, 5, 4, 0), # replicated: always slot 0
467 (True, 0, 4, 0), # replicated: slot 0 regardless of device
468 (False, 5, 4, 1), # non-replicated: 5 % 4 == 1
469 (False, 7, 4, 3), # non-replicated: 7 % 4 == 3
470 ],
471 )
472 def test_cpu_spec_create_worker_rank_assignment(
473 monkeypatch, replicated_layout, device_index, world_size, expected_rank
474 ):
475 import vllm.v1.kv_offload.cpu.spec as cpu_spec_module
476
477 monkeypatch.setattr(cpu_spec_module.current_platform, "is_cuda_alike", lambda: True)
478 monkeypatch.setattr(cpu_spec_module.current_platform, "is_rocm", lambda: False)
479 worker_kv_bytes_per_block = SharedOffloadRegion.BLOCK_SIZE_ALIGNMENT
480 spec = _create_spec(
481 cpu_bytes_to_use=worker_kv_bytes_per_block * 8,
482 worker_kv_bytes_per_block=worker_kv_bytes_per_block,
483 world_size=world_size,
484 replicated_layout=replicated_layout,
485 )
486
487 region_calls: list[dict[str, Any]] = []
488
489 def fake_region_ctor(**kwargs):
490 region_calls.append(kwargs)
491 return MagicMock()
492
493 monkeypatch.setattr(cpu_spec_module, "SharedOffloadRegion", fake_region_ctor)
494 monkeypatch.setattr(cpu_spec_module, "CPUOffloadingWorker", MagicMock())
495 monkeypatch.setattr(
496 cpu_spec_module.torch.accelerator, "current_device_index", lambda: device_index
497 )
498
499 spec.create_worker(MagicMock())
500
501 assert region_calls[0]["rank"] == expected_rank
502
503
504 def test_offloading_spec_has_replicated_layout_default():
505 spec = SingleArgExternalOffloadingSpec(_make_offloading_config())
506 assert spec.replicated_layout is False
507
508
509 def test_offloading_spec_uses_normalized_chunk_geometry():
510 groups = (
511 OffloadingGroupConfig(12, ("full_layer",), 0),
512 OffloadingGroupConfig(16, ("mla_layer",), 1),
513 )
514 spec = _create_spec(
515 groups=groups,
516 tokens_per_hash=4,
517 blocks_per_chunk=2,
518 )
519
520 assert spec.tokens_per_block == (12, 16)
521 assert spec.tokens_per_hash == 4
522 assert spec.blocks_per_chunk == 2
523
524
525 def test_create_dynamic_spec_receives_config():
526 config = _make_offloading_config(
527 spec_name="SingleArgExternalOffloadingSpec",
528 extra_config={"spec_module_path": "tests.v1.kv_offload.test_factory"},
529 )
530
531 spec = OffloadingSpecFactory.create_spec(config)
532
533 assert isinstance(spec, SingleArgExternalOffloadingSpec)
534 assert spec.config is config
535
536
537 def test_dynamic_load_via_spec_module_path():
538 del OffloadingSpecFactory._registry["CPUOffloadingSpec"]
539 config = _make_offloading_config(
540 extra_config={"spec_module_path": "vllm.v1.kv_offload.cpu.spec"}
541 )
542
543 spec_cls = OffloadingSpecFactory.get_spec_cls(config.extra_config)
544
545 assert spec_cls is CPUOffloadingSpec
546
547
548 def test_unregistered_spec_without_module_path_raises():
549 config = _make_offloading_config(spec_name="NonexistentSpec")
550 with pytest.raises(ValueError, match="Unsupported spec type"):
551 OffloadingSpecFactory.get_spec_cls(config.extra_config)
552
553 with pytest.raises(ValueError, match="Unsupported spec type"):
554 OffloadingSpecFactory.create_spec(config)
555
556
557 def test_cpu_spec_missing_cpu_bytes_to_use_raises():
558 with pytest.raises(Exception, match="cpu_bytes_to_use must be specified"):
559 _create_spec(cpu_bytes_to_use=None)
560
561
562 def test_duplicate_registration_raises():
563 with pytest.raises(ValueError, match="is already registered"):
564 OffloadingSpecFactory.register_spec(
565 "CPUOffloadingSpec", "some.module", "SomeClass"
566 )
567
568
569 def test_build_metric_definitions_below_threshold():
570 from vllm.v1.kv_offload.cpu.common import CPUOffloadingMetrics
571
572 extra_config = {"store_threshold": 1}
573 spec_cls = OffloadingSpecFactory.get_spec_cls({"spec_name": "CPUOffloadingSpec"})
574 metrics = spec_cls.build_metric_definitions(extra_config)
575
576 assert CPUOffloadingMetrics.STORES_SKIPPED not in metrics
577 assert CPUOffloadingMetrics.CPU_ALLOCATION_SIZE in metrics
578
579
580 def test_build_metric_definitions_allocation_size_histogram():
581 from vllm.v1.kv_offload.cpu.common import CPUOffloadingMetrics
582
583 spec_cls = OffloadingSpecFactory.get_spec_cls({"spec_name": "CPUOffloadingSpec"})
584 metrics = spec_cls.build_metric_definitions({})
585 metadata = metrics[CPUOffloadingMetrics.CPU_ALLOCATION_SIZE]
586
587 assert isinstance(metadata, OffloadingHistogramMetadata)
588 assert metadata.buckets == (
589 1,
590 4,
591 16,
592 64,
593 256,
594 1024,
595 4096,
596 16384,
597 65536,
598 262144,
599 )
600
601
602 def test_build_metric_definitions_returns_counter_at_threshold():
603 from vllm.v1.kv_offload.cpu.common import CPUOffloadingMetrics
604
605 extra_config = {"store_threshold": 2}
606 spec_cls = OffloadingSpecFactory.get_spec_cls({"spec_name": "CPUOffloadingSpec"})
607 metrics = spec_cls.build_metric_definitions(extra_config)
608
609 assert CPUOffloadingMetrics.STORES_SKIPPED in metrics