跳到主要内容

G5 MLA KV 访存建模设计规格

版本:0.1.1 状态:Accepted 创建日期:2026-06-22 最后更新:2026-06-22 作者:xiang.li 前置G5-计算算子建模方法分层设计规格G5-softmax算子建模设计规格

版本号规则 (SemVer):

  • major (X.0.0):KV 访存建模形态重构、latent 口径变更
  • minor (X.Y.0):新增阶段(如 chunked-prefill)、新增 KV 访存项(向后兼容)
  • patch (X.Y.Z):修正笔误、补充说明

变更历史

版本日期变更说明
0.1.02026-06-22初版:G5 fa2 路径 MLA latent KV 访存建模 + decode HBM KV 读取访存腿

@tbl-gmkv-00 文档变更历史


概述

本 spec 定义 G5 路径(Rust 指令级事件驱动仿真)下 MLA(Multi-head Latent Attention)的 KV 访存建模,解决两处与硬件行为不符的现状:fa2 的 DMA 访存量用 tiling buffer 大小代替真实 KV 读量decode 阶段从 HBM 读历史 latent KV cache 的访存通路缺失。目标模型为 DeepSeek-V3/V3.2(MLA 结构)。方法论引用父 spec《G5-计算算子建模方法分层设计规格》的 roofline 分层,不重立方法;不动 Math 路径,不碰已建模的 softmax 发射。

背景

G5 的 MLA 计算行为建模有两个量化缺陷,导致 decode 阶段访存失真:

  • fa2 的 DMA 访存量不是真实 KV 读量:fa2 发射的 prologue DMA 用 tiling buffer 大小(a_tile_bytes / b_tile_bytes)作为搬运字节数,是片上 tile 的容量,不反映从 HBM 实际读取的 KV cache 字节量。

  • decode 的 HBM latent-KV 读取通路缺失:G5 当前的访存边只计 LMEM 操作数读取,不含 decode 阶段从 HBM 搬全部历史 KV cache 的字节量。decode(query 长度 1、读全历史 KV)的真实瓶颈正是这条 HBM→片上的搬运。缺它,"decode 访存受限"在模型里无法成立——而 decode 是 MLA 部署的主要场景。

  • MLA 的 KV 是 latent 压缩,访存语义独特:MLA 用低秩投影把 KV 压成 latent 向量(维度 kv_lora_rank,DeepSeek-V3 为 512),外加单独缓存的解耦 RoPE key(维度 qk_rope_head_dim,64)。decode 缓存与读取的是 latent,字节量按 kv_lora_rank + qk_rope_head_dim 算,与 num_heads × head_dim 无关。这与 GQA 的 H_kv × head_dim 是完全不同的口径——按完整 K/V 算会高估约 57 倍(DeepSeek-V3 实测 KV cache 等效 GQA 2.25 组、较 MHA 压缩约 1/57)。

  • 配置加载违规:现状 kv_lora_rank / qk_rope_head_dim 等用带默认值的方式读取(缺失时回退到 hidden_size 或 0),违反项目 config-loading.md。MLA 模型缺这些字段应 raise,不应静默回退。

名词定义

名词定义
latent KV (c_KV)MLA 低秩投影压缩后的 KV 表示,decode 缓存的对象
kv_lora_rank (d_c)KV latent 的维度,DeepSeek-V3 为 512
qk_rope_head_dim (d_rope)解耦 RoPE key 的维度,单独缓存(RoPE 无法在 latent 空间计算),DeepSeek-V3 为 64
KV cache 字节每 token 每层缓存的 KV 字节量 = (d_c + d_rope) × dtype_bytes
decode KV-readdecode 单步从 HBM 读全部历史 latent KV cache 的字节量
prefill处理输入 prompt 阶段,一次算所有 prompt token,attention 算力受限
decode自回归单 token 生成阶段,读全历史 KV cache,访存受限
上下文长度 (s_ctx)decode 某步已累积的历史 token 数
standard 模式MLA 先把 latent 解压成完整 K/V 再做 attention(mla_mode=standard)
absorb 模式MLA 把上投影矩阵吸收进 Q/O,直接在 latent 空间算,不解压 K/V(部署主流)
HBM 访存腿roofline 访存支中,从 HBM 搬 KV cache 到片上的字节量 / 带宽

目标与非目标

