Skip to content

[RFC] Prefix caching on paged KV cache path #159

Description

@ricky-chaoju

Problem

The paged KV path recomputes KV from scratch on every prefill, even when requests share the same prefix (system prompts, multi-turn history). This hurts TTFT.

What the upstream scheduler already does

The upstream vLLM scheduler handles block hashing, cache hit detection, and block reuse:

  1. Request.update_block_hashes() computes chained block hashes on request creation
  2. kv_cache_manager.get_computed_blocks(request) finds the longest prefix cache hit
  3. NewRequestData.num_computed_tokens carries the hit count to the model runner
  4. block_ids includes both cached and newly allocated blocks
  5. enable_prefix_caching defaults to True, nothing in vllm-metal forces it off

No hash/LRU code needed on our side — the scheduler handles all of that.

What vllm-metal's paged path does today

The model runner reads num_computed_tokens (model_runner.py:1949), but only uses it for intermediate chunk detection. For complete prefills, it always processes all tokens from position 0.

Why this is blocked on kernel_v2

Our prefill uses mx.fast.scaled_dot_product_attention(Q, K, V) — it takes Q/K/V as input tensors and can't read cached K/V from paged blocks. If we skip the prefix tokens, SDPA won't have the prefix K/V and attention output will be wrong.

On GPU, flash attention reads cached K/V directly from paged blocks via block tables. We need kernel_v2 (varlen attention, #148 Stage 2) to do the same on Metal.

Once kernel_v2 lands:

  1. When num_computed_tokens > 0, only prefill token_ids[num_computed_tokens:]
  2. Add offset to prepare_prefill() so slot_mapping starts from the right position
  3. Set RoPE offset = num_computed_tokens
  4. Kernel_v2 reads cached prefix K/V from paged blocks via block tables

RFC @WindChimeRan @LxYuan0420

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions