gfx936 DCU上实现INT8 KV与INT8 MMAC Attention推理优化前言我们在一张gfx936 DCU上为Qwen3.5-27B做了一轮完整的INT8 KV与 INT8 MMAC Attention实现与优化从在线量化、分页存储一直做到低精度运算的INT8 QK、INT8 PV 。比赛环境项目配置加速卡单卡 gfx93664 GiB 显存软件栈DTK 26.04、Python 3.10、PyTorch 2.10.0推理框架赛事版 vLLM基于 v0.18.1 修改模型Qwen3.5-27B单卡运行服务方式OpenAI 兼容接口请求串行执行max_concurrency1整体思路首个Prefill Chunk使用成熟的高精度 Attention算子计算但使用融合的 KV 生产内核把 K/V 写成 INT8存储留给后续阶段复用。非首个Prefill Chunk把 Query也量化为 INT8让历史和当前块的 INT8 K/V 在同一个online softmax内核里完成 INT8 QK 和 INT8 PV。Decode 阶段使用 INT8 KV并以v_mmac_i32_16x16x32_i8重写 QK/PV 低精度计算按 256 token 分区。配套优化实现融合 RoPE、Q/K/V 动态量化、Scale 写入和分页 KV 写入等优化。最终效果初步版本在官方评测相对量化前的提交提高约 0.4 分精度扣分仍为 0实现了正向收益。但由于时间原因量化引入的很多额外开销尚且未作深度优化和消除。折腾了四五天比赛截止前几个小时才把正确的量化版本跑通且有正向收益 /(ㄒoㄒ)/~~本文先分析INT8 KV和INT8 MMAC Attention算子的理论收益然后分别介绍如何实现。1. INT8 KV 的理论性能收益来源结合DCU的MMAC指令讨论 INT8 KV Cache量化时很多人想到的收益仅仅是“显存容量“可以容纳更多的KV和组更大batch进行计算。但其实远非如此。INT8 KV量化还可以让元素位宽减半单次HBM读取指令的元素翻倍访存速度近似翻倍。同时结合使用INT8的MMAC指令相对于BF16的MMAC指令该指令算力峰值近似翻倍 计算速度翻倍。比赛中很多人认为INT8 KV没有收益也有不少人实现完成了KV Cache量化却没有取得端到端收益。这通常是因为只看到了INT8 KV所带来的”显存容量“这一点且恰好在比赛的单请求的特定测试负载下显存容量并非瓶颈自然并无法转化为端到端收益。但是对于后两点来说即便在单请求的负载下仍然是可以取得一些收益的却被很多人忽视了。下面结合DCU对这三个点展开具体分析。本文代码仓库https://github.com/sinpeyw/qwen3.5-vllm-dcu-optimization1.1 HBM容量收益不考虑张量并行时一层 Attention 的 KV 数据量为KV_bytes 2 × sequence_length × num_kv_heads × head_dim × bytes_per_elementQwen3.5-27B 是混合结构共 64 层其中 16 层使用全 Attention。全 Attention 部分采用 24 个 Query 头、4 个 KV 头head dimension 为 256。因此每个 token、每个全 Attention 层的原始 BF16 KV 数据是2 × 4 × 256 × 2 Byte 4096 Byte将 K/V 主数据改为 INT8 后这部分变为2 × 4 × 256 × 1 Byte 2048 Byte此外还需要为每个 token、每个 KV 头分别保存 K 和 V 的 FP32 Scale还需要2 × 4 × 4 Byte 32 Byte所以KV逻辑大小从 4096 Byte 降到 2080 Byte约为 BF16 的50.78%。为何比赛负载没有收益评测负载固定为 max_concurrency1单请求最长上下文为 32K。按 16 个全 Attention 层计算BF16 KV Cache 的最大容量需求约为 4096 Byte × 32768 × 16 2 GiB。单卡 DCU 显存约为 63.98 GiB实测模型权重加载占用 50.38 GiB仅扣除权重后理论上仍剩约 13.60 GiB。即使还需为计算图、激活值和算子工作区保留显存KV Cache 容量也足以容纳单个 32K 请求。因此在本次比赛负载下显存容量并非瓶颈INT8 KV 带来的存储容量缩减无法直接转化为吞吐收益。何种负载下有收益负载允许组batch且显存容量限制了batch的大小prefix cache命中率高显存可以保留更多的历史KV来复用显存容量是瓶颈。1.2 HBM带宽收益按前面的布局每个历史 token、每个全 Attention 层需要读取的 BF16 K/V 主数据为 4096 Byte。改成 INT8 后K/V 主数据与 FP32 Scale 合计为 2080 Byte。若历史长度为L只考虑这部分逻辑负载BF16 KV traffic 4096 × L Byte INT8 KV traffic 2080 × L Byte traffic ratio 50.78%HBM带宽不变相同时间读取元素个数提升4096 / 2080 ≈ 1.97x对于Prefill来算Prefill Attention是计算瓶颈提升KV读取速度整体收益不明显。Prefill如果分chunk之后非首个Prefill chunk同样需要读取已有 KV理论也能获得一部分 HBM 收益但是可能仍然是计算瓶颈收益不大。对于Decode来说 每一步只产生一个新 Query却要读取此前所有 token 的 K/V因此Attention瓶颈在KV的HBM访存且上下文越长访存瓶颈越加剧。INT8 KV将读取的数据量降低一半提升读取速度理论上有收益。但 1.97x 只是 K/V 有效负载的带宽上限不是 Decode Attention 的预期加速比。实际路径还需要读取 block table 和 Scale维护 online softmax 状态并执行分页寻址、分区归并和输出写回这些流量与计算不会随 K/V 位宽一起减半。只有 Attention 内核直接读取分页 INT8 K/V并在 MMAC 累加结果和 online softmax 数据流中融合应用 Scale减少的 K/V 字节数才能真正进入时延账如果先反量化并写出一份完整 BF16 K/V中间张量的额外写入和再次读取会重新消耗 HBM 带宽。第 3 节将具体介绍 INT8 KV 的直接消费路径1.3 Tensor Core 峰值收益DCU 的计算单元不仅包含普通标量和向量运算通路还提供面向矩阵乘加的专用矩阵计算单元,称为 Tensor Core在 gfx936 的指令层它通过 MMAC指令体现。MMAC 不是让单个线程独立计算一个小矩阵而是由一个 wave64 协同提供输入 fragment并把一个矩阵输出块的累加结果分布在各个 lane 的 VGPR 中。这样可以用较少的指令完成高密度点积也是我们重写 QK 和 PV 的硬件基础。BF16 基线路径涉及的指令是v_mmac_f32_16x16x16_bf16。它以 BF16 作为输入由一个 wave 计算16×16×16的矩阵块并使用 FP32 累加前两个16表示输出块的 M、N 维最后一个16表示单条指令覆盖的 K 维。INT8 路径使用v_mmac_i32_16x16x32_i8。它同样生成16×16输出块但输入改为 INT8、累加器改为 INT32单条指令覆盖的 K 维从 16 增加到 32。也就是说在相同输出块和相近指令发射条件下INT8 MMAC 一次可以完成两倍的乘加元素数因此 gfx936 的 INT8 MMAC 理论峰值约为 BF16 MMAC 的两倍。后续 Scale 恢复和浮点 softmax 则在矩阵累加之后完成。QK 和 PV 是Attention主要的矩阵计算。若 Q、K 和 V 已完成量化两次乘法可以写成Score ≈ MMAC_INT8(Q_int8, K_int8^T) × sQ × sK / sqrt(d) Output ≈ MMAC_INT8(P_int8, V_int8) × sP第二个式子是简写。实际实现先把每个 token 的sV融入 softmax 权重再对P × sV分块量化因此最终恢复的是概率块的 Scale不能在整个 PV 结束后统一乘一个 V Scale。对于 head dimension 256INT8 QK 的 K 维需要 8 个 MMAC stepBF16 路径需要 16 个 stepPV 也采用相同的低精度矩阵核心。在 Prefill Attention中QK/PV 计算占主导INT8 存在接近两倍峰值算力的理论空间。Decode 也使用同样的 INT8 QK/PV但单请求 Decode Attention更受历史 KV 读取限制Tensor Core 峰值通常不是它的第一收益来源。同样峰值算力比不等于 Attention 内核的实际加速比。MMAC 的 K-step 减半只加速 QK 和 PV 中的矩阵乘加部分RoPE、online softmax、分页寻址和输出转换原本就存在也不会因此变快。INT8 路线还会额外引入 absmax 归约、Scale 计算、除法、舍入以及 PV 概率再量化。如果这些新增操作独立执行或者产生额外的全局内存中间结果其成本可能超过 INT8 MMAC 节省的计算时间。在后面第 2章将介绍如何融合KV量化生产过程第 3章则介绍如何把 Scale 应用、softmax和 INT8 QK/PV 组织在同一条消费链路中。1.4 为什么不少 INT8 KV Cache 实现没有收益只把 KV Cache 的存储类型改成 INT8并不等于 Attention 已经使用 INT8 计算。一条容易实现但很难加速的路径是BF16 K/V → 独立量化 kernel → INT8 Cache → 完整反量化为 BF16 → 原有 BF16 Attention这条路径可能减少持久缓存容量却增加了 BF16 读取、INT8 写入、Scale 读写、反量化和额外 kernel launch。更关键的是QK 和 PV 仍由 BF16 矩阵指令完成gfx936 的 INT8 MMAC 峰值没有真正被利用。在单请求场景中新增开销很容易超过节省的 KV 读取时间。能够产生性能收益的数据流应当更接近RoPE absmax 量化 INT8 KV 写入 → Attention 直接读取分页 INT8 K/V → INT8 QK MMAC → online softmax 与 Scale 恢复 → 概率分块量化 → INT8 PV MMAC这要求重构 Attention 内核而不只是替换 Cache dtype。Prefill Attention 的 QK/PV 更偏计算受限INT8 MMAC 的理论峰值约为 BF16 MMAC 的两倍因此重点是让两次矩阵乘法都原生进入 INT8 指令。Decode Attention 更偏显存带宽受限重点是直接读取 INT8 K/V将历史主数据流量约减半。两条路径的收益来源不同但都要求避免完整反量化中间张量。我们最终围绕这两类成本重构了完整数据流KV 不再先写入 BF16 Cache 后二次量化而是在 producer 中融合 RoPE、absmax、动态量化、Scale 写入和分页 INT8 KV 写入Query 只量化一次并由后续分段复用。消费端不生成完整 BF16 K/VQK 将 INT32 点积结果与 sQ×sK 融合恢复PV 则先把每个 token 的 sV 融入 softmax 权重再对新的权重块进行量化并执行 INT8 MMAC。这样INT8 数据从 Cache 写入一直保持到 QK/PV 的矩阵计算阶段避免了完整反量化和额外中间张量。下面第2章将展开这条数据流的INT8 KV生产端第3章介绍 Decode 和带历史KV的 Prefill Chunk如何直接消费这些 INT8 数据。2. INT8 KV 如何产生INT8 KV 的生产位置和方式会直接决定它是否有性能价值。首先应该否定的一种朴素做法是按原路径写出 BF16 KV再启动一个独立 kernel 扫描缓存并转成 INT8。因为这样会多读一遍 BF16、多写一遍 INT8还会增加临时空间和 kernel launch性能退化无法接收。我们的核心思路是把量化并入原本就要执行的 KV 生产阶段。2.1 动态量化粒度要生成什么样的数据我们采用对称 INT8、per-token、per-head Scale。对一个长度为 D 的向量xamax max(abs(x[i])) scale amax / 127 q[i] clamp(round(x[i] / scale), -127, 127)反量化关系为x[i] ≈ q[i] × scale量化范围使用[-127, 127]以保持正负对称。amax0时显式给出安全 Scale 或全零输出避免除零。per-token、per-head 并不是理论上误差最小的粒度和最优方法。很多文章指出如KIVI K 中常有稳定的通道离群值K 更适合 per-channel/groupV 更适合 per-token并提出采用非统一的量化方法。这里选择统一规则一方面是因为简单它在 gfx936 上具有固定的归约范围、简单的 Scale 寻址和较低的运行时开销精度风险再通过下游任务验证约束。另外是因为作者时间有限尚且未来得及探索复杂方法/(ㄒoㄒ)/~~。需要注意“反量化关系”只是定义数值近似关系。我们的最终实现中不会真的生成完整 BF16 K/V这一点后文会继续解释。2.2 融合 RoPE、量化与分页写入什么时候、怎样生成Q/K/V 投影完成后Q/K 需要经过 RoPEK/V 需要写入分页 Cache。本文将这段数据流称为 KV producer。为了避免先写 BF16 KV、再启动独立量化 kernel最终实现把动态量化直接融合进 producer。最终 KV 生产内核在一次 HIP kernel 中完成读取 Q/K/V对 Q/K 应用 RoPE或消费已经旋转后的 Q/K在 wave 内归约 Q/K/V 的 absmax计算 Scale 并量化将 K/V 写入分页 INT8 Cache写入 K/V Scale在纯 INT8 Attention 路径中跳过无用的 BF16 Q/K 回写。内核中的主数据流可以简化为float4 qload4(query,token,q_head);float4 kload4(key,token,kv_head);float4 vload4(value,token,kv_head);qapply_rope(q,position);kapply_rope(k,position);if(quantize_query)wave_quantize_store(q,query_int8,q_scale);wave_quantize_store(k,paged_key_cache[slot],k_scale[slot]);wave_quantize_store(v,paged_value_cache[slot],v_scale[slot]);首个Prefill Chunk只生成 INT8 K/V当前 Attention仍走高精度路径Query保留在高精度数据流中带历史 Prefill Chunk和 Decode则同时量化 Query。Query只量化一次随后可被多个历史分区split-K复用KV 的分页槽位映射也只计算一次。融合的价值不只是少启动一个 kernel更重要的是避免把中间 BF16 数据重新写回显存再读出。同一 producer需要同时覆盖单 token Decode和数千 token Prefill。最终实现按 token 数选择最优并行配置1、2、超过 2 个 token分别使用 1、2、8 个 wave避免小形状承担过多同步开销也避免大形状并行度不足。2.3 物理布局与显存管理量化数据如何排列存储量化数据产生后还需要同时解决两个问题怎样排列才能被 QK/PV 高效读取以及怎样接入 vLLM 原有的分页缓存和显存规划。前者决定 Attention 内核的实际访存效率后者决定服务能否在固定显存预算下稳定启动。QK 和 PV 对数据读取方向的要求不同因此 K 和 V 没有强行使用相同布局。K 按 16 个 head-dimension 元素分块K cache: [blocks, 4, 16, block_size, 16]这样QK 中负责 token 方向的 lane 可以为固定维度组织合并读取。V 保持 token 方向连续V cache: [blocks, 4, 256, block_size]PV 中一个 lane 可以连续取得多个 token 在同一输出维度上的 V。两种布局都围绕 16 字节搬运设计避免把 INT8 的带宽优势消耗在大量标量 byte load 上。Scale 独立存储为K/V scale: [blocks, block_size, 4], FP32需要注意的是由于前文已经分析INT8 KV容量并不能在比赛负载中带来收益因此为了简单和兼容性起见作者在初版代码并未为INT8 量化重构KV页的结构。仍沿用 BF16 大小的物理页面只在页面前半部分存放紧凑 INT8 数据Attention 内核只读取这部分有效数据。此时能够取得读取速度收益但页面的物理分配没有减半。KV 数据区仍占 BF16 页面分配的 100%再加约 0.78% 的 Scale每个逻辑 token 的持久分配约为 BF16 的100.78%。代码中的为 K/V Scale 各创建[num_blocks, block_size, 4]的 FP32 tensor用固定显存预算主动扣除 Scale空间而不是依赖启动参数预留。如果测试负载有组batch或者有prefix cache可以进一步考虑为INT8量化专门设计KV 页结构。3. INT8 KV 如何被消费INT8 MMAC指令将 KV 写成 INT8 只完成了一半工作。如果消费端先把整份缓存恢复成 BF16再调用普通 Attention省下的存储会被反量化和中间张量开销抵消。作者的核心思路是使用DCU的低精度INT8 MMAC相关指令改造内核Attention 内核直接从分页缓存加载 INT8 K/V fragment并将其送入 MMAC整个过程中不生成完整 BF16 K/V 中间张量。这样既避免了反量化带来的开销也能利用INT8 MMAC指令的翻倍算力峰值。3.1 首个Prefill Chunk高精度计算融合写入 INT8 KV首个 Prefill 块没有历史KV缓存可读。最终实现继续调用成熟的高精度 Attention只让融合 producer 把当前 K/V 写成 INT8为后续 Prefill 和 Decode 复用。这样既保留首块高精度内核的调度优势也没有再运行独立的量化 kernel。3.2 非首个Prefill Chunk在一次 online softmax 中消费分块 Prefill 已经积累至少 4096 token KV后producer 同时生成 INT8 Query并由gfx936_int8_prefix_attention消费历史KV与当前块的 INT8 K/V。Q、历史 K/V 和当前 K/V 在同一个 Attention 内完成 INT8 QK、online softmax 和 INT8 PV。注意不能让历史 INT8 KV 和当前 BF16 K/V 分别计算两次 Attention再依靠两个 log-sum-exp 状态合并。数学上可以完成合并但实现上会增加一次 Attention 数据流、状态写回和归并使本来有限的 INT8 收益被额外开销吃掉。最终路径因此坚持在一个 online softmax 生命周期中处理完整上下文。3.3 Decode直接读取分页 INT8 KVpaged_attention_int8_kv接收分页 INT8 K/V、逐 token Scale、INT8 Query 和 Query Scale。block table 只负责定位物理页K/V fragment 从页面进入寄存器或 LDS 后直接送入 MMAC中间不生成完整 BF16 K/V tensor。其计算过程可以概括为定位分页 K/V → INT8 QK MMAC → Scale 恢复与 online softmax → 概率分块量化 → INT8 PV MMAC → 分区归并并输出 BF16QK 和 PV 的关键不是在 MMAC 前生成完整 BF16 K/V而是在局部累加结果上恢复 Scale。一个简化的 32-token fragment 计算如下int32x4 qkmmac_int8(q_int8,k_int8);floatscorefloat(qk)*q_scale*k_scale[token]*softmax_scale;floatponline_softmax_update(score);floatp_with_v_scalep*v_scale[token];floatp_scaleblock_absmax(p_with_v_scale)/127.0f;int8x8 p_int8quantize(p_with_v_scale,p_scale);int32x4 pvmmac_int8(p_int8,v_int8);outputfloat(pv)*p_scale;这种路径同时使用了两类收益历史 K/V 主数据读取量降低QK 和 PV 也直接进入v_mmac_i32_16x16x32_i8。按 256 token 分区后各工作组独立处理一段历史上下文再合并 softmax 状态和输出。最终的路由可以概括为Q/K/V(BF16) ├─ 首个Prefill Chunk │ 高精度 Attention │ 融合 RoPE、动态量化和 INT8 K/V 写入 ├─ 非首个Prefill Chunk │ INT8 Q 历史/当前 INT8 K/V │ 单内核 INT8 QK、online softmax、INT8 PV └─ Decode 分页 INT8 K/V INT8 QK、online softmax、INT8 PV4. BW1000 DCU 实测结果局部 MMAC 更快不代表服务一定同比加速。我们把测试边界分为三级单个算子、完整 Attention 层数据流以及真实服务端到端。下文的加速比均定义为“对照耗时 / 候选耗时”不同表格的对照边界不相同。4.1 算子级收益对比先看 INT8 路线中三个可以独立计时的核心算子。算子边界对照INT8 候选实测结果QK 内层矩阵块BF16 QKINT8 QK MMAC长上下文约1.55x-1.63x256-token 小块接近持平PV 内层计算BF16 PVINT8 PV MMAC4K/8K/16K 为1.1049x/1.0979x/1.2653xKV producer未消除重复写回的生产路径融合 RoPE、量化和分页写入32.747 us - 12.122 us即2.7016xQK 和 PV 的结果说明两次低精度矩阵乘法本身都有收益producer 的结果则说明量化开销能否被融合掉同样关键。producer 的 workgroup 形状也会改变结果。一个 wave 是 gfx936 上锁步执行的 64 个线程下表固定以 BF16 producer 为对照只改变 INT8 producer 的 workgroup wave 数。旧自动策略在大 Prefill 块上选择 4 waves优化后改为 8 waves。token 数旧 4-wave 配置相对控制组优化后 8-wave 配置相对控制组22420.7455x1.1269x40960.7351x1.1155x小 token 下各配置只有零点几微秒差异真正有信息量的是数千 token 的 Prefill 块。旧 4-wave 路径明显回退改为 8 waves 后才恢复正收益。最终 producer 按 token 数选择1/2/8个 wave分别覆盖 1、2、超过 2 个 token 的形状。4.2 Attention 层收益对比算子成立后还要把 RoPE、动态量化、KV 写入、QK、online softmax、PV 和输出放进更完整的计时边界。这里涉及两个容易混淆的概念。第一“完整生命周期”不仅包含 Attention还包含生成它所需数据的前置工作。BF16 对照执行 RoPE、写入 BF16 K/V再调用 BF16 AttentionINT8 候选执行 RoPE、Q/K/V 动态量化、写入 INT8 K/V 和 Scale再调用使用 INT8 QK/PV 的 Attention。第二INT8 Attention 候选本身还经历了一次并行组织调优。早期内核中一个 workgroup 处理 64 个 Query 行改进后由 8 个 wave 协同处理 128 个 Query 行使同一份 K/V tile 可以被更多 Query 复用。此前代码和测试中把两者简称为QTile64和QTile128本文后面直接称为“64-query-row 内核”和“128-query-row 内核”。二者都使用 INT8 QK/PV这组比较不涉及 BF16 对照。比较层级对照候选计时范围加速Attention 完整生命周期RoPE BF16 K/V 写入 BF16 AttentionRoPE 动态量化 INT8 K/V、Scale 写入 128-query-row INT8 Attention数据生产与 Attention 消费1.0613xINT8 Attention 内核调优64-query-row INT8 Attention128-query-row INT8 AttentionQK、online softmax、PV 和输出1.3158x真正回答“从 BF16 改成 INT8 是否仍然更快”的是第一行加入 absmax、Scale、量化和缓存写入后完整生命周期仍有1.0613x的收益。第二行的1.3158x只说明 128-query-row 内核优于旧的 64-query-row INT8 内核不能把它当作 INT8 相对 BF16 的加速比。在Prefill中通常分为多个Chunk执行并非一开始就使用INT8 Attention最好。为了决定从哪个Chunk开始启用 INT8我们固定采用“BF16 完整生命周期”为对照将各历史长度下的“全 INT8 完整生命周期”作为候选历史上下文 当前块对照候选加速BF16 耗时 / INT8 耗时0 4KBF16 数据生产 BF16 AttentionINT8 数据生产 INT8 Attention0.9140x4K 4KBF16 数据生产 BF16 AttentionINT8 数据生产 INT8 Attention1.0298x8K 4KBF16 数据生产 BF16 AttentionINT8 数据生产 INT8 Attention1.0801x12K 2242BF16 数据生产 BF16 AttentionINT8 数据生产 INT8 Attention1.1168xPrefill首块的0.9140x表明在线量化成本尚未被覆盖历史越长INT8 QK/PV 和 KV 读取收益越明显。因此最终路由没有全局启用 INT8而是让首块继续使用高精度 Attention同时写入 INT8 K/V 供后续复用历史达到 4K 后再启用完整 INT8 Attention。将这些已测形状按最终路由组合得到前面的1.0705x。排查 Decode 时还额外测试了一组用于batch负载的数据。这里的 BF16 对照同样包含 RoPE、BF16 KV 写入和 BF16 AttentionINT8 候选包含融合动态量化、INT8 KV 写入以及 INT8 QK/PV Attention。历史长度合成 batchBF16 生命周期INT8 生命周期加速最大绝对误差8K2425.504 us100.256 us4.2442x0.00158716K2432.240 us160.384 us2.6950x0.0008548K10472.224 us340.960 us1.3850x0.00134316K10837.903 us617.728 us1.3564x0.000977这些数据证明了合成 batch 形状下的 INT8 KV Attention 层生命周期具有收益而且收益并不随 batch 单调增加。但是初赛吞吐脚本固定max_concurrency1两条或十条请求只是串行样本数不会形成服务 batch。4.3 服务端到端收益对比端到端测试统一比较两条服务路径。BF16 对照保留相同的模型、推理框架和非量化优化K/V 存储与 Attention 计算均使用 BF16INT8 候选在此基础上启用最终集成数据流首个 Prefill Chunk 使用高精度 Attention 并写入 INT8 K/V后续 Prefill Chunk 和 Decode 直接消费 INT8 K/V以 INT8 MMAC 完成 QK/PV同时启用融合 RoPE、动态量化和分页写入。需要注意的是一次单请求 hipprof 中Prefill 和 Decode Attention 分别只占所记录 HIP 内核时间的7.556%和3.918%将包含量化与缓存写入成本的完整路径收益代入 Amdahl 定律可兑现到完整请求的理想收益大约只有0.4%-0.8%因此端到端上限本来就不高。下面只保留能够说明最终路线收益的测试。负百分比表示时延下降。验证范围BF16 对照最终 INT8 候选结果8K-16K若干串行请求输出吞吐7.991030 tok/s平均 TTFT3784.290 ms平均 TPOT47.755 ms输出吞吐8.033833 tok/s平均 TTFT3773.134 ms平均 TPOT47.292 ms两组输出长度持平吞吐提高0.536%平均 TTFT 降低0.295%平均 TPOT 降低0.970%官方平台提交保留相同非量化优化、尚未启用本文 INT8 KV 数据流的提交版本启用完整 INT8 KV 写入与消费路径的最终版本最终得分提高约0.4分精度扣分保持为0本地完整精度测试共 109 条。INT8 候选在 HotpotQA、GovReport、Retrieval 和 Aggregation 上分别得到77.96/32.97/100/100BF16 对照为77.96/32.83/100/100没有观察到精度下降。官方平台测量的提分足以确认整条 INT8 数据流取得了小幅端到端正收益。5. 踩坑经验5.1 只压缩存储没有使用原生 INT8 计算早期路径从 INT8 Cache 读取 K在寄存器中转成 BF16再调用 BF16 MMAC。真实 Qwen tile 上只有 BF16 路径的0.71x-1.00xK 的读取量虽然减少但转换和 Scale 开销抵消了收益QK 也没有使用 INT8 MMAC。INT8 KV 要取得性能收益消费端必须直接使用低精度数据不能在 Attention 前恢复完整 BF16 K/V。5.2 在错误的阶段强制启用 INT8Prefill阶段曾被强制改成“先写 INT8 页面再从页面读取做全 INT8 Attention”结果输出吞吐下降26.954%平均 TTFT 增加约59.2%平均 TPOT 增加约2.0%。首块没有历史 KV 的带宽收益却要承担完整在线量化和分页读取成本。另一条路径让历史 INT8 KV 与当前 BF16 K/V 分别计算两次 Attention再合并两个 LSE 状态完整生命周期为39.151 ms对13.332 ms只有0.3405x。最终方案保留首块高精度 Attention并让带历史的当前块与历史 KV 在同一个 online softmax 状态中完成计算。5.3 局部内核已经加速生产路由却没有生效一次合成单序列生命周期测试在 8K/16K 下达到5.6363x/3.7543x随后同容器服务测试却回退2.034%。检查运行日志后发现Qwen3.5 在 RoPE 前还有 Q/K RMSNorm原有图匹配模式没有命中真实调用点测得的融合 producer 根本没有进入服务路径。后来通过真实调用点接入、Meta/FakeTensor 支持、编译缓存身份隔离和运行时路由日志才确认候选真正生效。5.4 跑得很快也可能只是少算了数据INT8 PV 的早期实现按连续0-31、32-63token 计算 Scale却没有对齐 MMAC fragment 的真实 token 归属。错误版本把正常的[95,12]输出变成[1024,1024]表面吞吐从约7.9968升到19.2006 tok/s。这不是优化而是错误概率分组改变了生成和停止行为。类似地8 Byte V load 只读取了 lane 所需数据的一半partition 512 也曾越过正确 fragment 映射。低精度内核必须同时验证数学参考、硬件 fragment、跨页地址和输出文本不能只检查 kernel 是否完成以及结果是否为有限数。5.5 输出长度会掩盖真实执行性能一次两请求测试表面吞吐提高2.4196%但候选多生成了 5 个 token整体执行时间反而增加按控制输出长度和候选 TTFT/TPOT 粗略归一化后约为-0.40%。相反前面的十请求测试虽然 TPOT 改善约1.24%却因少生成 43 个 token 而得到负的原始吞吐。5.6 旁路显存必须进入统一预算INT8 K/V 主数据变小并不意味着可以忽略 Scale、Query 工作区和分区归并空间。早期旁路分配没有完整进入 KV planner平台曾在服务初始化阶段因缺少少量连续显存而 OOM。最终实现让 planner 显式计入每 token、每层 32 Byte 的 K/V Scale并复用 Query 和 Decode workspace同时保留必要的显存余量。后续文章本文介绍完整 INT8 KV Attention 方案。后续第二篇《gfx936 DCU上实现INT8 QK MMAC分页访存、Fragment映射与GQA适配》和第三篇《gfx936 DCU上实现INT8 PV MMACV Scale融合、概率量化与Fragment分组》将分别展开 QK 与 PV 的内核实现。