目标

  1. decode 的 latent KV 读取建为独立访存项:新增一个独立的 cache-read 访存项表示从 HBM 读历史 latent KV,不挂 fa2 prologue、不用 tiling buffer 大小(fa2 prologue 搬的是 standard 模式解压后的完整 K/V,属片上中间激活,见 概念模型 (b),本期不改)。
  2. decode 的 HBM latent-KV 读取进延迟项:decode 单步从 HBM 读全历史 latent KV 的字节量进入 roofline 访存支,使 decode 访存受限可被建模。
  3. KV 访存按 latent 维度:KV cache 与 decode 读量按 kv_lora_rank + qk_rope_head_dim 缩放,与 num_headshead_dim 无关。
  4. 配置合规kv_lora_rank / qk_rope_head_dim 必填,缺失 raise(含字段名 + 来源),不静默回退。

非目标

  • TIU cycle 常数 / LMEM 带宽 / bank_conflict / overlap 率等速率标定(依赖真机,后续 B 阶段)。
  • GQA / GLM 的 H_kv × head_dim KV 访存口径(GLM 进项目单独 spec,KV 语义不同)。
  • Math 路径任何改动。
  • softmax 发射路径(已建模)。
  • standard 模式解压中间激活的精确建模(standard 先解压完整 K/V 产生额外中间激活访存,本期只建两模式共性的 HBM latent-KV 读取主干,解压差异留后续)。

用例说明

用例 1 — DeepSeek-V3 decode 访存(主场景):评估 DeepSeek-V3(kv_lora_rank=512, qk_rope=64, FP8)单步 decode,历史 4096。fa2 应让 decode 从 HBM 读历史 latent KV 的字节量 = B × 4096 × (512+64) × 1 进入访存支,roofline 判定为访存受限;该字节量与 num_heads(128) 无关。

用例 2 — prefill 数值退化:prefill(query=历史=prompt 长)下,KV 是当前 batch 现算的,不读历史 cache,attention 算力受限——修订后 prefill 的访存量与计算量不发生变化(退化为现状)。

用例 3 — 配置缺失报错:MLA 模型配置未提供 kv_lora_rank。构建时 raise,错误含字段名与来源,不回退到 hidden_size。

详细设计

概念模型

MLA 的 KV cache 以压缩 latent 形式存于 HBM。建模区分两个独立访存事件:

  • (a) decode 从 HBM 读历史 latent KV cache:decode 的访存瓶颈,字节量按 latent 维度(d_c + d_rope)、与 num_heads/head_dim 无关。这是本 spec 要补的独立 cache-read 访存项
  • (b) standard 模式下 latent 上投影成完整 K/V:产物是片上中间激活,不是 HBM cache 读,本期不建(见 目标与非目标 节)。

(a) 是独立访存项,不挂在 fa2 的 prologue DMA 上——standard 模式下 fa2 内部消费的是 (b) 的解压产物(完整 K/V),把 latent 读量挂上 fa2 会与之矛盾。prefill 不读历史 cache(KV 现算),只有 decode 有 (a) 这条腿。standard 与 absorb 两模式的 (a) HBM latent 读量相同(MLA 缓存内容不变量),差异只在 (b)——本期只建 (a) 这条两模式共性主干。

算法与公式

B=batch,d_c=kv_lora_rank,d_rope=qk_rope_head_dim,s_ctx=历史长度,e=dtype 字节数,L=层数。

每 token 每层 KV cache 字节

$\text{kv\_bytes} = (d_c + d_{rope}) \times e$

