cpu.py 3.02 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
from collections.abc import Iterator

import torch

from vllm.config import VllmConfig, get_layers_from_vllm_config
from vllm.model_executor.layers.attention_layer_base import AttentionLayerBase
from vllm.platforms import current_platform
from vllm.v1.kv_offload.abstract import LoadStoreSpec, OffloadingManager
from vllm.v1.kv_offload.backends.cpu import CPUBackend
from vllm.v1.kv_offload.lru_manager import LRUOffloadingManager
from vllm.v1.kv_offload.mediums import CPULoadStoreSpec, GPULoadStoreSpec
from vllm.v1.kv_offload.spec import OffloadingSpec
from vllm.v1.kv_offload.worker.cpu_gpu import CpuGpuOffloadingHandler
from vllm.v1.kv_offload.worker.worker import OffloadingHandler


class CPUOffloadingSpec(OffloadingSpec):
    def __init__(self, vllm_config: VllmConfig):
        super().__init__(vllm_config)

        num_cpu_blocks = self.extra_config.get("num_cpu_blocks")
        if not num_cpu_blocks:
25
26
27
            raise Exception(
                "num_cpu_blocks must be specified in kv_connector_extra_config"
            )
28
29
30
        self.num_cpu_blocks: int = num_cpu_blocks

        # scheduler-side
31
        self._manager: OffloadingManager | None = None
32
33

        # worker-side
34
        self._handler: OffloadingHandler | None = None
35
36
37
38

    def get_manager(self) -> OffloadingManager:
        if not self._manager:
            kv_events_config = self.vllm_config.kv_events_config
39
40
41
42
43
44
45
46
47
            enable_events = (
                kv_events_config is not None and kv_events_config.enable_kv_cache_events
            )
            self._manager = LRUOffloadingManager(
                CPUBackend(
                    block_size=self.offloaded_block_size, num_blocks=self.num_cpu_blocks
                ),
                enable_events=enable_events,
            )
48
49
50
51
        return self._manager

    def get_handlers(
        self, kv_caches: dict[str, torch.Tensor]
52
    ) -> Iterator[tuple[type[LoadStoreSpec], type[LoadStoreSpec], OffloadingHandler]]:
53
54
        if not self._handler:
            if not current_platform.is_cuda():
55
56
57
                raise Exception(
                    "CPU Offloading is currently only supported on CUDA GPUs"
                )
58
59

            layer_names = list(kv_caches.keys())
60
61
62
            layers = get_layers_from_vllm_config(
                self.vllm_config, AttentionLayerBase, layer_names
            )
63
64
65
66
67
68
69
70
71
72
            attn_backends = {
                layer_name: layers[layer_name].get_attn_backend()
                for layer_name in layer_names
            }

            self._handler = CpuGpuOffloadingHandler(
                attn_backends=attn_backends,
                gpu_block_size=self.gpu_block_size,
                cpu_block_size=self.offloaded_block_size,
                num_cpu_blocks=self.num_cpu_blocks,
73
74
                gpu_caches=kv_caches,
            )
75
76
77
78

        assert self._handler is not None
        yield GPULoadStoreSpec, CPULoadStoreSpec, self._handler
        yield CPULoadStoreSpec, GPULoadStoreSpec, self._handler