perf: MLA 历史分块 prefill 与稀疏打分优化(默认 16K) - #30
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
改动解决的问题
MLA 将历史 KV 压缩为 latent 与 RoPE cache,但旧 prefill 会一次 gather 全历史,再展开成逐 head 的 K/V。历史越长,展开张量和投影临时空间越大;单纯提高 workspace 上限只能允许更大的分配,不能限制峰值。
本 PR 将历史的 gather → KV 投影展开 → attention → 合并 整条链按块执行,同时保留稀疏方法所需的观察窗口打分。生产路径收敛为 logits 复用展开 K、probability 扫描 latent,移除四组合实验覆盖开关和旧全量展开入口。
新增配置
mla_prefill_history_chunk_size,默认 16384(16K),要求正整数。它控制每次展开的历史 KV token 数,与调度器的engine_prefill_chunk_size、max_num_batched_tokens分别独立;不进行自适应容量搜索或 OOM 后循环重试。中英文配置文档均已同步 16K。分块 attention 如何执行
对两个不相交 key 分区,设局部结果为
(O₁, L₁)和(O₂, L₂),其中L = logsumexp(scaled QK):合并采用 FP32 累加,避免每个历史块都进行一次 BF16 舍入。这保持完整历史 attention 的数学语义;不同 GEMM/归约顺序仍可能造成浮点差异,不要求逐 bit 相等。
在支持的 provider 上使用 FA3 contiguous varlen partial attention;没有相应入口时使用绑定的 Triton partial attention 实现。provider 解析不放入 forward 热路径。
内存边界:历史展开量由总历史长度降为单块 W;当前 packed token 仍由调度 token budget 决定。最终 token scores、query/output、LSE 和 metadata 仍占用空间,因此不能将“历史 KV 展开受限”理解成整个 workspace 完全不随输入增长。现有 workspace 预算检查保留,估算按分块 live tensors 计算。
两种稀疏打分方式
记观察 query 集合为 Ω,可参与选择的 causal key 集合为 C(q)。观察窗口只限制使用哪些 Q;probability 仍沿 eligible K 维度归一化,不会沿观察 Q 归一化。
logitsprobabilitylogits:复用主 attention 已展开的 K
当前 token 与每个历史块都在 K 释放前完成打分。评分 kernel 直接归约出每个 token 的分数,不持久化完整的观察 Q×全部 K 矩阵,也不需要第二遍历史扫描。打分与主 attention 使用同一份已展开 K,可以避免为 logits 额外变换 Q 引入的 BF16 舍入差异。
probability:在 latent 空间重建观察 QK
采用列向量记法,若
K_nope = W_K · c,则:仅变换观察窗口的 Q;随后扫描共享 latent 与 RoPE cache 计算分数。评分是主 attention 外的独立 kernel,不是向 FA3 内部插入评分逻辑。
分母有两种情况:
生产没有 latent-logits / 展开-K-probability 的实验选择开关;算法模式仍由
sparse_prefill_score_mode指定,不自动将 probability 替换成 logits。展开 K 与 absorbed Q 的有限精度计算并非逐 bit 等价,数值测试与 LongBench 分别检查数学误差和最终任务表现。代码职责与兼容范围
PrefillScoreRequest描述每条请求的观察 query 范围、评分模式与候选边界;cache manager 将现有方法状态映射为物理坐标,operator 消费请求并返回token_scores。现有方法继续负责评分后的累计、pooling、选择与缓存管理。PrefillComputeView.token_scores是可选结果交接;没有预计算分数时沿用现有 collector。GQA/MHA 主 attention 与 MLA decode 算法未在本 PR 中改写。run_explicit_prefill及相应 capability 标记。性能数据:GLM-4.7-Flash / SnapKV
采用新旧实现的配套性能测试结果。H100 80GB、TP=1、BF16、
sgl_fa3_sm90,fixed batch=4,输出 512 tokens;观察窗口 32、pool kernel=1、decode keep=2048、结果中的稀疏预算=2176;当前 prefill chunk 与 max batched tokens 均为 8192,GPU utilization=0.95。seed=42,每种长度预热 1 轮、测量 2 轮,每行统计 8 个请求。已核对新旧所有运行的逐请求 prompt digest、输入/输出长度、iteration 与 request index 一致,全部测量请求成功。16K/32K/64K 为 nominal prompt 长度,实际请求有相同的长度扰动。
新实现的历史块容量扫描
每格为 平均 TTFT(秒) / 端到端输出吞吐(tok/s);W 为历史块容量,不是当前 prefill chunk。
这组 logits 扫描中 16K 的三个长度 TTFT 与吞吐均优于 4K/8K/32K,支持将默认历史块设为 16K。没有 probability / 16K 实测,不能将 logits 的块容量结论直接推广成 probability 最优值。
同为 W=8K 时,logits 相比 probability 的 TTFT 低约 1%–2%,输出吞吐也接近;新 probability 已不再呈现旧实现中数秒级的额外 TTFT。
与旧实现对比
数据解释:旧结果与新结果使用不同的同型号 H100;因此小幅提升按本批实测报告,不声称严格同卡配对显著性。吞吐使用
output_token_throughput_tps,包含 prefill 对端到端时长的影响,不等同于纯 decode kernel 吞吐或理论 MFU。probability 的大幅改善来自整条实现路径变化,不能全部归因于 latent 点积更快。旧评分中的长度相关 Triton 编译特化可在新请求长度上触发额外编译;新实现的有界扫描与运行时长度处理也改变了这部分开销。本组端到端记录未分离每个因素的贡献。
LongBench v1:完整 1,500 样本结果
对比新旧实现的 logits 与 probability,共四组完整评估结果。
四组均为 1,500 个 success,无失败;已核对
(dataset, source_idx)、prompt token 数与参考答案一致。repobench-p 为 500 个样本,其余五任务各 200 个。配置记录中的samples_per_task=20不代表本次实际计分数量,数量以逐样本文件及 task status 为准。新质量运行均显式使用 W=8192。其余关键配置:TP=1、batch size=4、max model len=131072、max batched tokens=65536、当前 prefill chunk=8192、window=32、pool=1、decode keep=2048、decode graph 开启、prefix cache 关闭、temperature=0、top_p=1、top_k=1、seed=42、thinking off。
类别平均未包含
multifieldqa_zh,因此与六任务等权平均不同。新 logits 相比旧 logits 等权平均 +0.13 分;新 probability 相比旧 probability +0.03 分。新 logits 比新 probability 高约 0.30 分,六任务中 4 项领先、1 项持平、1 项略低;这批数据没有显示 probability 的整体质量优势,但未做逐样本显著性检验。同一 LongBench runtime 配置下,记录的 KV slots 从旧 logits 的 165,635 增至新 logits/probability 的 231,948(+40.0%)。这是这组 W=8K 配置下的可用容量观测,不能直接当作 16K 默认值下的容量,也不代表采样到的整卡显存峰值下降 40%。
基于这些数据,logits 是这组 GLM/SnapKV 工作负载的优先选择;probability 保留其原有算法语义,并获得更低内存的实现。没有新增自动选择打分模式的策略。
验证与复现边界
git diff --check通过。