{#eq:gmkv-cache}

decode 单步 HBM latent-KV 读量(单层)

$\text{kv\_read} = B \times s_{ctx} \times (d_c + d_{rope}) \times e$

{#eq:gmkv-read}

与等效 MHA 的压缩比n_h=num_heads, d_h=head_dim):

$\text{ratio} = \frac{d_c + d_{rope}}{2 \cdot n_h \cdot d_h}$

{#eq:gmkv-ratio}

DeepSeek-V3 代入 (512+64)/(2·128·128) ≈ 1/57

roofline 访存支(引用父 spec):decode 时长由 kv_read / (BW_hbm · η_m) 主导,BW_hbm 为 HBM 带宽(单位 _gb_per_s),η_m 为可标定效率因子(后续 B 阶段填)。

设计原理

  • 为什么按 latent 而非完整 K/V:MLA 只缓存 latent c_KV + RoPE key,decode 从 HBM 读的就是 latent。按解压后的 n_h × d_h 算会忽略 MLA 的压缩收益,高估约 57 倍——MLA 的核心价值就在这压缩比。
  • 为什么 decode 访存受限、prefill 算力受限:decode query 长度 1、读全历史 latent KV,arithmetic intensity 低,落访存支;prefill query=历史,GEMM 形态高 intensity,落算力支。同一 roofline max() 原语,regime 由形状自动决定。
  • 为什么 standard/absorb 共用 latent 读量主干:两模式缓存内容相同(latent + RoPE key),decode 从 HBM 搬的 KV 量相同,是 MLA 不变量。standard 多出的解压中间激活是次要项,本期不建,留标注。
  • 为什么 DMA 字节不能用 tiling buffer:tiling buffer 是片上 tile 容量,与从 HBM 实际搬的 KV 量无关;decode 的瓶颈正是 HBM 搬运量,用 buffer 大小代替会丢掉这条主瓶颈。

约束

  • kv_lora_rankqk_rope_head_dim 必填,缺失 raise,错误含字段名与来源。
  • 带宽字段命名遵循 naming-conventions.md_gb_per_s)。
  • 不引入带默认值的配置加载。

集成点

  • 上游:模型元数据层提供 kv_lora_rankqk_rope_head_dim、阶段标识(prefill/decode)、历史长度 s_ctx(decode)。
  • 下游:访存量进 G5 的 roofline 访存支与事件驱动时序层。
  • 与 softmax 的边界:本 spec 只改 fa2 的 KV 访存量(DMA 搬运字节 + decode HBM 读取腿),不碰 softmax 发射、不碰 QK^T/PV 的 cycle 公式。
  • decode HBM latent-KV 读取的算子归属:作为独立 cache-read 访存项建模,归属一个表示"读历史 latent KV cache"的算子节点,不并入 fa2 的 prologue DMA。理由:standard 模式下 fa2 内部消费解压后的完整 K/V,latent 读量挂 fa2 会与之矛盾(见 概念模型 节)。
  • MLA 模式范围:本期只建 standard 与 absorb 两模式共性的 HBM latent-KV 读取主干(事件 a),不依赖 absorb 落地,也不建 standard 的解压中间激活(事件 b,见 局限与后续工作 节)。

备选方案

方案否决理由
decode KV 读量按解压后完整 K/V(n_h × d_h)算那是 MHA 口径,忽略 MLA latent 压缩收益,高估约 57×——MLA 的核心价值就是只读 latent
只改 fa2 的 DMA tile 字节、不建 HBM latent-KV 读取腿decode 瓶颈在 HBM 搬全历史 latent KV,不在 fa2 的片上 tile;不建这条腿,decode 访存受限仍无法成立
本期就把 standard 解压中间激活精确建模解压激活是 standard 特有的次要项,部署主流是 absorb(无解压);先建两模式共性的 latent 读取主干,避免范围膨胀

完整业界调研对比见 附录 A。

非功能性需求

  • 兼容性:prefill 阶段(不读历史 cache)的访存量与计算量在修订后不变(退化为现状)。
  • 性能:访存量为闭式公式,不增加 G5 仿真时间复杂度。

局限与后续工作

  • 速率标定(B 阶段):本 spec 定义访存量口径,TIU cycle / HBM 带宽 / η_m 等速率常数仍是未标定 placeholder,绝对时长不可信、仅相对可信,标定依赖真机。
  • standard 解压中间激活:standard 模式解压 latent→完整 K/V 的中间激活访存本期不建,留后续。
  • GQA / GLMH_kv × head_dim 口径的 KV 访存(GLM 类)单独 spec。

验收标准

因绝对速率是 placeholder(B 阶段未做),本期只验证相对正确性,不验证绝对时长:

  1. decode 单步 latent KV 读量 = B × s_ctx × (d_c + d_rope) × e(@eq:gmkv-read),公式中不含 num_headshead_dim
  2. MLA 的 decode KV 读量显著小于等效 MHA,比值 ≈ (d_c+d_rope)/(2·n_h·d_h)(@eq:gmkv-ratio,DeepSeek-V3 约 1/57)。
  3. decode KV 读量随历史长度 s_ctx 单调增。
  4. prefill 退化测试:prefill 形状下(KV 为当前 batch 现算、无历史 cache 读,decode 独立 cache-read 项不发射),访存量与计算量与现状一致(数值无漂移)。
  5. kv_lora_rank / qk_rope_head_dim 缺失时 raise,错误含字段名与来源。
  6. 新增 decode/KV 访存分支的串行/overlap 用 op_start_ns / op_end_ns 断言,禁止 duration-sum(防 overlap 被掩盖)。
  7. fa2 的 KV cache-read 访存项字节量等于真实 latent KV 读量(@eq:gmkv-read 对应项),不等于 tiling buffer 容量。
  8. 测试用 conftest 的内存 dict(SG2262_CONFIG),不读真实 YAML;断言严格无容差。

附录 A:业界调研

来源MLA KV 访存建模关键数字出处
DeepSeek-V2 论文只缓存 latent c_KV + RoPE key,(d_c+d_rope)·l 元素;等效 GQA 2.25 组;较 V2 自身 MHA 配置压缩 93.3%(论文口径),按 (d_c+d_rope)/(2·n_h·d_h) 为等效 MHA 的 ≈1/57(比值口径)d_c=512, d_rope=64, n_h=128arXiv:2405.04434 §2.1/§3.1
DeepSeek-V3 论文同 MLA 结构L=61arXiv:2412.19437
FlashMLA(官方实现)decode memory-bound,实测 ~3000 GB/s @ H800(HBM 峰值约 89%);FP8 每 token 656 bytes(含 per-block scale + 对齐 padding;纯 latent 理论口径为 (512+64)×1=576github.com/deepseek-ai/FlashMLA
Vidur(MLSys'24)不支持 MLA,KV cache 按标准 MHA/GQA 假设arXiv:2405.05465

@tbl-gmkv-survey MLA KV 访存建模业界调研对比

业界共识:MLA decode 缓存与读取 latent(d_c+d_rope),不读完整 K/V;standard 与 absorb 模式 KV 读量相同、差异在解压激活;部署主流(DeepSeek 官方 / SGLang / vLLM)默认 absorb。分歧:是否建模 standard 的解压中间激活(多数工具不建)。本 spec 取 latent 读量主干 + 闭式 roofline,匹配项目"先相对后绝对"。

关键引用:

  • MLA: DeepSeek-V2, arXiv:2405.04434
  • MLA: DeepSeek-V3, arXiv:2412.19437
  • Roofline: Williams et al. 2009, CACM

附录 B:实现说明

记录实现与 spec 的偏差与落地决策(spec 冻结后唯一允许追加的内容)。

  • decode 判别用形状 QS < KS:不引入新 config 字段,复用现状机制。decode 配置 q_seq_len=1 < kv_seq_len,prefill QS==KS 不产 cache-read op。
  • cache-read 走 GDMA DDR_TO_LMEM,与 attention 并发(非强制串行):cache-read 发射为独立 GDMA 命令,cmd_id_dep 指向前驱 kv_b 投影的 TIU(读取在 latent 投影后开始)。GDMA 的 cmd_id_dep 仅能等 TIU,无法等另一条 GDMA,且 GDMA 支持多 outstanding,故 cache-read 与 fa2 计算并发(flash-decode KV 边搬边算),读量进 roofline 访存支。这满足目标 2 的相对正确性意图(HBM latent-KV 读量真实进入访存支、可被 roofline 计入)。验收 6 允许 overlap,测试以 op_start_ns/op_end_ns 区间相交断言并发、区间非零断言 latency 未被 duration-sum 折叠。
  • 未强制 attn 串行等 cache-read:图内已建 kv_cache_read → attn 数据边,但指令时序未强制 fa2 等 cache-read。若需真串行(使 decode 在标定后体现 HBM 搬运主导),可仿 DSA gather → fa2 的 SDMA + initial_sdma_dep 机制,把 cache-read 改走 SDMA 并把 sdma_id 传入紧随 fa2 的 initial_sdma_dep。留后续 plan(GDMA vs SDMA 的带宽域取舍随 B 阶段标定一并定)。
  • 绝对时长不可信:当前 placeholder 速率下,小 batch decode 的计算链 wall-clock 可能仍长于 cache-read 腿(compute-bound),故本期不断言 cache-read 主导 wall-clock——绝对速率属 B 阶段,本期只验相对正确性。

附录 C:接口契约

MLA KV 访存接口(语义契约,不含实现):

  • 输入:kv_lora_rank(必填)、qk_rope_head_dim(必填)、阶段标识、s_ctx(decode)、batchdtype
  • KV cache 字节:返回 @eq:gmkv-cache。
  • decode KV 读量:返回 @eq:gmkv-read,按 latent 维度,不含 num_heads。
  • 异常:kv_lora_rank / qk_rope_head_dim 缺失 → raise ValueError(含字段名 + 来源)。