[Bugfix][KV Offload] Compact canonical MLA rows (#56799)
Signed-off-by: Itay Etelis <92247226+Etelis@users.noreply.github.com> Co-authored-by: Or Ozeri <oro@il.ibm.com>
This commit is contained in:
@@ -17,6 +17,7 @@ from vllm.distributed.kv_transfer.kv_connector.v1.offloading.scheduler import (
|
||||
SchedulerOffloadConfig,
|
||||
)
|
||||
from vllm.platforms import current_platform
|
||||
from vllm.v1.core.kv_cache_utils import generate_scheduler_kv_cache_config
|
||||
from vllm.v1.kv_cache_interface import (
|
||||
FullAttentionSpec,
|
||||
HiddenStateCacheSpec,
|
||||
@@ -32,6 +33,8 @@ from vllm.v1.kv_cache_interface import (
|
||||
UniformTypeKVCacheSpecs,
|
||||
)
|
||||
from vllm.v1.kv_cache_spec_registry import KVCacheSpecRegistry
|
||||
from vllm.v1.kv_offload.file_mapper import FileMapper
|
||||
from vllm.v1.kv_offload.tiering.spec import TieringOffloadingSpec
|
||||
|
||||
|
||||
def _make_vllm_config(
|
||||
@@ -876,6 +879,43 @@ def test_canonical_layout_certifies_v2_model_runner():
|
||||
assert _parallelism_agnostic(groups, canonical=True, v2=True)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tp_size", [1, 2, 4])
|
||||
@pytest.mark.parametrize("scheduler", [False, True])
|
||||
def test_canonical_mla_dsa_rows_are_tp_independent(tp_size, scheduler):
|
||||
specs = {
|
||||
f"l{i}": _mla_spec(block_size=64, head_size=size, dtype=torch.uint8)
|
||||
for i, size in enumerate([656] * 4 + [132] * 3)
|
||||
}
|
||||
uniform = UniformTypeKVCacheSpecs(block_size=64, kv_cache_specs=specs)
|
||||
kv_cache_config = KVCacheConfig(
|
||||
num_blocks=4,
|
||||
kv_cache_tensors=[
|
||||
KVCacheTensor(
|
||||
size=4 * uniform.page_size_bytes,
|
||||
layers=list(specs),
|
||||
layer_stride=0,
|
||||
block_stride=uniform.page_size_bytes,
|
||||
)
|
||||
],
|
||||
kv_cache_groups=[KVCacheGroupSpec(list(specs), uniform)],
|
||||
)
|
||||
if scheduler:
|
||||
kv_cache_config = generate_scheduler_kv_cache_config([kv_cache_config])
|
||||
config = _make_vllm_config(
|
||||
tensor_parallel_size=tp_size,
|
||||
extra_config={"canonical_layout": True, "cpu_bytes_to_use": 196608 * 8},
|
||||
)
|
||||
config.cache_config.kv_cache_layout = "LBHNC"
|
||||
config.parallel_config.distributed_executor_backend = "mp"
|
||||
offloading_config = build_offloading_config(config, kv_cache_config)
|
||||
spec = TieringOffloadingSpec(offloading_config)
|
||||
assert spec.kv_bytes_per_chunk == 196608
|
||||
assert spec.num_chunks == 8
|
||||
mapper = FileMapper.from_offloading_spec("/cache", spec, parallel_agnostic=True)
|
||||
assert mapper.get_run_config()["tp_size"] == 1
|
||||
assert mapper.get_run_config()["replicated_layout"] is True
|
||||
|
||||
|
||||
def test_parallelism_agnostic_disabled_on_v2_model_runner():
|
||||
config = _make_vllm_config()
|
||||
config.use_v2_model_runner = True
|
||||
|
||||
@@ -97,6 +97,7 @@ def _make_worker(
|
||||
kv_cache_config: KVCacheConfig,
|
||||
replicated_layout: bool = False,
|
||||
rank: int = 0,
|
||||
canonical_layout: bool = False,
|
||||
):
|
||||
"""Create an OffloadingConnectorWorker with mocked dependencies."""
|
||||
from vllm.distributed.kv_transfer.kv_connector.v1.offloading.worker import (
|
||||
@@ -106,6 +107,7 @@ def _make_worker(
|
||||
spec = MagicMock(spec=OffloadingSpec)
|
||||
spec.replicated_layout = replicated_layout
|
||||
spec.config = MagicMock()
|
||||
spec.config.canonical_layout = canonical_layout
|
||||
spec.config.parallel.rank = rank
|
||||
spec.get_worker.return_value = MagicMock()
|
||||
|
||||
@@ -204,11 +206,13 @@ def test_prepare_store_kv_non_writer_marks_completed_without_submit():
|
||||
assert meta.completed_jobs == {7: 1}
|
||||
|
||||
|
||||
def test_prepare_store_kv_writer_submits_store():
|
||||
@pytest.mark.parametrize("rank,canonical_layout", [(0, False), (0, True), (1, True)])
|
||||
def test_prepare_store_kv_writer_submits_store(rank, canonical_layout):
|
||||
worker, _ = _make_worker(
|
||||
KVCacheConfig(num_blocks=0, kv_cache_tensors=[], kv_cache_groups=[]),
|
||||
replicated_layout=True,
|
||||
rank=0,
|
||||
rank=rank,
|
||||
canonical_layout=canonical_layout,
|
||||
)
|
||||
|
||||
worker.prepare_store_kv(_store_metadata(8))
|
||||
|
||||
@@ -233,6 +233,20 @@ def build_offloading_config(
|
||||
and parallel_config.world_size == tp_size
|
||||
)
|
||||
|
||||
if canonical_layout and is_parallelism_agnostic:
|
||||
replicated_layout = (
|
||||
all(
|
||||
type(spec) is MLAAttentionSpec
|
||||
for _, group in selected_groups
|
||||
for spec in iter_layer_specs(group.kv_cache_spec)
|
||||
)
|
||||
and parallel_config.nnodes_within_dp == 1
|
||||
and (
|
||||
parallel_config.world_size == 1
|
||||
or parallel_config.distributed_executor_backend == "mp"
|
||||
)
|
||||
)
|
||||
|
||||
kv_events_config = vllm_config.kv_events_config
|
||||
cache_dtype = (
|
||||
vllm_config.model_config.dtype
|
||||
|
||||
@@ -53,7 +53,9 @@ class OffloadingConnectorWorker:
|
||||
self.worker: OffloadingWorker | None = None
|
||||
# Non-writers still ack: pending_count waits for world_size per job.
|
||||
self._is_store_writer = (
|
||||
not self.spec.replicated_layout or self.spec.config.parallel.rank == 0
|
||||
not self.spec.replicated_layout
|
||||
or self.spec.config.canonical_layout
|
||||
or self.spec.config.parallel.rank == 0
|
||||
)
|
||||
|
||||
# job_id -> req_id for in-flight loads.
|
||||
|
||||
Reference in New Issue
Block a user