执行摘要
- 一句话:为混合缓存实现 Marconi 式共享前缀准入策略,提升 Qwen 等模型缓存命中率
- 推荐动作:值得精读。该 PR 展示了如何在不修改 kernel 的情况下利用现有缓存机制实现高级缓存准入策略,设计思路可推广到其他 hybrid attention 模型。
功能与动机
Marconi 论文 (https://arxiv.org/abs/2411.19379) 提出两种有效缓存准入策略:最后状态和共享前缀。vLLM 此前只支持最后状态缓存,缺少共享前缀缓存,导致系统提示等重复前缀场景无法充分利用前缀缓存。本 PR 实现共享前缀缓存,以进一步减少预填充时间。
实现拆解
- 在
KVCacheCoordinator._get_cache_hit_blocks 中新增 longest_hit_length 记录所有 attention 组的最长缓存命中,计算 num_uncached_common_prefix_tokens 并暴露为属性。
- 在
Scheduler.schedule 中,若模型包含 Mamba 层,从协调器读取 num_uncached_common_prefix_tokens。
- 在
Scheduler._mamba_block_aligned_split 中接收该参数,若未缓存公共前缀 ≥ block_size 且当前调度长度更长,则截断调度长度以强制缓存该前缀,保持块对齐。
- 新增测试
test_hybrid_cache_mamba_align_shared_prefix_detection,覆盖共享前缀检测及调度调整逻辑。
关键文件:
vllm/v1/core/sched/scheduler.py(模块 调度器;类别 source;类型 core-logic;符号 _mamba_block_aligned_split, schedule): 核心调度器,修改了 _mamba_block_aligned_split 函数以支持共享前缀缓存的调度对齐
vllm/v1/core/kv_cache_coordinator.py(模块 缓存协调器;类别 source;类型 core-logic;符号 _get_cache_hit_blocks, num_uncached_common_prefix_tokens): 缓存协调器,追踪最长缓存命中长度并暴露未缓存公共前缀长度,为调度器提供决策依据
tests/v1/core/test_prefix_caching.py(模块 测试;类别 test;类型 test-coverage;符号 test_hybrid_cache_mamba_align_shared_prefix_detection): 新增 test_hybrid_cache_mamba_align_shared_prefix_detection 测试,验证共享前缀检测和调度调整
关键符号:_mamba_block_aligned_split, _get_cache_hit_blocks, test_hybrid_cache_mamba_align_shared_prefix_detection
关键源码片段
vllm/v1/core/kv_cache_coordinator.py
缓存协调器,追踪最长缓存命中长度并暴露未缓存公共前缀长度,为调度器提供决策依据
def _get_cache_hit_blocks(self, block_hashes, max_cache_hit_length):
# ... 初始化变量 ...
longest_hit_length = 0 # 新增:记录所有 attention 组中的最长命中
while True:
curr_hit_length = hit_length
for idx, (spec, group_ids, manager_cls, use_eagle) in enumerate(
self.attention_groups
):
# ... 原有逻辑:查找每组最长缓存命中 ...
hit_blocks = manager_cls.find_longest_cache_hit(...)
_new_hit_length = len(hit_blocks[0]) * spec.block_size
# ... 更新 curr_hit_length ...
# 新增:更新全局最长命中
longest_hit_length = max(longest_hit_length, curr_hit_length)
# ... 循环终止条件 ...
# ... 截断 Full Attention 块 ...
# 新增:计算未缓存的公共前缀 token 数
self.num_uncached_common_prefix_tokens = longest_hit_length - hit_length
return (blocks_tuple, hit_length)
评论区精华
命名讨论
tdoublep 建议将参数名 mamba_tokens_lag 改为 num_uncached_common_prefix_tokens,语义更清晰,已采纳。
未初始化变量风险
gemini-code-assist 指出 mamba_tokens_lag 可能未定义导致 UnboundLocalError;作者说明该路径受条件保护,后续版本通过属性方式彻底规避。
变量复用可读性
gemini-code-assist 指出 num_new_local_computed_tokens 复用易混淆;作者重构为直接使用协调器属性,消除复用。
协调器返回值设计
tdoublep 和 yannicks1 讨论 get_computed_blocks 是否应返回两个长度;最终采用协调器属性方式,简化接口。
条件判断粒度
yannicks1 建议使用 need_mamba_block_aligned_split;作者认为 has_mamba_layers 更通用,以覆盖非 align 模式。
- 重命名参数 mamba_tokens_lag (design): 作者同意并修改。
- 未初始化变量风险 (correctness): 作者解释该代码块受条件保护,后续版本通过属性方式避免。
- 变量复用导致可读性差 (style): 作者重构为直接返回 num_uncached_common_prefix_tokens,移除了复用。
- 协调器返回值设计 (design): 作者改为在协调器上设置属性 num_uncached_common_prefix_tokens,调度器直接读取。
- 条件判断使用 has_mamba_layers vs need_mamba_block_aligned_split (design): 作者解释 has_mamba_layers 更通用,因为需要获取最长命中长度,即使 mamba 模式不是 align。
- 测试中断言顺序 (testing): 作者调整了测试中的断言顺序。
风险与影响
关联脉络
参与讨论