Skip to content

vllm.distributed.kv_transfer.kv_connector.v1.hf3fs.utils.gather_scatter_helper

Classes:

  • CopyBufferAllocator

    Memory pool for tensor buffers to avoid frequent allocation/deallocation.

Functions:

  • gather_kv_caches

    Gather KV cache data from KV cache storage to destination tensor.

  • scatter_kv_caches

    Scatter KV cache data from source tensor to KV cache storage.

CopyBufferAllocator

Memory pool for tensor buffers to avoid frequent allocation/deallocation.

Methods:

Source code in vllm/distributed/kv_transfer/kv_connector/v1/hf3fs/utils/gather_scatter_helper.py
class CopyBufferAllocator:
    """Memory pool for tensor buffers to avoid frequent allocation/deallocation."""

    def __init__(
        self, device: torch.device, dtype: torch.dtype, shape: list, max_count: int
    ):
        self._shape = shape
        self._max_count = max_count
        self._device = device
        self._free_buffers = [
            torch.empty(shape, dtype=dtype, device=device) for _ in range(max_count)
        ]
        self._inuse_count = 0

    def alloc_buffer(self, count: int) -> list[torch.Tensor] | None:
        """Allocate buffers from the pool."""
        if count == 0:
            return []

        if self._inuse_count + count <= self._max_count:
            self._inuse_count += count
            result = self._free_buffers[-count:]
            del self._free_buffers[-count:]
            return result
        return None

    def free_buffer(self, buffers: list[torch.Tensor]) -> None:
        """Return buffers to the pool."""
        if not buffers:
            return

        if self._inuse_count >= len(buffers):
            self._inuse_count -= len(buffers)
            self._free_buffers.extend(buffers)
        else:
            raise RuntimeError("Attempted to free more buffers than allocated")

alloc_buffer(count)

Allocate buffers from the pool.

Source code in vllm/distributed/kv_transfer/kv_connector/v1/hf3fs/utils/gather_scatter_helper.py
def alloc_buffer(self, count: int) -> list[torch.Tensor] | None:
    """Allocate buffers from the pool."""
    if count == 0:
        return []

    if self._inuse_count + count <= self._max_count:
        self._inuse_count += count
        result = self._free_buffers[-count:]
        del self._free_buffers[-count:]
        return result
    return None

free_buffer(buffers)

Return buffers to the pool.

Source code in vllm/distributed/kv_transfer/kv_connector/v1/hf3fs/utils/gather_scatter_helper.py
def free_buffer(self, buffers: list[torch.Tensor]) -> None:
    """Return buffers to the pool."""
    if not buffers:
        return

    if self._inuse_count >= len(buffers):
        self._inuse_count -= len(buffers)
        self._free_buffers.extend(buffers)
    else:
        raise RuntimeError("Attempted to free more buffers than allocated")

gather_kv_caches(kv_caches_ptrs, total_token_in_kvcache, dst_tensor, token_indices, tokens_per_block, num_heads, content_size, kv_cache_strides)

Gather KV cache data from KV cache storage to destination tensor.

Parameters:

  • kv_caches_ptrs

    (Tensor) –

    Tensor of KV cache pointers (one per layer)

  • total_token_in_kvcache

    (int) –

    Total number of tokens in KV cache

  • dst_tensor

    (Tensor) –

    Destination [L, H, N, C] tensor

  • token_indices

    (list[int]) –

    List of token positions to gather

  • tokens_per_block

    (int) –

    Number of stored states in each cache block

  • num_heads

    (int) –

    Size of the H axis

  • content_size

    (int) –

    Size of the C axis

  • kv_cache_strides

    (tuple[int, ...]) –

    Element strides of each [B, H, N, C] layer view

Source code in vllm/distributed/kv_transfer/kv_connector/v1/hf3fs/utils/gather_scatter_helper.py
def gather_kv_caches(
    kv_caches_ptrs: torch.Tensor,
    total_token_in_kvcache: int,
    dst_tensor: torch.Tensor,
    token_indices: list[int],
    tokens_per_block: int,
    num_heads: int,
    content_size: int,
    kv_cache_strides: tuple[int, ...],
) -> None:
    """Gather KV cache data from KV cache storage to destination tensor.

    Args:
        kv_caches_ptrs: Tensor of KV cache pointers (one per layer)
        total_token_in_kvcache: Total number of tokens in KV cache
        dst_tensor: Destination ``[L, H, N, C]`` tensor
        token_indices: List of token positions to gather
        tokens_per_block: Number of stored states in each cache block
        num_heads: Size of the H axis
        content_size: Size of the C axis
        kv_cache_strides: Element strides of each ``[B, H, N, C]`` layer view

    """
    num_layers = kv_caches_ptrs.shape[0]
    num_tokens_in_block = len(token_indices)

    assert dst_tensor.shape == (
        num_layers,
        num_heads,
        num_tokens_in_block,
        content_size,
    )
    assert len(kv_cache_strides) == 4

    device = dst_tensor.device
    token_indices_tensor = async_tensor_h2d(
        token_indices, device=device, dtype=torch.int32
    )

    grid = (num_layers, num_tokens_in_block)
    BLOCK_SIZE = 128

    kv_cache_gather_kernel[grid](
        kv_caches_ptrs,
        dst_tensor,
        token_indices_tensor,
        num_tokens_in_block,
        total_token_in_kvcache,
        num_layers,
        tokens_per_block,
        *kv_cache_strides,
        num_heads=num_heads,
        content_size=content_size,
        BLOCK_SIZE=BLOCK_SIZE,
    )

scatter_kv_caches(kv_caches_ptrs, total_token_in_kvcache, src_tensor, token_indices, tokens_per_block, num_heads, content_size, kv_cache_strides)

Scatter KV cache data from source tensor to KV cache storage.

Parameters:

  • kv_caches_ptrs

    (Tensor) –

    Tensor of KV cache pointers (one per layer)

  • total_token_in_kvcache

    (int) –

    Total number of tokens in KV cache

  • src_tensor

    (Tensor) –

    Source [L, H, N, C] tensor containing data to scatter

  • token_indices

    (list[int]) –

    List of token positions to update

  • tokens_per_block

    (int) –

    Number of stored states in each cache block

  • num_heads

    (int) –

    Size of the H axis

  • content_size

    (int) –

    Size of the C axis

  • kv_cache_strides

    (tuple[int, ...]) –

    Element strides of each [B, H, N, C] layer view

Source code in vllm/distributed/kv_transfer/kv_connector/v1/hf3fs/utils/gather_scatter_helper.py
def scatter_kv_caches(
    kv_caches_ptrs: torch.Tensor,
    total_token_in_kvcache: int,
    src_tensor: torch.Tensor,
    token_indices: list[int],
    tokens_per_block: int,
    num_heads: int,
    content_size: int,
    kv_cache_strides: tuple[int, ...],
) -> None:
    """Scatter KV cache data from source tensor to KV cache storage.

    Args:
        kv_caches_ptrs: Tensor of KV cache pointers (one per layer)
        total_token_in_kvcache: Total number of tokens in KV cache
        src_tensor: Source ``[L, H, N, C]`` tensor containing data to scatter
        token_indices: List of token positions to update
        tokens_per_block: Number of stored states in each cache block
        num_heads: Size of the H axis
        content_size: Size of the C axis
        kv_cache_strides: Element strides of each ``[B, H, N, C]`` layer view

    """
    num_layers = len(kv_caches_ptrs)
    num_tokens_in_block = len(token_indices)

    assert src_tensor.shape == (
        num_layers,
        num_heads,
        num_tokens_in_block,
        content_size,
    )
    assert len(kv_cache_strides) == 4

    device = src_tensor.device
    token_indices_tensor = async_tensor_h2d(
        token_indices, device=device, dtype=torch.int32
    )

    grid = (num_layers, num_tokens_in_block)
    BLOCK_SIZE = 128

    kv_cache_scatter_kernel[grid](
        kv_caches_ptrs,
        src_tensor,
        token_indices_tensor,
        num_tokens_in_block,
        total_token_in_kvcache,
        num_layers,
        tokens_per_block,
        *kv_cache_strides,
        num_heads=num_heads,
        content_size=content_size,
        BLOCK_SIZE=BLOCK_SIZE,
    )