Skip to content

vllm.v1.kv_offload.cpu

CPUOffloadingSpec

Bases: OffloadingSpec

Source code in vllm/v1/kv_offload/cpu.py
class CPUOffloadingSpec(OffloadingSpec):
    def __init__(self, vllm_config: VllmConfig, kv_cache_config: KVCacheConfig):
        super().__init__(vllm_config, kv_cache_config)

        cpu_bytes_to_use = self.extra_config.get("cpu_bytes_to_use")
        if not cpu_bytes_to_use:
            raise Exception(
                "cpu_bytes_to_use must be specified in kv_connector_extra_config"
            )

        # calculate kv_bytes_per_offloaded_block
        assert kv_cache_config is not None
        page_sizes = {
            kv_cache_group.kv_cache_spec.page_size_bytes
            for kv_cache_group in kv_cache_config.kv_cache_groups
        }
        assert len(page_sizes) == 1
        page_size_bytes = page_sizes.pop()
        kv_bytes_per_block = (
            page_size_bytes
            * len(kv_cache_config.kv_cache_tensors)
            * vllm_config.parallel_config.world_size
        )
        kv_bytes_per_offloaded_block = kv_bytes_per_block * (
            self.offloaded_block_size // self.gpu_block_size
        )

        self.num_blocks = (
            int(cpu_bytes_to_use) // kv_bytes_per_offloaded_block
            if kv_bytes_per_offloaded_block > 0
            else 0
        )

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

        # worker-side
        self._handlers: CpuGpuOffloadingHandlers | None = None

        self.eviction_policy: str = self.extra_config.get("eviction_policy", "lru")

    def get_manager(self) -> OffloadingManager:
        if not self._manager:
            kv_events_config = self.vllm_config.kv_events_config
            enable_events = (
                kv_events_config is not None and kv_events_config.enable_kv_cache_events
            )

            backend = CPUBackend(
                block_size=self.offloaded_block_size, num_blocks=self.num_blocks
            )

            if self.eviction_policy == "lru":
                self._manager = LRUOffloadingManager(
                    backend=backend, enable_events=enable_events
                )
            elif self.eviction_policy == "arc":
                self._manager = ARCOffloadingManager(
                    backend=backend, enable_events=enable_events
                )
            else:
                raise ValueError(
                    f"Unknown eviction policy: {self.eviction_policy}. "
                    f"Supported policies: lru, arc"
                )
        return self._manager

    def get_handlers(
        self,
        kv_caches: dict[str, torch.Tensor],
        attn_backends: dict[str, type[AttentionBackend]],
    ) -> Iterator[tuple[type[LoadStoreSpec], type[LoadStoreSpec], OffloadingHandler]]:
        if not self._handlers:
            if not current_platform.is_cuda_alike():
                raise Exception(
                    "CPU Offloading is currently only supported on CUDA-alike GPUs"
                )

            self._handlers = CpuGpuOffloadingHandlers(
                attn_backends=attn_backends,
                gpu_block_size=self.gpu_block_size,
                cpu_block_size=self.offloaded_block_size,
                num_cpu_blocks=self.num_blocks,
                gpu_caches=kv_caches,
            )

        assert self._handlers is not None
        yield GPULoadStoreSpec, CPULoadStoreSpec, self._handlers.gpu_to_cpu_handler
        yield CPULoadStoreSpec, GPULoadStoreSpec, self._handlers.cpu_to_gpu_handler

_handlers instance-attribute

_handlers: CpuGpuOffloadingHandlers | None = None

_manager instance-attribute

_manager: OffloadingManager | None = None

eviction_policy instance-attribute

eviction_policy: str = get('eviction_policy', 'lru')

num_blocks instance-attribute

num_blocks = (
    int(cpu_bytes_to_use) // kv_bytes_per_offloaded_block
    if kv_bytes_per_offloaded_block > 0
    else 0
)

__init__

__init__(
    vllm_config: VllmConfig, kv_cache_config: KVCacheConfig
)
Source code in vllm/v1/kv_offload/cpu.py
def __init__(self, vllm_config: VllmConfig, kv_cache_config: KVCacheConfig):
    super().__init__(vllm_config, kv_cache_config)

    cpu_bytes_to_use = self.extra_config.get("cpu_bytes_to_use")
    if not cpu_bytes_to_use:
        raise Exception(
            "cpu_bytes_to_use must be specified in kv_connector_extra_config"
        )

    # calculate kv_bytes_per_offloaded_block
    assert kv_cache_config is not None
    page_sizes = {
        kv_cache_group.kv_cache_spec.page_size_bytes
        for kv_cache_group in kv_cache_config.kv_cache_groups
    }
    assert len(page_sizes) == 1
    page_size_bytes = page_sizes.pop()
    kv_bytes_per_block = (
        page_size_bytes
        * len(kv_cache_config.kv_cache_tensors)
        * vllm_config.parallel_config.world_size
    )
    kv_bytes_per_offloaded_block = kv_bytes_per_block * (
        self.offloaded_block_size // self.gpu_block_size
    )

    self.num_blocks = (
        int(cpu_bytes_to_use) // kv_bytes_per_offloaded_block
        if kv_bytes_per_offloaded_block > 0
        else 0
    )

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

    # worker-side
    self._handlers: CpuGpuOffloadingHandlers | None = None

    self.eviction_policy: str = self.extra_config.get("eviction_policy", "lru")

get_handlers

get_handlers(
    kv_caches: dict[str, Tensor],
    attn_backends: dict[str, type[AttentionBackend]],
) -> Iterator[
    tuple[
        type[LoadStoreSpec],
        type[LoadStoreSpec],
        OffloadingHandler,
    ]
]
Source code in vllm/v1/kv_offload/cpu.py
def get_handlers(
    self,
    kv_caches: dict[str, torch.Tensor],
    attn_backends: dict[str, type[AttentionBackend]],
) -> Iterator[tuple[type[LoadStoreSpec], type[LoadStoreSpec], OffloadingHandler]]:
    if not self._handlers:
        if not current_platform.is_cuda_alike():
            raise Exception(
                "CPU Offloading is currently only supported on CUDA-alike GPUs"
            )

        self._handlers = CpuGpuOffloadingHandlers(
            attn_backends=attn_backends,
            gpu_block_size=self.gpu_block_size,
            cpu_block_size=self.offloaded_block_size,
            num_cpu_blocks=self.num_blocks,
            gpu_caches=kv_caches,
        )

    assert self._handlers is not None
    yield GPULoadStoreSpec, CPULoadStoreSpec, self._handlers.gpu_to_cpu_handler
    yield CPULoadStoreSpec, GPULoadStoreSpec, self._handlers.cpu_to_gpu_handler

get_manager

get_manager() -> OffloadingManager
Source code in vllm/v1/kv_offload/cpu.py
def get_manager(self) -> OffloadingManager:
    if not self._manager:
        kv_events_config = self.vllm_config.kv_events_config
        enable_events = (
            kv_events_config is not None and kv_events_config.enable_kv_cache_events
        )

        backend = CPUBackend(
            block_size=self.offloaded_block_size, num_blocks=self.num_blocks
        )

        if self.eviction_policy == "lru":
            self._manager = LRUOffloadingManager(
                backend=backend, enable_events=enable_events
            )
        elif self.eviction_policy == "arc":
            self._manager = ARCOffloadingManager(
                backend=backend, enable_events=enable_events
            )
        else:
            raise ValueError(
                f"Unknown eviction policy: {self.eviction_policy}. "
                f"Supported policies: lru, arc"
            )
    return self._manager