Skip to content

vllm.v1.attention.ops.common

Functions:

  • pack_seq_triton

    Pack sequences of different lengths into a batched tensor.

  • unpack_seq_triton

    Unpack a packed decode query tensor back to the original format.

pack_seq_triton(x, lengths, pad_value=-float('inf'), block_t=64, block_d=64)

Pack sequences of different lengths into a batched tensor.

Supports float dtypes (any, via fp32 pad) and torch.uint8 (exact-byte pad — e.g. MXFP4 packed nibbles or ue8m0 scale bytes). For uint8 inputs pad_value must be an integer in [0, 255].

Parameters:

  • x

    (Tensor) –

    [N, ...] — input tensor where N is total number of tokens.

  • lengths

    (Tensor) –

    [B] — sequence lengths for each batch.

  • pad_value

    (float | int, default: -float('inf') ) –

    value to use for padding. Defaults to -inf which is only sensible for float dtypes; pass 0 (or any byte) for uint8 inputs.

  • block_t

    (int, default: 64 ) –

    block size for time dimension.

  • block_d

    (int, default: 64 ) –

    block size for feature dimension.

Returns:

  • packed ( Tensor ) –

    [B, Lmax, ...] — packed tensor.

Source code in vllm/v1/attention/ops/common.py
def pack_seq_triton(
    x: torch.Tensor,
    lengths: torch.Tensor,
    pad_value: float | int = -float("inf"),
    block_t: int = 64,
    block_d: int = 64,
) -> torch.Tensor:
    """Pack sequences of different lengths into a batched tensor.

    Supports float dtypes (any, via fp32 pad) and ``torch.uint8`` (exact-byte
    pad — e.g. MXFP4 packed nibbles or ue8m0 scale bytes). For uint8 inputs
    ``pad_value`` must be an integer in ``[0, 255]``.

    Args:
        x: [N, ...] — input tensor where N is total number of tokens.
        lengths: [B] — sequence lengths for each batch.
        pad_value: value to use for padding. Defaults to ``-inf`` which is
            only sensible for float dtypes; pass ``0`` (or any byte) for
            uint8 inputs.
        block_t: block size for time dimension.
        block_d: block size for feature dimension.

    Returns:
        packed: [B, Lmax, ...] — packed tensor.
    """
    is_uint8 = x.dtype == torch.uint8
    if is_uint8:
        assert isinstance(pad_value, int) and 0 <= pad_value <= 255, (
            f"uint8 pack requires an integer pad in [0, 255], got {pad_value!r}"
        )
        pad_constexpr: int | float = int(pad_value)
    else:
        pad_constexpr = float(pad_value)

    # Handle multi-dimensional input by reshaping to (N, -1)
    original_shape = x.shape
    if len(original_shape) > 2:
        N = original_shape[0]
        x_reshaped = x.reshape(N, -1)
        D = x_reshaped.shape[1]
    else:
        N, D = x.shape
        x_reshaped = x

    B = lengths.numel()
    Lmax = int(lengths.max().item())

    out = torch.empty((B, Lmax, D), device=x.device, dtype=x.dtype)

    grid = (B, triton.cdiv(Lmax, block_t), triton.cdiv(D, block_d))
    _pack_seq_kernel[grid](
        x_reshaped,
        out,
        lengths.int(),
        N,
        D,
        Lmax,
        PAD_VALUE=pad_constexpr,
        PAD_IS_UINT8=is_uint8,
        BLOCK_T=block_t,
        BLOCK_D=block_d,
        num_warps=4,
        num_stages=2,
    )

    if len(original_shape) > 2:
        out = out.reshape((B, Lmax) + original_shape[1:])

    return out

unpack_seq_triton(packed_tensor, lengths, block_t=64, block_d=64)

Unpack a packed decode query tensor back to the original format. Efficient Triton implementation.

Parameters:

  • packed_tensor

    (Tensor) –

    [B, Lmax, ...] - packed tensor from pack_seq_triton

  • lengths

    (Tensor) –

    [B] - sequence lengths for each batch

  • block_t

    (int, default: 64 ) –

    block size for time dimension

  • block_d

    (int, default: 64 ) –

    block size for feature dimension

Returns:

  • unpacked_tensor ( Tensor ) –

    [N, ...] where N = sum(lengths)

Source code in vllm/v1/attention/ops/common.py
def unpack_seq_triton(
    packed_tensor: torch.Tensor,
    lengths: torch.Tensor,
    block_t: int = 64,
    block_d: int = 64,
) -> torch.Tensor:
    """
    Unpack a packed decode query tensor back to the original format.
    Efficient Triton implementation.

    Args:
        packed_tensor: [B, Lmax, ...] - packed tensor from pack_seq_triton
        lengths: [B] - sequence lengths for each batch
        block_t: block size for time dimension
        block_d: block size for feature dimension

    Returns:
        unpacked_tensor: [N, ...] where N = sum(lengths)
    """

    # Handle multi-dimensional input by reshaping to (B, Lmax, -1)
    original_shape = packed_tensor.shape
    if len(original_shape) > 3:
        B, Lmax = original_shape[:2]
        packed_reshaped = packed_tensor.reshape(B, Lmax, -1)
        D = packed_reshaped.shape[2]
    else:
        B, Lmax, D = packed_tensor.shape
        packed_reshaped = packed_tensor

    # Calculate total number of elements
    N = int(lengths.sum().item())

    out = torch.empty((N, D), device=packed_tensor.device, dtype=packed_tensor.dtype)

    grid = (B, triton.cdiv(Lmax, block_t), triton.cdiv(D, block_d))
    _unpack_seq_triton_kernel[grid](
        packed_reshaped,
        out,
        lengths.int(),
        B,
        Lmax,
        D,
        BLOCK_T=block_t,
        BLOCK_D=block_d,
        num_warps=4,
        num_stages=2,
    )

    # Reshape output back to original dimensions (except first dimension)
    if len(original_shape) > 3:
        output_shape = (N,) + original_shape[2:]
        out = out.reshape(output_shape)

    return out