Appearance
KV缓存与PagedAttention — 练习
练习 1:块分配模拟
配置:block_size=16,总共 8 个物理块。
请求序列:
- 请求 A:prompt 40 tokens
- 请求 B:prompt 24 tokens(前 16 tokens 与 A 相同)
- 请求 A decode 10 个新 token
- 请求 C:prompt 48 tokens(前 16 tokens 与 A 相同)
请模拟每步的块分配状态(物理块使用情况、空闲块数、引用计数)。
参考答案
初始:8 个空闲块 [0-7]
请求 A(40 tokens):需要 3 个块(ceil(40/16)=3)。分配块 [0,1,2]。空闲:5
- Block 0: hash(A[0:16]), ref=1
- Block 1: hash(A[16:32]), ref=1
- Block 2: hash(A[32:40]), ref=1(部分填充)
请求 B(24 tokens,前 16 与 A 相同):需要 2 个块。
- Block 0: hash 匹配,复用,ref=2
- Block 3: 新分配(B[16:24]),ref=1
- 空闲:4
请求 A decode 10 tokens:现有 40+10=50 tokens,需要 ceil(50/16)=4 个块。
- Block 2 原来只填到 40,现在填到 48(8 个新 token)
- 需要 Block 4(第 49-50 token),新分配,ref=1
- 空闲:3
请求 C(48 tokens,前 16 与 A 相同):需要 3 个块。
- Block 0: hash 匹配,复用,ref=3
- Block 5, 6: 新分配(C[16:48]),ref=1
- 空闲:1
练习 2:前缀缓存效果分析
假设 system prompt 为 512 tokens,有 10 个并发请求共享此 system prompt。
计算有无前缀缓存时的 KV 缓存块数(block_size=16):
- 无前缀缓存
- 有前缀缓存
参考答案
System prompt 块数:ceil(512/16) = 32 块
无前缀缓存:每个请求独立存储 system prompt。
- 10 × 32 = 320 块用于 system prompt
- 总共至少 320 + 10 × (user query blocks)
有前缀缓存:所有请求共享一份 system prompt。
- 32 块用于 system prompt(ref=10)
- 总共 32 + 10 × (user query blocks)
- 节省:320 - 32 = 288 块(90% 节省)
练习 3:KV 缓存卸载策略分析
分析以下场景中应该使用哪种卸载策略:
- 10 个请求并发,GPU 显存刚好够用,但第 11 个请求到达
- 100 个长对话请求,其中 80% 已进入空闲等待状态
- 离线批量推理场景,请求按顺序处理
参考答案
Re-computation:只是暂时的显存压力,抢占一个请求后很快会恢复。重新 prefill 的开销小于 swap 的 I/O 开销。
CPU Swapping:大量不活跃请求,适合将它们的 KV 缓存换出到 CPU 内存。当用户继续对话时再换入。
不卸载:离线场景中请求按顺序处理,不需要保留已完成请求的 KV 缓存。直接释放即可。
拓展挑战
- 阅读
vllm/v1/core/kv_cache_utils.py中的块哈希计算逻辑 - 分析
KVCacheCoordinator如何管理多个缓存组(sliding window + full attention) - 研究
simple_kv_offload/manager.py的卸载实现