<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>橙子派的个人博客</title><description>C++/CUDA学习分享</description><link>https://chengzipai.xyz/</link><templateTheme>chengzipai</templateTheme><templateThemeVersion>6.13.3</templateThemeVersion><templateThemeUrl>https://github.com/CuteLeaf/chengzipai</templateThemeUrl><lastBuildDate>2026年7月15日 21:03:00</lastBuildDate><item><title>CUDA FlashAttention：从在线 Softmax 到长序列 IO 极限</title><link>https://chengzipai.xyz/posts/cuda-flash-attention-io-aware/</link><guid isPermaLink="true">https://chengzipai.xyz/posts/cuda-flash-attention-io-aware/</guid><description>以大模型因果 Attention 为背景，从二次中间矩阵、在线 Softmax、分层 tile 与 warp/MMA 数据流出发，实现并验证 FlashAttention 的 CUDA 优化。</description><pubDate>Wed, 15 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;大模型把上下文从 2K 推到 8K、32K 以后，Attention 的问题不再只是“两个 GEMM 很贵”。标准实现会把 &lt;span&gt;&lt;span&gt;QKTQK^T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Q&lt;/span&gt;&lt;span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 写回显存，经过 mask 和 Softmax 后再读回来与 &lt;span&gt;&lt;span&gt;VV&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;V&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 相乘。计算量仍是二次的，真正先让实现失去扩展性的往往是这个 &lt;span&gt;&lt;span&gt;N×NN\times N&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 中间矩阵。&lt;/p&gt;
&lt;p&gt;本文只讨论精确的 dense causal attention，不用稀疏近似换速度。目标是从一个可核验的 CUDA 数据流出发，解释 FlashAttention 为什么有效、如何分层到 CTA/warp/MMA、在什么 shape 下应回退，以及生产实现和教学骨架之间还差哪些工作。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;1. 问题、shape 与性能指标&lt;a href=&quot;#1-问题shape-与性能指标&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;设&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Q,K,V∈RB×H×N×D,Q,K,V\in\mathbb{R}^{B\times H\times N\times D},&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Q&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;V&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;大模型中的 scaled dot-product attention 为&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;O=softmax⁡(QKTD+M)V,O=\operatorname{softmax}\left(\frac{QK^T}{\sqrt D}+M\right)V,&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;softmax&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Q&lt;/span&gt;&lt;span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;V&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;其中 causal mask &lt;span&gt;&lt;span&gt;Mij=0M_{ij}=0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ij&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 当 &lt;span&gt;&lt;span&gt;j≤ij\le i&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;j&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≤&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，否则为 &lt;span&gt;&lt;span&gt;−∞-\infty&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;∞&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。本文实测使用 &lt;span&gt;&lt;span&gt;B=1,H=32,D=128B=1,H=32,D=128&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;128&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，这对应常见大模型的 head geometry；&lt;span&gt;&lt;span&gt;NN&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 从 512 扩展到 8192。&lt;/p&gt;&lt;p&gt;非 causal 前向的两个矩阵乘法约需 &lt;span&gt;&lt;span&gt;4BHN2D4BHN^2D&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; FLOP。causal kernel 若能跳过上三角 tile，实际有效计算约为&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Fcausal≈2BHN2D.F_{\mathrm{causal}}\approx 2BHN^2D.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;F&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;causal&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;性能不能只看 TFLOP/s，还要同时记录：端到端 kernel 延迟、输入之外的峰值显存、长序列是否 OOM，以及 FP16 输出相对 FP32 Softmax 参考路径的误差。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. 精度语义：低精度乘法不等于低精度 Softmax&lt;a href=&quot;#2-精度语义低精度乘法不等于低精度-softmax&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;本文的 &lt;span&gt;&lt;span&gt;Q,K,VQ,K,V&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Q&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;V&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 和输出为 FP16，点积与输出 accumulator 使用 FP32。在线 Softmax 的行最大值 &lt;span&gt;&lt;span&gt;mm&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;、指数和 &lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 也必须是 FP32：如果 &lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 用 FP16，长行会更早丢失小概率项；如果不减行最大值，&lt;code&gt;exp&lt;/code&gt; 会溢出。&lt;/p&gt;&lt;p&gt;BF16 有更大的指数范围，但尾数更短，仍应保留 FP32 的 &lt;span&gt;&lt;span&gt;m/l/Om/l/O&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; accumulator。TF32 是 FP32 GEMM 的硬件折中，不是本文 FP16 大模型路径的输入格式。FP8/INT8 可以降低 Q/K/V 流量，但需要 per-tensor 或 per-block scale，且 Softmax 状态仍应提升到 FP32。FP64 吞吐和容量代价都不适合作为大模型默认路径，只用于高精度离线校验。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. 朴素实现为何先撞上显存&lt;a href=&quot;#3-朴素实现为何先撞上显存&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;朴素路径是三个独立阶段：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;GEMM 写出 &lt;span&gt;&lt;span&gt;S=QKT/DS=QK^T/\sqrt D&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;S&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Q&lt;/span&gt;&lt;span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;mask 与 Softmax 读写 &lt;span&gt;&lt;span&gt;SS&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;GEMM 读取 &lt;span&gt;&lt;span&gt;P=softmax⁡(S)P=\operatorname{softmax}(S)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;softmax&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;S&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 和 &lt;span&gt;&lt;span&gt;VV&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;V&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，写出 &lt;span&gt;&lt;span&gt;OO&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;即使只把 &lt;span&gt;&lt;span&gt;SS&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 保存成 FP16，中间矩阵也占&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;MS=2BHN2 bytes.M_S=2BHN^2\ \text{bytes}.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;bytes&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;在 &lt;span&gt;&lt;span&gt;B=1,H=32,N=8192B=1,H=32,N=8192&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;8192&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 时，仅一份 &lt;span&gt;&lt;span&gt;SS&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 就是 4096 MiB。安全 Softmax 还可能生成 mask、FP32 临时量或额外输出，因此真实峰值高于这个下界。OneFlow 对 Softmax 的拆解给出了同样的工程信号：&lt;code&gt;exp&lt;/code&gt;、reduce 和 broadcast 分成多个 kernel 会反复读写整行，优化应先减少全局访存，而不是先抠一条指令。&lt;/p&gt;&lt;p&gt;从 roofline 看，两个大 GEMM 本身有较高算术强度，但 GEMM 之间的 &lt;span&gt;&lt;span&gt;N2N^2&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 物化流量没有产生新的模型信息。FlashAttention 不减少 dense attention 的渐近计算量，而是利用片上 SRAM 重排计算，消掉这部分 HBM 往返。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. 在线 Softmax：不保存整行仍保持精确&lt;a href=&quot;#4-在线-softmax不保存整行仍保持精确&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;把一行 score 分成 tile。处理第 &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 个 tile 前保存运行状态：最大值 &lt;span&gt;&lt;span&gt;m(t−1)m^{(t-1)}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;、指数和 &lt;span&gt;&lt;span&gt;l(t−1)l^{(t-1)}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;、未归一化输出向量 &lt;span&gt;&lt;span&gt;o(t−1)o^{(t-1)}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。新 tile 的局部最大值和局部指数和为&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;m~=max⁡jsj,l~=∑jesj−m~.\tilde m=\max_j s_j,\qquad
\tilde l=\sum_j e^{s_j-\tilde m}.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;~&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;j&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;max&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;j&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;~&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;j&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;∑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;j&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;~&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;合并时先更新最大值&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;m(t)=max⁡(m(t−1),m~),m^{(t)}=\max\left(m^{(t-1)},\tilde m\right),&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;~&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;再重标定旧状态：&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;α=em(t−1)−m(t),β=em~−m(t),\alpha=e^{m^{(t-1)}-m^{(t)}},\qquad
\beta=e^{\tilde m-m^{(t)}},&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;β&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;~&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;l(t)=αl(t−1)+βl~,l^{(t)}=\alpha l^{(t-1)}+\beta\tilde l,&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;β&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;~&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;o(t)=αo(t−1)+∑jesj−m(t)vj.o^{(t)}=\alpha o^{(t-1)}+
\sum_j e^{s_j-m^{(t)}}v_j.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;j&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;∑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;j&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;j&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;最后输出 &lt;span&gt;&lt;span&gt;O=o(T)/l(T)O=o^{(T)}/l^{(T)}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。这是代数重排，不是近似；只要每个 tile 都进入合并，结果与整行安全 Softmax 相同，差异来自浮点加法顺序。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;FlashAttention online softmax tile flow&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;760&quot; src=&quot;/_astro/online-softmax-tile-flow.Mfv_pyST_1Vvu8P.svg&quot; srcset=&quot;/_astro/online-softmax-tile-flow.Mfv_pyST_Z8FbRi.svg 640w, /_astro/online-softmax-tile-flow.Mfv_pyST_Z1Kwbz0.svg 750w, /_astro/online-softmax-tile-flow.Mfv_pyST_GFRxK.svg 828w, /_astro/online-softmax-tile-flow.Mfv_pyST_Z1Dgcu0.svg 1080w, /_astro/online-softmax-tile-flow.Mfv_pyST_1Vvu8P.svg 1280w&quot; /&gt;&lt;figcaption&gt;FlashAttention online softmax tile flow&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;图 1：Q tile 常驻寄存器，K/V tile 通过双缓冲 shared memory 流过；每轮只保留 FP32 的 &lt;span&gt;&lt;span&gt;m/l/Om/l/O&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 状态，不把 score tile 写回 HBM。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. 从能跑到高吞吐的 CUDA 数据流&lt;a href=&quot;#5-从能跑到高吞吐的-cuda-数据流&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;5.1 CTA tile：让 K/V 被多个 query 复用&lt;a href=&quot;#51-cta-tile让-kv-被多个-query-复用&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;一个 CTA 负责 &lt;span&gt;&lt;span&gt;BrB_r&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;r&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 行 query。&lt;span&gt;&lt;span&gt;QiQ_i&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Q&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 只加载一次并留在寄存器或 shared memory；K/V 按 &lt;span&gt;&lt;span&gt;BcB_c&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 个 token 分块。单个 K/V tile 从 HBM 读取一次，却服务 &lt;span&gt;&lt;span&gt;BrB_r&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;r&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 行 query，避免“一行 query 一个 block”重复读取整个上下文。&lt;/p&gt;&lt;p&gt;shared memory 预算近似为&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Msmem≈2BcD s+MQ+MP,M_{\mathrm{smem}}\approx 2B_cD\,s+M_Q+M_P,&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;smem&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Q&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;其中 &lt;span&gt;&lt;span&gt;s=2s=2&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; bytes 对应 FP16。增大 &lt;span&gt;&lt;span&gt;BcB_c&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 提高复用，却会增加 shared memory 和寄存器占用，减少每个 SM 的并发 CTA。不存在对所有 &lt;span&gt;&lt;span&gt;D,ND,N&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 都最优的 tile。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.2 warp/MMA：把乘加留给 Tensor Core&lt;a href=&quot;#52-warpmma把乘加留给-tensor-core&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;span&gt;&lt;span&gt;QKTQK^T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Q&lt;/span&gt;&lt;span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 和 &lt;span&gt;&lt;span&gt;PVPV&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;V&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 应映射到 &lt;code&gt;mma.sync&lt;/code&gt; 支持的 fragment，而不是逐元素 FP32 FMA。warp 先协作装载 FP16 fragment，Tensor Core 以 FP32 累加；Softmax 的 max/sum 则使用 warp shuffle 和少量 shared memory 做跨 warp 合并。&lt;/p&gt;&lt;p&gt;FlashAttention-2 的关键不是换一个 Softmax 公式，而是减少非矩阵乘 FLOP、在单 head 内沿 query 方向增加 CTA 并行，并调整 warp 分工以减少 shared-memory 通信。对 &lt;span&gt;&lt;span&gt;B×HB\times H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 很小而 &lt;span&gt;&lt;span&gt;NN&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 很长的情况，这种并行度尤其重要。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.3 K 维流水与 bank conflict&lt;a href=&quot;#53-k-维流水与-bank-conflict&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Ampere 的 &lt;code&gt;cp.async&lt;/code&gt; 可以把 global-to-shared copy 与当前 tile 的 MMA 重叠：stage 0 计算时预取 stage 1，随后交换 buffer。K/V shared layout 要同时满足 128-bit 合并访存和 MMA fragment 的访问方式；简单的二维行主序可能让多个 lane 命中同一 bank。常见处理是 padding 或 swizzle，而不是盲目增大 shared memory。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.4 向量化、对齐与尾部&lt;a href=&quot;#54-向量化对齐与尾部&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;head dim 为 64/128 且首地址 16-byte 对齐时，使用 &lt;code&gt;uint4&lt;/code&gt; 或等价的 128-bit load 搬运 8 个 FP16。尾部不整齐、跨页或变长序列必须走 masked load。向量化减少指令数，但不能越界，也不能假设框架给出的任意 stride 都连续。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. 核心 CUDA 骨架&lt;a href=&quot;#6-核心-cuda-骨架&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;下面只展示在线状态更新和 tiled 主循环的边界。生产 kernel 还需要真正的 MMA fragment、swizzle layout、causal 边界和架构特化；benchmark 不使用这段教学骨架冒充工业实现。&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OnlineState&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; row_max;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; row_sum;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;__device__ __forceinline__ OnlineState &lt;/span&gt;&lt;span&gt;merge_softmax_tile&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;OnlineState old_state, &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; tile_max, &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; tile_sum) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; next_max &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fmaxf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;old_state&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;row_max&lt;/span&gt;&lt;span&gt;, tile_max);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; old_scale &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;__expf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;old_state&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;row_max&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; next_max);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; tile_scale &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;__expf&lt;/span&gt;&lt;span&gt;(tile_max &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; next_max);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;next_max,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;old_state&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;row_sum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; old_scale &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; tile_sum &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; tile_scale,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Br&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Bc&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;__global__ &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;flash_attention_forward&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; half&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; __restrict__ q,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; half&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; __restrict__ k,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; half&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; __restrict__ v,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;half&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; __restrict__ out,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; sequence,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; scale) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;extern&lt;/span&gt;&lt;span&gt; __shared__ half smem[];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;half&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;k_stage&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {smem, smem &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; Bc &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; D};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;half&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;v_stage&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {smem &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; Bc &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; D, smem &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; Bc &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; D};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// Q fragments and FP32 m/l/O accumulators stay live across the K/V loop.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;OnlineState state{ &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;CUDART_INF_F, &lt;/span&gt;&lt;span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;span&gt;F&lt;/span&gt;&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;output_fragment&lt;/span&gt;&lt;span&gt;[D &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;32&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;33&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; col &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, stage &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;; col &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; sequence; col &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; Bc, stage &lt;/span&gt;&lt;span&gt;^=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;34&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// Production code issues aligned cp.async into the next stage here.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;35&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;load_kv_tile_async&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Bc&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&amp;gt;(k, v, col, &lt;/span&gt;&lt;span&gt;k_stage&lt;/span&gt;&lt;span&gt;[stage], &lt;/span&gt;&lt;span&gt;v_stage&lt;/span&gt;&lt;span&gt;[stage]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;36&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;cp_async_wait_and_sync&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;37&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;38&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// mma_qk returns FP32 score fragments; masked tiles become -infinity.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;39&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;auto&lt;/span&gt;&lt;span&gt; scores &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;mma_qk&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Br&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;Bc&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&amp;gt;(q, &lt;/span&gt;&lt;span&gt;k_stage&lt;/span&gt;&lt;span&gt;[stage], scale);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;40&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; tile_max &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;warp_block_max&lt;/span&gt;&lt;span&gt;(scores);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;41&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; next_max &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fmaxf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;row_max&lt;/span&gt;&lt;span&gt;, tile_max);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;42&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;rescale_output&lt;/span&gt;&lt;span&gt;(output_fragment, &lt;/span&gt;&lt;span&gt;__expf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;row_max&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; next_max));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;43&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; tile_sum &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;exp_scores_and_mma_pv&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;44&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scores, next_max, &lt;/span&gt;&lt;span&gt;v_stage&lt;/span&gt;&lt;span&gt;[stage], output_fragment);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;45&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;state &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {next_max,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;46&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;             &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;row_sum&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;__expf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;row_max&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; next_max) &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; tile_sum};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;47&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;48&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;store_normalized&lt;/span&gt;&lt;span&gt;(out, output_fragment, &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;row_sum&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;49&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;代码中最容易写错的是状态顺序：旧输出必须按新最大值重标定后再累加当前 &lt;span&gt;&lt;span&gt;PVPV&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;V&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;；causal mask 必须在 tile max 之前生效；全 mask 行不能让 &lt;span&gt;&lt;span&gt;−∞−(−∞)-\infty-(-\infty)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;∞&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;∞&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 产生 NaN。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. shape、mask 与大模型 dispatch&lt;a href=&quot;#7-shapemask-与大模型-dispatch&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;工业实现至少应按以下维度分派：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;span&gt;&lt;span&gt;D=64/128D=64/128&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;64/128&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;：使用专用 MMA/layout；其他 head dim 走通用 kernel 或库回退。&lt;/li&gt;
&lt;li&gt;短 &lt;span&gt;&lt;span&gt;NN&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;：kernel launch 和 online bookkeeping 占比高，普通 fused SDPA 或 GEMM 可能更合适。&lt;/li&gt;
&lt;li&gt;长 &lt;span&gt;&lt;span&gt;NN&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;、小 &lt;span&gt;&lt;span&gt;B×HB\times H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;：沿 K 维做 split，多个 CTA 产生局部 &lt;span&gt;&lt;span&gt;(m,l,o)(m,l,o)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，再用同一合并公式归约。&lt;/li&gt;
&lt;li&gt;causal：跳过完全位于上三角的 tile；对角 tile 才做逐元素 mask。&lt;/li&gt;
&lt;li&gt;GQA/MQA：query head 映射到共享 KV head，避免物理复制 K/V；但多个 query head 的复用要和 CTA 调度一起设计。&lt;/li&gt;
&lt;li&gt;dropout/反向：训练必须保存或重算 log-sum-exp，并保证随机数 offset 可复现，不能直接套推理 kernel。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;极长序列还要考虑 32-bit 索引溢出、grid 维度、变长 batch 的有效 token 数，以及 sequence parallel/context parallel 的跨卡归约。单卡 FlashAttention 解决的是片上/显存 IO，不自动解决多卡通信。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;8. 独占 GPU benchmark&lt;a href=&quot;#8-独占-gpu-benchmark&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;测试环境为 RTX 3060 Laptop 6 GiB、SM86、driver 581.57、PyTorch 2.11.0+cu130。输入为 causal FP16，&lt;span&gt;&lt;span&gt;B=1,H=32,D=128B=1,H=32,D=128&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;128&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。每个 shape 先 warmup，再做 7 组 CUDA Event 测量，每组内重复 5 到 30 次，报告 7 组均值的中位数。&lt;/p&gt;&lt;p&gt;测试前 &lt;code&gt;nvidia-smi&lt;/code&gt; 和 &lt;code&gt;pmon&lt;/code&gt; 均无 compute process。运行时临时把允许的 power limit 从 100 W 提到 130 W，监控峰值为 100% SM、7000 MHz 显存、1965 MHz 核心、102 W、76°C；结束后恢复 100 W。监控进程只采样硬件计数，不提交 CUDA 工作。&lt;/p&gt;&lt;p&gt;对比项强制为 PyTorch &lt;code&gt;SDPBackend.FLASH_ATTENTION&lt;/code&gt; 与 &lt;code&gt;SDPBackend.MATH&lt;/code&gt;。因此下表验证的是生产 FlashAttention 数据流，而不是上一节的简化骨架。&lt;/p&gt;




















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;span&gt;&lt;span&gt;NN&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/th&gt;&lt;th&gt;FlashAttention&lt;/th&gt;&lt;th&gt;Math SDPA&lt;/th&gt;&lt;th&gt;加速&lt;/th&gt;&lt;th&gt;Flash 峰值额外显存&lt;/th&gt;&lt;th&gt;Math 峰值额外显存&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;512&lt;/td&gt;&lt;td&gt;0.149 ms&lt;/td&gt;&lt;td&gt;2.214 ms&lt;/td&gt;&lt;td&gt;14.82x&lt;/td&gt;&lt;td&gt;8.1 MiB&lt;/td&gt;&lt;td&gt;109.0 MiB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1024&lt;/td&gt;&lt;td&gt;0.447 ms&lt;/td&gt;&lt;td&gt;7.878 ms&lt;/td&gt;&lt;td&gt;17.61x&lt;/td&gt;&lt;td&gt;16.1 MiB&lt;/td&gt;&lt;td&gt;364.0 MiB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2048&lt;/td&gt;&lt;td&gt;1.704 ms&lt;/td&gt;&lt;td&gt;30.276 ms&lt;/td&gt;&lt;td&gt;17.77x&lt;/td&gt;&lt;td&gt;32.3 MiB&lt;/td&gt;&lt;td&gt;1312.1 MiB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4096&lt;/td&gt;&lt;td&gt;6.573 ms&lt;/td&gt;&lt;td&gt;155.493 ms&lt;/td&gt;&lt;td&gt;23.66x&lt;/td&gt;&lt;td&gt;64.5 MiB&lt;/td&gt;&lt;td&gt;4960.1 MiB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;8192&lt;/td&gt;&lt;td&gt;25.854 ms&lt;/td&gt;&lt;td&gt;OOM&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;129.0 MiB&lt;/td&gt;&lt;td&gt;OOM&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;在 &lt;span&gt;&lt;span&gt;N≤4096N\le4096&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≤&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;4096&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的可比区间，最大绝对误差均为 &lt;span&gt;&lt;span&gt;1.953125×10−31.953125\times10^{-3}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1.953125&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，相对 &lt;span&gt;&lt;span&gt;L2L_2&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 误差从 &lt;span&gt;&lt;span&gt;2.54×10−42.54\times10^{-4}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2.54&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 到 &lt;span&gt;&lt;span&gt;2.68×10−42.68\times10^{-4}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2.68&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。这是 FP16 输出和不同归约顺序的预期量级，不应要求 bitwise 一致。&lt;/p&gt;&lt;p&gt;可复现入口如下：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; torch.nn.attention &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; SDPBackend, sdpa_kernel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; torch.nn.functional &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; F&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;with&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;sdpa_kernel&lt;/span&gt;&lt;span&gt;(SDPBackend.&lt;/span&gt;&lt;span&gt;FLASH_ATTENTION&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;output &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; F.&lt;/span&gt;&lt;span&gt;scaled_dot_product_attention&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;query, key, value, &lt;/span&gt;&lt;span&gt;is_causal&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;True&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;dropout_p&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这里的 14.82x 到 23.66x 不能外推到 H100，也不能解释为“算法少算了同样倍数的 FLOP”。Math 路径承担了中间张量物化、mask 和多 kernel 流量；硬件、框架版本、shape 或非 causal 模式改变后比例会变化。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;9. 局限与回退路径&lt;a href=&quot;#9-局限与回退路径&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;本文只验证 forward causal FP16。没有测试 backward、dropout、变长 packed sequence、RoPE 融合、FP8 scale 或多 GPU context parallel。SM86 也没有 Hopper 的 TMA、WGMMA 和更大的片上资源。&lt;/p&gt;&lt;p&gt;生产中优先调用框架 SDPA、FlashAttention 官方实现或 cuDNN，并让后端根据 dtype、head dim 和 mask 选择 kernel。只有自定义 bias、特殊稀疏模式或框架不覆盖的融合边界，才值得维护手写 CUDA；不支持的 shape 应明确回退，而不是静默给出错误结果。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;10. 参考资料&lt;a href=&quot;#10-参考资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2205.14135&quot; target=&quot;_blank&quot;&gt;FlashAttention：IO-Aware Exact Attention&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2307.08691&quot; target=&quot;_blank&quot;&gt;FlashAttention-2：并行划分与工作分配&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Dao-AILab/flash-attention&quot; target=&quot;_blank&quot;&gt;FlashAttention 官方 CUDA 实现&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.pytorch.org/docs/main/generated/torch.nn.functional.scaled_dot_product_attention.html&quot; target=&quot;_blank&quot;&gt;PyTorch Scaled Dot Product Attention&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.nvidia.com/blog/?p=113179&quot; target=&quot;_blank&quot;&gt;NVIDIA：Tuning Flash Attention for Peak Performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oneflow.org/a/share/jishuboke/54.html&quot; target=&quot;_blank&quot;&gt;OneFlow：如何实现一个高效的 Softmax CUDA kernel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oneflow.org/a/share/jishuboke/55.html&quot; target=&quot;_blank&quot;&gt;OneFlow：系统设计中的 Kernel 与 CUDA Stream 边界&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dlog.com.cn/posts/leetgpu05/softmax/&quot; target=&quot;_blank&quot;&gt;dlog：Softmax 优化详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/cuda/cuda-programming-guide/04-special-topics/async-copies.html&quot; target=&quot;_blank&quot;&gt;CUDA Programming Guide：异步 global-to-shared copy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>CUDA KV Cache：分页存储与长上下文 Decode 极致优化</title><link>https://chengzipai.xyz/posts/cuda-paged-kv-cache-extreme/</link><guid isPermaLink="true">https://chengzipai.xyz/posts/cuda-paged-kv-cache-extreme/</guid><description>面向大模型推理拆解 KV Cache 容量、分页寻址、向量化 append、GQA decode 与 split-KV，并用 FlashInfer 和 PyTorch 做长上下文实测。</description><pubDate>Wed, 15 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;自回归大模型每次只生成一个 token，却必须让新 query 访问此前所有 token 的 key/value。KV Cache 把过去 token 的 K/V 保留下来，避免每步重算整个前缀；代价是缓存容量随 batch、层数和上下文线性增长，而且 decode 每步都要重新流式读取这些历史数据。&lt;/p&gt;
&lt;p&gt;当服务端同时处理变长请求时，单纯把缓存预留成连续的 &lt;code&gt;max_seq_len&lt;/code&gt; 数组，会把显存浪费、碎片、拷贝和 attention kernel 寻址绑在一起。本文从 CUDA 地址计算出发，实现分页 append 与 paged GQA decode，再讨论长上下文下的 warp 划分、split-KV、量化和调度边界。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;1. KV Cache 为什么成为大模型推理瓶颈&lt;a href=&quot;#1-kv-cache-为什么成为大模型推理瓶颈&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;设每层有 &lt;span&gt;&lt;span&gt;HkvH_{kv}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 个 KV head，head dim 为 &lt;span&gt;&lt;span&gt;DD&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，batch 为 &lt;span&gt;&lt;span&gt;BB&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，上下文长度为 &lt;span&gt;&lt;span&gt;LL&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，元素字节数为 &lt;span&gt;&lt;span&gt;ss&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，层数为 &lt;span&gt;&lt;span&gt;NlN_l&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。K 和 V 两份缓存总容量是&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;MKV=2BNlLHkvDs.M_{KV}=2BN_lLH_{kv}Ds.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;V&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;以 &lt;span&gt;&lt;span&gt;Nl=32,Hkv=8,D=128,L=32768N_l=32,H_{kv}=8,D=128,L=32768&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;128&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;32768&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;、FP16、&lt;span&gt;&lt;span&gt;B=1B=1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 为例：&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;MKV=2×1×32×32768×8×128×2=4 GiB.M_{KV}=2\times1\times32\times32768\times8\times128\times2
=4\ \text{GiB}.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;V&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;32768&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;128&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;GiB&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;这还没有包含模型权重、激活、allocator 保留页和 attention workspace。若把 8 个 KV head 物理展开到 32 个 query head，容量会再乘 4。GQA 的意义不只是少几个参数，它直接降低 decode 每步必须读取的缓存字节数。&lt;/p&gt;&lt;p&gt;单 token decode 的矩阵很“瘦”：&lt;span&gt;&lt;span&gt;QQ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Q&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 只有一行，Tensor Core 很难像 prefill 大 GEMM 一样饱和；随着 &lt;span&gt;&lt;span&gt;LL&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 增大，它越来越接近显存带宽和访存延迟受限。因此要同时优化两件事：页面管理不能制造额外复制，kernel 也不能先 gather 成连续大张量再做 attention。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. 连续缓存、分页缓存与精度语义&lt;a href=&quot;#2-连续缓存分页缓存与精度语义&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;连续缓存通常布局为&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[B,Lmax,2,Hkv,D].[B,L_{max},2,H_{kv},D].&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ma&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;它的地址计算简单，但每个请求必须预留最大长度；请求结束或增长时可能留下不可复用空洞。Paged KV Cache 把物理显存切成固定 token 数的 block：&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;cache[P][2][T][Hkv][D],\text{cache}[P][2][T][H_{kv}][D],&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;其中 &lt;span&gt;&lt;span&gt;PP&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 是物理页数，&lt;span&gt;&lt;span&gt;TT&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 是 page size。每个请求只保存逻辑页到物理页的 &lt;code&gt;block_table&lt;/code&gt;。逻辑 token &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的地址为&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;pl=⌊tT⌋,o=t mod T,p=block_table[b,pl].p_l=\left\lfloor\frac{t}{T}\right\rfloor,\qquad
o=t\bmod T,\qquad
p=\mathrm{block\_table}[b,p_l].&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;⌊&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⌋&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;block_table&lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;最后一页最多浪费 &lt;span&gt;&lt;span&gt;T−1T-1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 个 token，而不是浪费到 &lt;span&gt;&lt;span&gt;LmaxL_{max}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ma&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;Paged KV logical-to-physical mapping&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;760&quot; src=&quot;/_astro/paged-kv-addressing.BlTCUHtW_1Vvu8P.svg&quot; srcset=&quot;/_astro/paged-kv-addressing.BlTCUHtW_Z8FbRi.svg 640w, /_astro/paged-kv-addressing.BlTCUHtW_Z1Kwbz0.svg 750w, /_astro/paged-kv-addressing.BlTCUHtW_GFRxK.svg 828w, /_astro/paged-kv-addressing.BlTCUHtW_Z1Dgcu0.svg 1080w, /_astro/paged-kv-addressing.BlTCUHtW_1Vvu8P.svg 1280w&quot; /&gt;&lt;figcaption&gt;Paged KV logical-to-physical mapping&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;图 1：请求看到连续的逻辑 token，物理页可以离散。append 和 decode 直接通过 page table 寻址，不生成连续 gather buffer；共享前缀可以让不同请求的逻辑页指向同一只读物理页。&lt;/p&gt;&lt;p&gt;本文缓存和 query 为 FP16，点积、在线 Softmax 和输出 accumulator 为 FP32。BF16 可扩大数值范围但流量不变。FP8/INT8 cache 可以近似减半流量和容量，代价是每页或每组 scale、dequant 指令和精度校准；不能只改存储类型却继续按 FP16 解释地址。FP64 不属于在线大模型 decode 的合理默认路径。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. 朴素路径的三个隐藏成本&lt;a href=&quot;#3-朴素路径的三个隐藏成本&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;3.1 按最大长度预留&lt;a href=&quot;#31-按最大长度预留&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;如果 100 个请求都按 32K 预留，而多数只生成几百 token，逻辑空闲空间仍占物理显存。连续 batching 能提高计算吞吐，却会放大不同生命周期带来的外部碎片。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.2 先 gather 再 attention&lt;a href=&quot;#32-先-gather-再-attention&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;一种容易实现的 paged attention 是：根据 page table 把 K/V gather 成连续张量，再调用 GEMM/SDPA。这样每个 decode step 都额外读写整个历史缓存，流量至少又增加&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2×MKV,active layer,2\times M_{KV,\mathrm{active\ layer}},&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;V&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;span&gt;active&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;layer&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;并产生大临时 buffer。分页的正确边界是把地址翻译融合进 attention kernel。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.3 把 GQA 展开成 MHA&lt;a href=&quot;#33-把-gqa-展开成-mha&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;若 &lt;span&gt;&lt;span&gt;Hq/Hkv=gH_q/H_{kv}=g&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;q&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，&lt;code&gt;repeat_interleave&lt;/code&gt; 会把 K/V 物理复制 &lt;span&gt;&lt;span&gt;gg&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 份。它让普通 MHA kernel 可以运行，却消除了 GQA 的容量与带宽收益。正确映射应是&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;hkv=⌊hqg⌋,h_{kv}=\left\lfloor\frac{h_q}{g}\right\rfloor,&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;⌊&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;q&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⌋&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;多个 query head 在读取时共享同一个 KV head，而不是事先复制。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. 向量化 paged append&lt;a href=&quot;#4-向量化-paged-append&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;每个 decode step 先把当前层的新 K/V 写进最后一页。标量 kernel 每个线程写一个 &lt;code&gt;half&lt;/code&gt;，还可能让 K 和 V 分成两个 launch。对 &lt;span&gt;&lt;span&gt;D=128D=128&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;128&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 且地址 16-byte 对齐的常见 shape，可以把 8 个 FP16 打成一个 &lt;code&gt;uint4&lt;/code&gt;，一个 block 同时完成地址翻译和连续写入。&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;HeadDim&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PageSize&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;__global__ &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;append_paged_kv&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; half&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; __restrict__ new_kv,&lt;/span&gt;&lt;span&gt;       // [B, 2, Hkv, D]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;half&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; __restrict__ cache,&lt;/span&gt;&lt;span&gt;              // [P, 2, T, Hkv, D]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int*&lt;/span&gt;&lt;span&gt; __restrict__ block_table,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int*&lt;/span&gt;&lt;span&gt; __restrict__ sequence_len,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; max_pages,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; num_kv_heads) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; batch &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; kind_head &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; kind &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; kind_head &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; num_kv_heads;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; head &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; kind_head &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; num_kv_heads;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; token &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;sequence_len&lt;/span&gt;&lt;span&gt;[batch] &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; logical_page &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; token &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; PageSize;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; page_offset &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; token &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; PageSize;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; physical_page &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;block_table&lt;/span&gt;&lt;span&gt;[batch &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; max_pages &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; logical_page];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;constexpr&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; kHalfPerVector &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;sizeof&lt;/span&gt;&lt;span&gt;(uint4) &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;sizeof&lt;/span&gt;&lt;span&gt;(half);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; vector_index &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (vector_index &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; HeadDim &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; kHalfPerVector) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;size_t&lt;/span&gt;&lt;span&gt; source &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;(((batch &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; kind) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; num_kv_heads &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; head) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; HeadDim);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;size_t&lt;/span&gt;&lt;span&gt; target &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;((((&lt;/span&gt;&lt;span&gt;&lt;span&gt;static_cast&lt;/span&gt;&lt;span&gt;&amp;lt;size_t&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(physical_page) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; kind) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; PageSize&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; page_offset) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; num_kv_heads &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; head) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; HeadDim);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;reinterpret_cast&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;uint4&lt;/span&gt;&lt;span&gt;*&amp;gt;&lt;/span&gt;&lt;span&gt;(cache &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; target)[vector_index] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;reinterpret_cast&lt;/span&gt;&lt;span&gt;&amp;lt;const&lt;/span&gt;&lt;/span&gt;&lt;span&gt; uint4&lt;/span&gt;&lt;span&gt;*&amp;gt;&lt;/span&gt;&lt;span&gt;(new_kv &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; source)[vector_index];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这个 kernel 适用于 &lt;code&gt;HeadDim % 8 == 0&lt;/code&gt;、输入和 cache 都满足 16-byte 对齐的路径。否则应 dispatch 到 &lt;code&gt;half2&lt;/code&gt; 或 masked scalar 尾部，而不是越界。batch 很小时，append 只有几十 KiB，瓶颈通常是 launch latency，不应拿有效带宽低就断言 global memory 很慢；融合 K/V 和多请求才是主要收益。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. Paged GQA decode 的 warp 数据流&lt;a href=&quot;#5-paged-gqa-decode-的-warp-数据流&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;一个直接的 CUDA 映射是每个 warp 负责一个 &lt;code&gt;(request, query_head)&lt;/code&gt;。lane 持有 &lt;span&gt;&lt;span&gt;D/32D/32&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;/32&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 个 query 和输出 fragment，沿 token 循环：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;通过 &lt;code&gt;block_table&lt;/code&gt; 得到 K/V page；&lt;/li&gt;
&lt;li&gt;合并读取对应 KV head 的 K，warp reduce 得到一个 score；&lt;/li&gt;
&lt;li&gt;用在线 Softmax 更新 &lt;span&gt;&lt;span&gt;m/lm/l&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;每个 lane 读取自己的 V fragment 并更新 FP32 输出。&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;HeadDim&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PageSize&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;__global__ &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;paged_decode&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; half&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; __restrict__ q,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; half&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; __restrict__ cache,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int*&lt;/span&gt;&lt;span&gt; __restrict__ page_table,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int*&lt;/span&gt;&lt;span&gt; __restrict__ lengths,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;half&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; __restrict__ out,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; query_heads,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; kv_heads,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; max_pages) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; lane &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;31&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; warp &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; query_head &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;blockDim&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; warp;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; batch &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (query_head &lt;/span&gt;&lt;span&gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; query_heads) &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; group_size &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; query_heads &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; kv_heads;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; kv_head &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; query_head &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; group_size;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;q_fragment&lt;/span&gt;&lt;span&gt;[HeadDim &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;o_fragment&lt;/span&gt;&lt;span&gt;[HeadDim &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;load_query_fragment&lt;/span&gt;&lt;span&gt;(q, batch, query_head, lane, q_fragment);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; running_max &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;CUDART_INF_F;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; running_sum &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;span&gt;F&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; token &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;; token &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lengths&lt;/span&gt;&lt;span&gt;[batch]; &lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;token) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; logical_page &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; token &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; PageSize;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; offset &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; token &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; PageSize;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; page &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;page_table&lt;/span&gt;&lt;span&gt;[batch &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; max_pages &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; logical_page];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; half&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; key &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;cache_ptr&lt;/span&gt;&lt;span&gt;(cache, page, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, offset, kv_head);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; half&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; value &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;cache_ptr&lt;/span&gt;&lt;span&gt;(cache, page, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, offset, kv_head);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;32&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; score &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;dot_fragment&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;HeadDim&lt;/span&gt;&lt;span&gt;&amp;gt;(q_fragment, key, lane);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;33&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;score &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;warp_sum&lt;/span&gt;&lt;span&gt;(score) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;rsqrtf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;static_cast&lt;/span&gt;&lt;span&gt;&amp;lt;float&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(HeadDim));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;34&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; next_max &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fmaxf&lt;/span&gt;&lt;span&gt;(running_max, score);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;35&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; old_scale &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;__expf&lt;/span&gt;&lt;span&gt;(running_max &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; next_max);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;36&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; weight &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;__expf&lt;/span&gt;&lt;span&gt;(score &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; next_max);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;37&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;#pragma&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unroll&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;38&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;; i &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; HeadDim &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;i) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;39&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;o_fragment&lt;/span&gt;&lt;span&gt;[i] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;o_fragment&lt;/span&gt;&lt;span&gt;[i] &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; old_scale&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;40&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                    &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; weight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;__half2float&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;[lane &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; i]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;41&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;42&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;running_sum &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; running_sum &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; old_scale &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; weight;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;43&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;running_max &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; next_max;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;44&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;45&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;store_output&lt;/span&gt;&lt;span&gt;(out, batch, query_head, lane, o_fragment, running_sum);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;46&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这段代码表达了正确的页寻址和在线归一化，但生产实现还会让多个 warp/CTA 协作、使用 packed load、减少整数除法、缓存 page id，并对长上下文做 split-KV。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;Paged GQA decode pipeline&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;760&quot; src=&quot;/_astro/gqa-paged-decode.CkPBqFBL_1Vvu8P.svg&quot; srcset=&quot;/_astro/gqa-paged-decode.CkPBqFBL_Z8FbRi.svg 640w, /_astro/gqa-paged-decode.CkPBqFBL_Z1Kwbz0.svg 750w, /_astro/gqa-paged-decode.CkPBqFBL_GFRxK.svg 828w, /_astro/gqa-paged-decode.CkPBqFBL_Z1Dgcu0.svg 1080w, /_astro/gqa-paged-decode.CkPBqFBL_1Vvu8P.svg 1280w&quot; /&gt;&lt;figcaption&gt;Paged GQA decode pipeline&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;图 2：32 个 query head 映射到 8 个 KV head；warp 沿逻辑 token 前进，每跨 page size 才更新物理页，FP32 的 &lt;span&gt;&lt;span&gt;m/l/Om/l/O&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 状态跨页保留。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. 从基础实现到极致优化&lt;a href=&quot;#6-从基础实现到极致优化&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;6.1 page id 不要每个元素都查&lt;a href=&quot;#61-page-id-不要每个元素都查&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;page table 查询应位于 token tile 或 page 边界，而不是每个 &lt;span&gt;&lt;span&gt;DD&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 元素。一个 warp 广播 page id，随后 lane 连续读取 head dim。&lt;code&gt;PageSize=16&lt;/code&gt; 时，单次表查询可以服务 16 个 token。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.2 packed load 与布局&lt;a href=&quot;#62-packed-load-与布局&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;对 NHD 布局 &lt;code&gt;[page, token, head, dim]&lt;/code&gt;，同一 head 的 &lt;span&gt;&lt;span&gt;DD&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 连续，适合 &lt;code&gt;half2&lt;/code&gt;/128-bit load。HND 布局 &lt;code&gt;[page, head, token, dim]&lt;/code&gt; 则让同一 head 跨 token 更连续，具体选择取决于 CTA 是并行 token 还是并行 head。不要只凭名字判断，应该从 warp 实际地址验证 transaction。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.3 GQA 共享与 CTA 组织&lt;a href=&quot;#63-gqa-共享与-cta-组织&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;同组 query head 读取相同 K/V。若每个 warp 独立读取，L2 可能复用但 HBM 流量不稳定；更激进的实现让一个 CTA 同时处理一组 query head，把 K/V tile 放进 shared memory，再由多个 warp 消费。代价是 shared memory、寄存器和同步增加，小 batch 或短上下文可能不划算。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.4 长上下文 split-KV&lt;a href=&quot;#64-长上下文-split-kv&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;当 batch 很小、&lt;span&gt;&lt;span&gt;LL&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 很长时，&lt;code&gt;batch * query_heads&lt;/code&gt; 仍可能不足以填满所有 SM。把 K 维分成 &lt;span&gt;&lt;span&gt;SS&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 段，每段 CTA 产生 &lt;span&gt;&lt;span&gt;(ms,ls,os)(m_s,l_s,o_s)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，再按在线 Softmax 的合并律归约：&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;m=max⁡sms,m=\max_s m_s,&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;max&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;l=∑slsems−m,o=∑sosems−m,O=o/l.l=\sum_s l_s e^{m_s-m},\qquad
o=\sum_s o_s e^{m_s-m},\qquad
O=o/l.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;∑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;∑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;split 增加临时状态和第二个归约 kernel，只有并行度收益大于额外流量时才启用。应按 &lt;span&gt;&lt;span&gt;B,Hq,L,DB,H_q,L,D&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;q&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 和 SM 数量 dispatch，而不是固定切段。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.5 page size、碎片与 TLB 式权衡&lt;a href=&quot;#65-page-size碎片与-tlb-式权衡&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;小 page 降低最后一页内部碎片，却增加 page table、allocator 元数据和地址切换；大 page 相反。16 token 是常见折中，不是定理。超长上下文、prefix cache 和 beam search 还要考虑只读页共享与 copy-on-write：共享前缀不能被后续 append 原地覆盖。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.6 量化、RoPE 与 CUDA Graph&lt;a href=&quot;#66-量化rope-与-cuda-graph&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;FP8/INT8 KV cache 应让 dequant 与 attention 融合，scale 最好按 page/head 或更细粒度存储；粒度越细精度越好，scale 流量和指令越多。RoPE 通常在写 K 前完成，或在读取时按位置融合，二者影响 cache 是否可跨位置复用。CUDA Graph 要求 workspace、page table buffer 和 kernel dispatch 稳定，不能每步 &lt;code&gt;cudaMalloc&lt;/code&gt; 或改变 host 控制流。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. 大规模 serving 的分层边界&lt;a href=&quot;#7-大规模-serving-的分层边界&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;CUDA kernel 只负责给定 page table 的高效读写。真正的大模型系统还需要上层 runtime：free-list/block allocator、continuous batching、请求抢占、prefix hash、跨请求共享、CPU/NVMe offload 和张量并行。把这些策略塞进一个 kernel 会失去可测试性。&lt;/p&gt;&lt;p&gt;合理分层是：scheduler 决定 active requests，block manager 维护逻辑页，append kernel 写当前 token，paged attention 只消费不可变的本轮 page table。OneFlow 的系统设计同样强调 Kernel 只向 CUDA stream 提交异步工作，资源生命周期和调度由上层边界管理。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;8. 独占 GPU benchmark&lt;a href=&quot;#8-独占-gpu-benchmark&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;测试环境为 RTX 3060 Laptop 6 GiB、SM86、driver 581.57、PyTorch 2.11.0+cu130、FlashInfer 0.6.12。shape 固定为 &lt;span&gt;&lt;span&gt;B=8,Hq=32,Hkv=8,D=128B=8,H_q=32,H_{kv}=8,D=128&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;q&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;H&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;128&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;、FP16、page size 16，context 从 1K 到 32K。每项 warmup 后做 7 组 CUDA Event 测量，报告组均值的中位数。&lt;/p&gt;&lt;p&gt;测试前后均无其他 compute PID；运行监控达到 100% SM、7000 MHz 显存、1965 MHz 核心、102 W、76°C，临时 130 W power limit 在结束后恢复到 100 W。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;8.1 Paged GQA decode&lt;a href=&quot;#81-paged-gqa-decode&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;分页路径使用 FlashInfer &lt;code&gt;BatchDecodeWithPagedKVCacheWrapper&lt;/code&gt;。对比路径把 8 个 KV head 预先展开成 32 个连续 head，再强制调用 PyTorch Flash SDPA。这个对比代表两种可运行的大模型数据路径，但 &lt;strong&gt;6 到 7 倍差距主要同时包含 GQA 不复制和专用 decode 调度收益，不能单独归因于 paging&lt;/strong&gt;。&lt;/p&gt;




















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Context&lt;/th&gt;&lt;th&gt;FlashInfer paged GQA&lt;/th&gt;&lt;th&gt;Expanded contiguous Flash SDPA&lt;/th&gt;&lt;th&gt;延迟比&lt;/th&gt;&lt;th&gt;原生 KV Cache&lt;/th&gt;&lt;th&gt;展开后 K/V&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1024&lt;/td&gt;&lt;td&gt;0.131 ms&lt;/td&gt;&lt;td&gt;0.838 ms&lt;/td&gt;&lt;td&gt;6.42x&lt;/td&gt;&lt;td&gt;32 MiB&lt;/td&gt;&lt;td&gt;128 MiB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4096&lt;/td&gt;&lt;td&gt;0.457 ms&lt;/td&gt;&lt;td&gt;3.283 ms&lt;/td&gt;&lt;td&gt;7.19x&lt;/td&gt;&lt;td&gt;128 MiB&lt;/td&gt;&lt;td&gt;512 MiB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;8192&lt;/td&gt;&lt;td&gt;0.953 ms&lt;/td&gt;&lt;td&gt;6.683 ms&lt;/td&gt;&lt;td&gt;7.01x&lt;/td&gt;&lt;td&gt;256 MiB&lt;/td&gt;&lt;td&gt;1024 MiB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;16384&lt;/td&gt;&lt;td&gt;1.785 ms&lt;/td&gt;&lt;td&gt;13.275 ms&lt;/td&gt;&lt;td&gt;7.44x&lt;/td&gt;&lt;td&gt;512 MiB&lt;/td&gt;&lt;td&gt;2048 MiB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;32768&lt;/td&gt;&lt;td&gt;3.623 ms&lt;/td&gt;&lt;td&gt;跳过&lt;/td&gt;&lt;td&gt;-&lt;/td&gt;&lt;td&gt;1024 MiB&lt;/td&gt;&lt;td&gt;需要 4096 MiB&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;32K 对比路径在缓存之外只剩约 3914 MiB 可用，却需要 4096 MiB 展开 K/V，因此按预先设定的安全阈值跳过，没有把系统推入不受控 OOM。分页 GQA 路径完成了 1 GiB 单层缓存的 decode。&lt;/p&gt;&lt;p&gt;在可比 shape 上，最大绝对误差从 &lt;span&gt;&lt;span&gt;1.22×10−41.22\times10^{-4}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1.22&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 降到 &lt;span&gt;&lt;span&gt;3.05×10−53.05\times10^{-5}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;3.05&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，相对 &lt;span&gt;&lt;span&gt;L2L_2&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 误差约 &lt;span&gt;&lt;span&gt;3.86×10−43.86\times10^{-4}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;3.86&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 到 &lt;span&gt;&lt;span&gt;4.00×10−44.00\times10^{-4}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;4.00&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，符合 FP16 输出和不同归约顺序。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;8.2 Fused paged append&lt;a href=&quot;#82-fused-paged-append&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;append 对比 FlashInfer fused kernel 与两次 PyTorch advanced-index store。每次写入 8 个请求的一枚 K/V token，时间主要受 launch 和索引开销控制。&lt;/p&gt;








































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Context&lt;/th&gt;&lt;th&gt;Fused append&lt;/th&gt;&lt;th&gt;两次 indexed store&lt;/th&gt;&lt;th&gt;加速&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1024&lt;/td&gt;&lt;td&gt;0.0344 ms&lt;/td&gt;&lt;td&gt;0.1266 ms&lt;/td&gt;&lt;td&gt;3.67x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4096&lt;/td&gt;&lt;td&gt;0.0312 ms&lt;/td&gt;&lt;td&gt;0.1159 ms&lt;/td&gt;&lt;td&gt;3.71x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;8192&lt;/td&gt;&lt;td&gt;0.0340 ms&lt;/td&gt;&lt;td&gt;0.1138 ms&lt;/td&gt;&lt;td&gt;3.35x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;16384&lt;/td&gt;&lt;td&gt;0.0278 ms&lt;/td&gt;&lt;td&gt;0.1102 ms&lt;/td&gt;&lt;td&gt;3.96x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;32768&lt;/td&gt;&lt;td&gt;0.0271 ms&lt;/td&gt;&lt;td&gt;0.1043 ms&lt;/td&gt;&lt;td&gt;3.84x&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;append 延迟几乎不随 context 线性增长，因为每步只写新 token；context 影响的是目标页地址和后续 decode 读取量。这里有效带宽不到显存峰值并不矛盾：写入量只有 32 KiB，kernel launch 和索引固定成本占主导。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;9. 局限与回退&lt;a href=&quot;#9-局限与回退&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;本文只测单 GPU、单层 cache 数据和无 RoPE/ALiBi 的 FP16 GQA decode，没有测完整模型 tokens/s。32 层 32K cache 的容量可以按公式外推，但不能把单层 kernel 延迟简单乘层数后当作端到端延迟，因为层间还有 GEMM、通信和调度。&lt;/p&gt;&lt;p&gt;page table 本身不能保证更快；请求长度接近且显存充足时，连续 cache 地址更简单。极小 batch、短 context 可回退到 contiguous decode；长 context 或并行度不足才启用 split-KV。量化 cache 必须以任务精度验证为前提，OOM 时的正确回退是降低 batch/context、启用 GQA/量化/offload，而不是越界复用物理页。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;10. 参考资料&lt;a href=&quot;#10-参考资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2309.06180&quot; target=&quot;_blank&quot;&gt;vLLM：PagedAttention 论文&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vllm-project.github.io/2023/06/20/vllm.html&quot; target=&quot;_blank&quot;&gt;vLLM：PagedAttention 工程介绍&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vllm-project/vllm&quot; target=&quot;_blank&quot;&gt;vLLM 官方仓库&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/flashinfer-ai/flashinfer&quot; target=&quot;_blank&quot;&gt;FlashInfer：LLM Serving Kernel Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.flashinfer.ai/generated/flashinfer.decode.cudnn_batch_decode_with_kv_cache.html&quot; target=&quot;_blank&quot;&gt;FlashInfer paged decode API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2307.08691&quot; target=&quot;_blank&quot;&gt;FlashAttention-2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oneflow.org/a/share/jishuboke/54.html&quot; target=&quot;_blank&quot;&gt;OneFlow：高效 Softmax CUDA kernel 的分段、half2 与 bank conflict&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oneflow.org/a/share/jishuboke/55.html&quot; target=&quot;_blank&quot;&gt;OneFlow：系统设计中的 Kernel/Stream 分层&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dlog.com.cn/posts/leetgpu05/softmax/&quot; target=&quot;_blank&quot;&gt;dlog：Softmax 优化详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/cuda/cuda-c-best-practices-guide/&quot; target=&quot;_blank&quot;&gt;CUDA Best Practices Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>CUDA LSMR 专栏（三）：递推融合与 8kv/11kv 实测</title><link>https://chengzipai.xyz/posts/cuda-lsmr-benchmark/</link><guid isPermaLink="true">https://chengzipai.xyz/posts/cuda-lsmr-benchmark/</guid><description>把 LSMR 小向量递推融合为 CUDA kernel，并用两组真实 FP32 重建输入对齐 CuPy 的迭代、残差与性能。</description><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;前两篇已经把 LSMR 的两个大头固定下来：Solver 不知道矩阵格式，SparseMatrix 则同时持有 CSR(A) 与 CSR(&lt;span&gt;&lt;span&gt;ATA^T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)。最后一篇处理 SpMV 之间的小向量递推，并给出两组真实重建输入的可复现结果。&lt;/p&gt;
&lt;p&gt;这一步最容易犯的错误，是看到“自写 CUDA”就只比较时间。迭代求解器首先要对齐 stop code、迭代数和残差；只有数值轨迹成立，性能数字才有意义。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;1. 剩余瓶颈与性能指标&lt;a href=&quot;#1-剩余瓶颈与性能指标&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;每轮两次 SpMV 之间，LSMR 还要完成归一化、搜索方向和解更新。以长度 &lt;span&gt;&lt;span&gt;nn&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的两条递推为例：&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;hˉ←h−chhˉ,\bar h\leftarrow h-c_h\bar h,&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;←&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;x←x+cxhˉ.x\leftarrow x+c_x\bar h.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;←&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;分成两个 elementwise kernel 时，第一步读 &lt;code&gt;h/hbar&lt;/code&gt;、写 &lt;code&gt;hbar&lt;/code&gt;，第二步读 &lt;code&gt;x/hbar&lt;/code&gt;、写 &lt;code&gt;x&lt;/code&gt;，合计约 6 个长度 &lt;span&gt;&lt;span&gt;nn&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的 FP32 流量，即 &lt;span&gt;&lt;span&gt;24n24n&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;24&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 字节。融合后，每个元素读 &lt;code&gt;h/hbar/x&lt;/code&gt;、写 &lt;code&gt;hbar/x&lt;/code&gt;，约为 &lt;span&gt;&lt;span&gt;20n20n&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 字节，同时少一次 kernel launch。&lt;/p&gt;&lt;p&gt;节省的 4 字节乘 &lt;span&gt;&lt;span&gt;nn&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 不是整个 LSMR 的主导项；真正价值是把确定存在的重复访问和 launch 去掉，同时保持公式边界清楚。评价仍以 solve wall time 为主，并记录迭代数、stop code、解相对差和独立计算的相对残差。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. 递推与 FP32 误差语义&lt;a href=&quot;#2-递推与-fp32-误差语义&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;融合必须尊重依赖：&lt;span&gt;&lt;span&gt;xkx_k&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 使用的是刚更新的 &lt;span&gt;&lt;span&gt;hˉk\bar h_k&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，不能把旧值读进另一个无序 kernel。逐元素形式为&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;hˉk,i=hk,i−chhˉk−1,i,\bar h_{k,i}=h_{k,i}-c_h\bar h_{k-1,i},&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;xk,i=xk−1,i+cxhˉk,i.x_{k,i}=x_{k-1,i}+c_x\bar h_{k,i}.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;两个式子对索引 &lt;span&gt;&lt;span&gt;ii&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 独立，因此可由同一个线程顺序完成。&lt;span&gt;&lt;span&gt;hh&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的下一步更新&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;hk+1,i=vk+1,i−cvhk,ih_{k+1,i}=v_{k+1,i}-c_v h_{k,i}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;与前两式没有需要跨线程同步的关系，但它读写另一组状态，保留为第二个 kernel 更简单。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;Fused LSMR vector recurrence&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;700&quot; src=&quot;/_astro/fused-recurrence.DGBz1jyy_Z4lz9b.svg&quot; srcset=&quot;/_astro/fused-recurrence.DGBz1jyy_febzi.svg 640w, /_astro/fused-recurrence.DGBz1jyy_Z1mBN7p.svg 750w, /_astro/fused-recurrence.DGBz1jyy_2cLaQe.svg 828w, /_astro/fused-recurrence.DGBz1jyy_Z1ycOOL.svg 1080w, /_astro/fused-recurrence.DGBz1jyy_Z4lz9b.svg 1200w&quot; /&gt;&lt;figcaption&gt;Fused LSMR vector recurrence&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;图 1：融合前后不是改变数学，而是让同一线程在寄存器中转交新的 &lt;code&gt;hbar&lt;/code&gt;。红色路径表示被消除的一次 global-memory 往返。&lt;/p&gt;&lt;p&gt;FP32 下不能要求不同归约树逐 bit 相同。这里采用三层正确性标准：stop code 与迭代数应一致；解相对差应落在 FP32 迭代可解释范围；最终使用同一个 CuPy sparse matrix 重新计算 &lt;span&gt;&lt;span&gt;∥Ax−b∥2/∥b∥2\|Ax-b\|_2/\|b\|_2&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;/∥&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，两者应匹配。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. 未融合实现的成本&lt;a href=&quot;#3-未融合实现的成本&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;CuPy 版本把递推写成清晰的数组表达式，适合作为算法参考，但每个表达式由 Python 驱动：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;hbar &lt;/span&gt;&lt;span&gt;*=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;coefficient&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;hbar &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; h&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; step &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; hbar&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;h &lt;/span&gt;&lt;span&gt;*=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;theta_over_rho&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;h &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; v&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;memory pool 可以复用分配，却不会自动把这些语句融合成一个 CUDA kernel；矩阵乘法返回临时向量后，后续加法也会增加一次遍历。对于 8kv/11kv 这类每轮 SpMV 已很快、迭代约百次的输入，host 调度和小 kernel 数量不是零成本。&lt;/p&gt;&lt;p&gt;纯 CUDA 库有两个可控点：矩阵递推通过 cuSPARSE 的 &lt;code&gt;beta&lt;/code&gt; 参数原位完成；依赖明确的小向量递推手写融合。范数仍交给 cuBLAS，不重复实现工业归约。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. 融合数据流&lt;a href=&quot;#4-融合数据流&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;从一轮的数据路径看，融合后的顺序是：&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;u←CSR(A)v→∥u∥2→v←CSR(AT)u→∥v∥2→(hˉ,x,h).u\xleftarrow{\mathrm{CSR}(A)}v
\rightarrow \|u\|_2
\rightarrow
v\xleftarrow{\mathrm{CSR}(A^T)}u
\rightarrow \|v\|_2
\rightarrow
(\bar h,x,h).&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;CSR&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;CSR&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;两个 norm 会把 FP32 标量送回 host，因为停止条件需要分支；其余状态保持在设备端。LSMR 的每一轮天然依赖上一轮，不能简单把多轮并发。优化重点应放在一轮内部的数据复用，而不是制造错误的跨轮流水。&lt;/p&gt;&lt;p&gt;对右端项也采用一次性适配：dense b 若在 host 则复制到复用 buffer；sparse b 先 &lt;code&gt;memset&lt;/code&gt;，再按唯一索引 scatter 成 dense u。LSMR 后续所有递推统一处理 dense 向量，不在热循环里保留 sparse-b 分支。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. Kernel 实现与适用条件&lt;a href=&quot;#5-kernel-实现与适用条件&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;核心 kernel 很短：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;__global__ &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;UpdateHbarAndXKernel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;float*&lt;/span&gt;&lt;span&gt; hbar, &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float*&lt;/span&gt;&lt;span&gt; h, &lt;/span&gt;&lt;span&gt;float*&lt;/span&gt;&lt;span&gt; x,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; coefficient, &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; step, std::&lt;/span&gt;&lt;span&gt;int64_t&lt;/span&gt;&lt;span&gt; size) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; std::&lt;/span&gt;&lt;span&gt;int64_t&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;static_cast&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;std::&lt;/span&gt;&lt;span&gt;int64_t&amp;gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;blockIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockDim&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (i &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; size) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; next_hbar &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;[i] &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; coefficient &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;hbar&lt;/span&gt;&lt;span&gt;[i];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;hbar&lt;/span&gt;&lt;span&gt;[i] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; next_hbar;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;[i] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fmaf&lt;/span&gt;&lt;span&gt;(step, next_hbar, &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;[i]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;每个线程只处理一个连续元素，256 threads/block。这里没有 shared memory、warp shuffle 或复杂 occupancy tuning，因为算子是纯带宽型逐元素更新，寄存器状态只有少量 float；引入 shared memory 只会增加搬运。&lt;/p&gt;&lt;p&gt;融合适用于两式存在逐元素生产者-消费者关系、shape 相同、没有跨元素归约的场景。代价是降低单个基础算子的复用性，所以它放在 LSMR 私有 kernel 层，不暴露成通用 public API。&lt;/p&gt;&lt;p&gt;OneFlow Softmax 的优化也从“naive 多次 global memory”出发，用融合和寄存器缓存减少数据往返；共同原则是先列出实际访存，再决定融合，而不是看到多个 kernel 就机械合并。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. shape、对齐与 dispatch&lt;a href=&quot;#6-shape对齐与-dispatch&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;本 kernel 对任意 &lt;span&gt;&lt;span&gt;nn&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 使用尾部判断，不要求 16-byte 对齐。&lt;code&gt;float4&lt;/code&gt; 能减少指令数，但 &lt;code&gt;hbar/h/x&lt;/code&gt; 三个输入输出指针需要共同对齐，尾部还要单独处理；在当前 &lt;span&gt;&lt;span&gt;n=6177n=6177&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;6177&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 和 &lt;span&gt;&lt;span&gt;2339423394&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;23394&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 上，SpMV 占比更大，先保留简单标量路径。&lt;/p&gt;&lt;p&gt;矩阵方向的 dispatch 则更重要：sparse A 走双 CSR SpMV，dense A 走 GEMV；sparse b 只在入口 scatter；多 RHS 当前逐列求解。没有把 SpMV 与 SpMM 混为一谈，也没有声称一个融合 kernel 适合所有 shape。&lt;/p&gt;&lt;p&gt;如果未来 profile 显示向量 kernel 成为主导，可以按对齐和 &lt;span&gt;&lt;span&gt;nn&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 分派 &lt;code&gt;float4&lt;/code&gt; 路径；如果多个 RHS 改为 block LSMR，则应重新设计 B/C tile 复用，而不是继续逐列调用。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. 可调用接口与 benchmark 脚本&lt;a href=&quot;#7-可调用接口与-benchmark-脚本&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;C++ 调用者提供 device 输出，Context 复用所有工作区：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cuda_lsmr::Context context;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;auto&lt;/span&gt;&lt;span&gt; A &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; cuda_lsmr::&lt;/span&gt;&lt;span&gt;SparseMatrix&lt;/span&gt;&lt;span&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span&gt;FromCsc&lt;/span&gt;&lt;span&gt;(context, csc_view);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cuda_lsmr::&lt;/span&gt;&lt;span&gt;Solver&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;solver&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cuda_lsmr::SolverOptions options;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;options&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;atol&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;1.0&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;F&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;options&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;btol&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;1.0&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;F&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;options&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;max_iterations&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;5000&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;auto&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;solver&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;solve&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;A, dense_b, device_x, options);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;synchronize&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;用于对比的 pybind11 层不参与算法，只接收 CuPy 的 &lt;code&gt;b.data.ptr&lt;/code&gt; 与 &lt;code&gt;x.data.ptr&lt;/code&gt;。矩阵加载、SciPy 转 CSC、H2D、双格式构造和两轮 warmup 都在计时外。CuPy 显式传入 FP32 零 &lt;code&gt;x0&lt;/code&gt;，避免其兼容路径把迭代解向量提升精度。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;8. 8kv/11kv 结果、容差与局限&lt;a href=&quot;#8-8kv11kv-结果容差与局限&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;测试环境为 RTX 3060 Laptop 6 GiB、CUDA 12.9.86、driver 581.57、CuPy 14.0.1。参数固定为 &lt;code&gt;damp=0&lt;/code&gt;、&lt;code&gt;atol=btol=1e-6&lt;/code&gt;、&lt;code&gt;conlim=1e8&lt;/code&gt;、&lt;code&gt;maxiter=5000&lt;/code&gt;。每组执行 7 次同步 solve，报告中位数。&lt;/p&gt;































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;数据集&lt;/th&gt;&lt;th&gt;shape&lt;/th&gt;&lt;th&gt;nnz&lt;/th&gt;&lt;th&gt;CUDA LSMR&lt;/th&gt;&lt;th&gt;CuPy&lt;/th&gt;&lt;th&gt;时间比&lt;/th&gt;&lt;th&gt;迭代数&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;8kv&lt;/td&gt;&lt;td&gt;&lt;span&gt;&lt;span&gt;306136×6177306136\times6177&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;306136&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;6177&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;5,588,894&lt;/td&gt;&lt;td&gt;60.24 ms&lt;/td&gt;&lt;td&gt;127.28 ms&lt;/td&gt;&lt;td&gt;0.473&lt;/td&gt;&lt;td&gt;86 / 86&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;11kv&lt;/td&gt;&lt;td&gt;&lt;span&gt;&lt;span&gt;936063×23394936063\times23394&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;936063&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;23394&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;19,747,202&lt;/td&gt;&lt;td&gt;167.11 ms&lt;/td&gt;&lt;td&gt;229.57 ms&lt;/td&gt;&lt;td&gt;0.728&lt;/td&gt;&lt;td&gt;96 / 96&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;FP32 benchmark comparison&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;700&quot; src=&quot;/_astro/benchmark-comparison.Btrue9iE_Z4lz9b.svg&quot; srcset=&quot;/_astro/benchmark-comparison.Btrue9iE_febzi.svg 640w, /_astro/benchmark-comparison.Btrue9iE_Z1mBN7p.svg 750w, /_astro/benchmark-comparison.Btrue9iE_2cLaQe.svg 828w, /_astro/benchmark-comparison.Btrue9iE_Z1ycOOL.svg 1080w, /_astro/benchmark-comparison.Btrue9iE_Z4lz9b.svg 1200w&quot; /&gt;&lt;figcaption&gt;FP32 benchmark comparison&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;图 2：同一 GPU、同一输入和停止参数下的 7 次中位数。数字只代表这两组矩阵，不用于宣称普遍快于 CuPy/cuSPARSE。&lt;/p&gt;&lt;p&gt;两边 stop code 均为 2，即近似满足最小二乘停止条件。解相对差为 &lt;span&gt;&lt;span&gt;1.84×10−71.84\times10^{-7}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1.84&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 和 &lt;span&gt;&lt;span&gt;6.26×10−76.26\times10^{-7}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;6.26&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。独立重算的相对残差分别为 0.3540266 和 0.2360898，两种实现一致。残差不接近零并非失败：输入是非一致最小二乘系统，应该比较停止语义与残差是否对齐。&lt;/p&gt;&lt;p&gt;性能达到并超过“与 CuPy 基本持平”的目标，但边界必须保留：双格式占用更多 VRAM；当前仅 FP32/int32；无预条件器；消费级 GPU 上的结果不能外推到 A100/H100；不同 CSR 行长分布可能改变 cuSPARSE 占比。若显存不足，回退单格式；若要求逐 bit 确定性，应选择对应 cuSPARSE algorithm 并接受吞吐代价。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;9. 参考资料&lt;a href=&quot;#9-参考资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1006.0758&quot; target=&quot;_blank&quot;&gt;Fong 与 Saunders：LSMR 原始论文&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cupy/cupy/blob/v14.0.0/cupyx/scipy/sparse/linalg/_solve.py&quot; target=&quot;_blank&quot;&gt;CuPy 14.0.0 LSMR 源码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/cuda/archive/12.9.2/cusparse/index.html&quot; target=&quot;_blank&quot;&gt;NVIDIA cuSPARSE 12.9 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oneflow.org/a/share/jishuboke/54.html&quot; target=&quot;_blank&quot;&gt;OneFlow：高效 Softmax CUDA kernel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oneflow.org/a/share/jishuboke/55.html&quot; target=&quot;_blank&quot;&gt;OneFlow：系统设计（下）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/cuda/cuda-programming-guide/04-special-topics/stream-ordered-memory-allocation.html&quot; target=&quot;_blank&quot;&gt;CUDA Programming Guide：显式 memory pool&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>CUDA LSMR 专栏（二）：用 CSR/CSC 双存储压榨双向 SpMV</title><link>https://chengzipai.xyz/posts/cuda-lsmr-dual-sparse/</link><guid isPermaLink="true">https://chengzipai.xyz/posts/cuda-lsmr-dual-sparse/</guid><description>拆解 LSMR 中 A·v 与 Aᵀ·u 的稀疏数据通路，解释 CSR/CSC 双存储、行长负载不均和显存池的收益与代价。</description><pubDate>Mon, 01 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;上一篇把 LSMR 拆成 Solver 与 LinearOperator。这一篇只盯住 Operator 中最贵的两步：&lt;span&gt;&lt;span&gt;AvAv&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 和 &lt;span&gt;&lt;span&gt;ATuA^Tu&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。核心结论很直接：既然每轮都要沿两个方向扫完整个稀疏矩阵，就分别为两个方向准备连续的“行”，而不是让一个格式勉强承担所有访问。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;1. 为什么双向 SpMV 是瓶颈&lt;a href=&quot;#1-为什么双向-spmv-是瓶颈&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;对 &lt;span&gt;&lt;span&gt;A∈Rm×nA\in\mathbb{R}^{m\times n}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，LSMR 每轮各执行一次&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ym=Avn,zn=ATum.y_m=Av_n,\qquad z_n=A^Tu_m.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;z&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;设每个非零值和索引各 4 字节。忽略向量缓存和 offset，一次方向的矩阵读取至少为&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;BSpMV≥(4+4)nnz⁡=8nnz⁡ bytes.B_{\mathrm{SpMV}}\ge (4+4)\operatorname{nnz}=8\operatorname{nnz}\ \text{bytes}.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;SpMV&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≥&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;nnz&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;nnz&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;bytes&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;对应计算量约为 &lt;span&gt;&lt;span&gt;2nnz⁡2\operatorname{nnz}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;nnz&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; FLOP，理想算术强度不超过&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;I≤2nnz⁡8nnz⁡=0.25 FLOP/byte,I\le \frac{2\operatorname{nnz}}{8\operatorname{nnz}}=0.25\ \text{FLOP/byte},&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;I&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≤&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;nnz&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;nnz&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0.25&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;FLOP/byte&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;实际还会更低。于是 roofline 上界首先由显存带宽决定。优化目标不是让每个线程多做几个 FMA，而是让 warp 读取连续的 values/indices、减少无效流量，并避免转置路径产生更差的归约或 scatter 行为。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. CSR、CSC 与精度语义&lt;a href=&quot;#2-csrcsc-与精度语义&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;CSR(A) 由三个数组组成：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;row_ptr&lt;/code&gt; 长度为 &lt;span&gt;&lt;span&gt;m+1m+1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，第 &lt;span&gt;&lt;span&gt;ii&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 行区间是 &lt;code&gt;[row_ptr[i], row_ptr[i+1])&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;col_ind[p]&lt;/code&gt; 给出第 &lt;span&gt;&lt;span&gt;pp&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 个非零元素的列；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;values[p]&lt;/code&gt; 给出其 FP32 数值。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;因此&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(Av)i=∑p=row_ptrirow_ptri+1−1valuesp vcol_indp.(Av)_i=\sum_{p=\mathrm{row\_ptr}_i}^{\mathrm{row\_ptr}_{i+1}-1}
\mathrm{values}_p\,v_{\mathrm{col\_ind}_p}.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;row_ptr&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;∑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;row_ptr&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;values&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;col_ind&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;CSC(A) 则用 &lt;code&gt;col_ptr&lt;/code&gt; 压缩列，&lt;code&gt;row_ind&lt;/code&gt; 保存行号。关键观察是：CSC(A) 的内存结构恰好就是 CSR(&lt;span&gt;&lt;span&gt;ATA^T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)。如果把 descriptor 的尺寸设为 &lt;span&gt;&lt;span&gt;n×mn\times m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，就能直接计算&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;z=ATuz=A^Tu&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;z&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;而不向 cuSPARSE 请求 transpose 操作。&lt;/p&gt;&lt;p&gt;矩阵值、输入、输出和 SpMV compute type 都固定为 FP32。这里没有 half2 或 Tensor Core 路径，因为不规则 SpMV 的主要矛盾是索引与带宽，而且测试输入已经是 FP32；盲目把值降到 FP16 会改变最小二乘系统的条件与停止轨迹。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. 单格式实现的瓶颈&lt;a href=&quot;#3-单格式实现的瓶颈&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;如果只保留 CSC(A)，&lt;span&gt;&lt;span&gt;ATuA^Tu&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 很自然，但 &lt;span&gt;&lt;span&gt;AvAv&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的行归约不再连续；只保留 CSR(A) 则相反。cuSPARSE 支持格式和 transpose 枚举，但官方文档明确指出 transpose 操作没有结果复现保证，而且具体算法的数据路径由库内部决定。&lt;/p&gt;&lt;p&gt;更重要的是，LSMR 不是偶尔做一次转置乘法，而是每轮固定交替两个方向。一次性多存一份矩阵，与每轮承担方向不匹配的代价，属于典型的“空间换稳定热路径”。&lt;/p&gt;&lt;p&gt;朴素的另一项问题是运行时转换：若在每次 &lt;code&gt;A.T @ u&lt;/code&gt; 前生成转置格式，转换成本会直接乘以迭代数。正确边界是在 SparseMatrix 构造时完成一次转换，并让两个 descriptor 随矩阵生命周期存在。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. 双格式数据流&lt;a href=&quot;#4-双格式数据流&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;Dual sparse storage paths&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;680&quot; src=&quot;/_astro/dual-sparse-path.DDb7PqPh_1DP8o.svg&quot; srcset=&quot;/_astro/dual-sparse-path.DDb7PqPh_2joVNd.svg 640w, /_astro/dual-sparse-path.DDb7PqPh_2mOjRP.svg 750w, /_astro/dual-sparse-path.DDb7PqPh_Z25Bc3w.svg 828w, /_astro/dual-sparse-path.DDb7PqPh_uAacS.svg 1080w, /_astro/dual-sparse-path.DDb7PqPh_1DP8o.svg 1200w&quot; /&gt;&lt;figcaption&gt;Dual sparse storage paths&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;图 1：输入无论是 CSC 还是 CSR，构造阶段都补齐另一种格式。求解阶段的两个方向均使用 &lt;code&gt;NON_TRANSPOSE&lt;/code&gt; CSR SpMV。&lt;/p&gt;&lt;p&gt;CSR 到 CSC 使用 &lt;code&gt;cusparseCsr2cscEx2&lt;/code&gt;。CSC 输入可以直接解释成 CSR(&lt;span&gt;&lt;span&gt;ATA^T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)，再把 &lt;span&gt;&lt;span&gt;ATA^T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 从 CSR 转成 CSC；所得 CSC(&lt;span&gt;&lt;span&gt;ATA^T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) 的数组，正好就是 CSR(A)。这个变换只重排一次 values/indices。&lt;/p&gt;&lt;p&gt;双存储的字节代价可近似写成&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Mdual≈2[8nnz⁡+4(m+n+2)].M_{\mathrm{dual}}\approx
2\left[8\operatorname{nnz}+4(m+n+2)\right].&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;dual&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;nnz&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;11kv 的 &lt;span&gt;&lt;span&gt;nnz⁡=19,747,202\operatorname{nnz}=19{,}747{,}202&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;nnz&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;19&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;span&gt;747&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;span&gt;202&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，仅双份 values/indices 已约为 301 MiB；还要为 offset、cuSPARSE workspace、LSMR 向量和内存池物理页留余量。这是明确的成本，不应只谈速度不谈容量。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. 从基础到工业实现&lt;a href=&quot;#5-从基础到工业实现&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;5.1 构造时转换，迭代时只换指针&lt;a href=&quot;#51-构造时转换迭代时只换指针&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cusparseCsr2cscEx2&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;handle, rows, cols, nnz,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;csr_values, csr_offsets, csr_indices,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;csc_values, csc_offsets, csc_indices,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CUDA_R_32F, CUSPARSE_ACTION_NUMERIC,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CUSPARSE_INDEX_BASE_ZERO, CUSPARSE_CSR2CSC_ALG1,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;conversion_workspace);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;构造完成后创建两个 sparse descriptor、四个 dense-vector descriptor，并查询两个方向所需 workspace 的最大值。热路径只调用 &lt;code&gt;cusparseDnVecSetValues&lt;/code&gt; 替换指针，然后发射 SpMV。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.2 用 beta 项吃掉 Golub-Kahan 旧向量&lt;a href=&quot;#52-用-beta-项吃掉-golub-kahan-旧向量&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;前向递推的分子是&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;u←Av−αu.u\leftarrow Av-\alpha u.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;←&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;直接设 &lt;code&gt;alpha=1&lt;/code&gt;、&lt;code&gt;beta=-alpha_k&lt;/code&gt;，让 cuSPARSE 在输出 &lt;code&gt;u&lt;/code&gt; 上完成它，避免生成 &lt;code&gt;Av&lt;/code&gt; 临时向量和一次额外 elementwise kernel。转置方向同理：&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;v←ATu−βv.v\leftarrow A^Tu-\beta v.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;←&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;β&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.3 行长分布决定负载不均&lt;a href=&quot;#53-行长分布决定负载不均&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;CSR 的“连续”不等于“均衡”。若某些行只有几个非零，而另一些行有上万个非零，固定的一行一 warp 会让不同 warp 的工作量严重失衡；短行还会浪费 lane，长行则需要循环和跨 warp 归约。&lt;/p&gt;&lt;p&gt;本项目把通用不规则矩阵交给 &lt;code&gt;CUSPARSE_SPMV_CSR_ALG1&lt;/code&gt;，没有虚构一个自写 kernel 普遍胜过 cuSPARSE。未来可在 Operator dispatch 中统计&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ℓi=row_ptri+1−row_ptri\ell_i=\mathrm{row\_ptr}_{i+1}-\mathrm{row\_ptr}_i&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ℓ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;row_ptr&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;row_ptr&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;的均值、方差和长尾，再为窄分布短行选择专用 warp kernel。机制、适用条件和维护代价必须一起评估。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. SpMV、SpMM 与 shape dispatch&lt;a href=&quot;#6-spmvspmm-与-shape-dispatch&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这里必须区分 SpMV 和 SpMM。单个 LSMR 右端项的 &lt;span&gt;&lt;span&gt;v,uv,u&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 都是向量，核心操作是 SpMV。&lt;code&gt;solve_many&lt;/code&gt; 虽然接受 dense RHS 矩阵，但每一列有自己的 &lt;span&gt;&lt;span&gt;αk,βk\alpha_k,\beta_k&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;β&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;、旋转和停止时刻，当前实现是逐列运行独立 LSMR，并不把它伪装成 SpMM。&lt;/p&gt;&lt;p&gt;真正的 block LSMR 才会让 B/C tile 在多个右端项之间复用：CSR(A) 的 values/indices 读一次，与 &lt;span&gt;&lt;span&gt;V∈Rn×rV\in\mathbb{R}^{n\times r}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;V&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的一小块相乘，形成 &lt;span&gt;&lt;span&gt;U∈Rm×rU\in\mathbb{R}^{m\times r}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;U&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。当 &lt;span&gt;&lt;span&gt;rr&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 足够大时，B tile 的连续列和输出 C tile 提高算术强度；代价是块正交化、更复杂的收敛判断和更大的寄存器/显存工作区。&lt;/p&gt;&lt;p&gt;当前 dispatch 因此保持诚实：&lt;code&gt;r=1&lt;/code&gt; 走 SpMV；多列输入复用内存但逐列求解；未来只有实现块算法后才启用 SpMM。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. 显存池与代码边界&lt;a href=&quot;#7-显存池与代码边界&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;矩阵双存储解决稳定带宽，显存池解决稳定延迟。Context 创建私有 &lt;code&gt;cudaMemPool_t&lt;/code&gt;，所有内部 buffer 都走显式 pool：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cudaMallocFromPoolAsync&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;reinterpret_cast&lt;/span&gt;&lt;span&gt;&amp;lt;void**&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;data), bytes, pool, stream);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;// Destruction remains ordered behind prior work on the same stream.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cudaFreeAsync&lt;/span&gt;&lt;span&gt;(data, stream);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;Stream-ordered memory pool timeline&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;600&quot; src=&quot;/_astro/memory-pool-timeline.CPEqakvp_ZAHNWj.svg&quot; srcset=&quot;/_astro/memory-pool-timeline.CPEqakvp_25Y3Ql.svg 640w, /_astro/memory-pool-timeline.CPEqakvp_ddqNq.svg 750w, /_astro/memory-pool-timeline.CPEqakvp_RjA4p.svg 828w, /_astro/memory-pool-timeline.CPEqakvp_Z6rG4d.svg 1080w, /_astro/memory-pool-timeline.CPEqakvp_ZAHNWj.svg 1200w&quot; /&gt;&lt;figcaption&gt;Stream-ordered memory pool timeline&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;图 2：第一次 shape 扩容向 pool 请求物理页，后续 solve 复用容量；free 也按 stream 排序，不引入 &lt;code&gt;cudaFree&lt;/code&gt; 的全局同步语义。&lt;/p&gt;&lt;p&gt;这与 CuPy 默认 memory pool 的目标相同，但库使用私有 pool，避免修改进程全局默认池。&lt;code&gt;DeviceBuffer::Resize&lt;/code&gt; 仅在新 shape 超过 capacity 时重新申请；迭代循环内没有分配。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;8. 验证、边界与回退&lt;a href=&quot;#8-验证边界与回退&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;双路径测试使用同一个小矩阵，分别从 CSR 和 CSC 构造，比较两个方向与 dense GEMV 的结果。Compute Sanitizer 对 Solver 测试报告 0 个访问错误。真实数据则记录 pool reserved bytes：8kv 约 192 MiB，11kv 约 640 MiB；这是 pool 的物理页保留量，不等于矩阵数组的精确逻辑字节数。&lt;/p&gt;&lt;p&gt;双存储适用于矩阵复用多个迭代、显存充足、两个方向频率相近的场景。如果矩阵只乘一次、转置极少使用，或双份数据会逼近 OOM，应回退为单格式。若索引或 &lt;span&gt;&lt;span&gt;nnz⁡\operatorname{nnz}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;nnz&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 超过 int32 范围，当前 API 会拒绝输入，而不是截断。&lt;/p&gt;&lt;p&gt;下一篇会进入剩余热路径：怎样融合 &lt;span&gt;&lt;span&gt;hˉ/x/h\bar h/x/h&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 递推，以及为什么最终 8kv/11kv 的迭代轨迹能与 CuPy 对齐。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;9. 参考资料&lt;a href=&quot;#9-参考资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/cuda/archive/12.9.2/cusparse/index.html&quot; target=&quot;_blank&quot;&gt;NVIDIA cuSPARSE 12.9：CSR/CSC 与 SpMV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/cuda/cuda-programming-guide/04-special-topics/stream-ordered-memory-allocation.html&quot; target=&quot;_blank&quot;&gt;CUDA Programming Guide：Stream-Ordered Memory Allocator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.nvidia.com/blog/using-cuda-stream-ordered-memory-allocator-part-1/&quot; target=&quot;_blank&quot;&gt;NVIDIA：Using the Stream-Ordered Memory Allocator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oneflow.org/a/share/jishuboke/54.html&quot; target=&quot;_blank&quot;&gt;OneFlow：高效 Softmax CUDA kernel 的带宽分析与 shape 分段&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dlog.com.cn/posts/cuda09/cub/&quot; target=&quot;_blank&quot;&gt;dlog：CUB 归约的分层设计&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>CUDA LSMR 专栏（一）：从迭代公式到分层库架构</title><link>https://chengzipai.xyz/posts/cuda-lsmr-architecture/</link><guid isPermaLink="true">https://chengzipai.xyz/posts/cuda-lsmr-architecture/</guid><description>从 Golub-Kahan 双对角化出发，拆解一个纯 CUDA FP32 LSMR 库的性能上界、接口边界与分层架构。</description><pubDate>Sat, 16 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这组文章记录一个可调用 CUDA LSMR 库的完整实现。第一篇先不急着写 kernel，而是回答三个更根本的问题：LSMR 每轮到底搬了什么数据，哪些变化属于数值算法，哪些变化应该被隔离在矩阵后端，以及怎样让 CSC、CSR 和稠密矩阵共用同一套迭代逻辑。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;1. 问题与性能指标&lt;a href=&quot;#1-问题与性能指标&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;给定 &lt;span&gt;&lt;span&gt;A∈Rm×nA\in\mathbb{R}^{m\times n}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 和 &lt;span&gt;&lt;span&gt;b∈Rmb\in\mathbb{R}^{m}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，LSMR 求解线性系统或最小二乘问题。带阻尼的形式是&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;min⁡x∥[b0]−[AλI]x∥2.\min_x \left\|
\begin{bmatrix}
b\\0
\end{bmatrix}
-
\begin{bmatrix}
A\\\lambda I
\end{bmatrix}x
\right\|_2.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;min&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;λ&lt;/span&gt;&lt;span&gt;I&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;它适合 &lt;span&gt;&lt;span&gt;AA&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 很大、很稀疏，无法显式形成 &lt;span&gt;&lt;span&gt;ATAA^TA&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的场景。每轮主要工作不是复杂标量计算，而是&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Avk,ATuk+1,A v_k,\qquad A^T u_{k+1},&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;外加若干长度为 &lt;span&gt;&lt;span&gt;mm&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 或 &lt;span&gt;&lt;span&gt;nn&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的向量更新与范数归约。若 CSR 的值和列索引都是 4 字节，仅顺序读取矩阵本体，一次 SpMV 至少要读取约 &lt;span&gt;&lt;span&gt;8nnz⁡8\operatorname{nnz}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;nnz&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 字节；每轮前向、转置各一次，因此矩阵流量下界已经接近&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Bmatrix≥16nnz⁡ bytes/iteration.B_{\mathrm{matrix}}\ge 16\operatorname{nnz}\ \text{bytes/iteration}.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;matrix&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≥&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;nnz&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;bytes/iteration&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;这还没有计入 &lt;span&gt;&lt;span&gt;x/yx/y&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 向量、row offset 和缓存未命中。每个非零元素只贡献一次乘加，算术强度很低，LSMR 在大多数非结构稀疏矩阵上首先是显存带宽问题，而不是 FP32 峰值算力问题。&lt;/p&gt;&lt;p&gt;因此本文采用四类指标：迭代数和 stop code 检查算法轨迹；&lt;span&gt;&lt;span&gt;∥Ax−b∥2/∥b∥2\|Ax-b\|_2/\|b\|_2&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;/∥&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 检查结果；单次 solve wall time 衡量端到端迭代开销；矩阵格式与工作区字节数解释显存代价。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. 数学定义与 FP32 语义&lt;a href=&quot;#2-数学定义与-fp32-语义&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;LSMR 基于 Golub-Kahan 双对角化。给定归一化后的 &lt;span&gt;&lt;span&gt;uk,vku_k,v_k&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，核心递推是&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;βk+1uk+1=Avk−αkuk,\beta_{k+1}u_{k+1}=Av_k-\alpha_k u_k,&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;β&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;αk+1vk+1=ATuk+1−βk+1vk.\alpha_{k+1}v_{k+1}=A^Tu_{k+1}-\beta_{k+1}v_k.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;β&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;随后通过一组稳定的对称 Givens 旋转更新 &lt;span&gt;&lt;span&gt;ρ,ρˉ,ζ\rho,\bar\rho,\zeta&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ρ&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ζ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，再更新搜索方向和解：&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;hˉk=hk−θˉkρkρk−1ρˉk−1hˉk−1,\bar h_k=h_k-
\frac{\bar\theta_k\rho_k}{\rho_{k-1}\bar\rho_{k-1}}\bar h_{k-1},&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ρ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ρ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;xk=xk−1+ζkρkρˉkhˉk.x_k=x_{k-1}+\frac{\zeta_k}{\rho_k\bar\rho_k}\bar h_k.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ρ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ζ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;ˉ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;Golub-Kahan data flow&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;620&quot; src=&quot;/_astro/golub-kahan-flow.C6O00CPV_Z1HFbCR.svg&quot; srcset=&quot;/_astro/golub-kahan-flow.C6O00CPV_Zwh9i1.svg 640w, /_astro/golub-kahan-flow.C6O00CPV_1xXrC7.svg 750w, /_astro/golub-kahan-flow.C6O00CPV_1DY8WE.svg 828w, /_astro/golub-kahan-flow.C6O00CPV_zQ47V.svg 1080w, /_astro/golub-kahan-flow.C6O00CPV_Z1HFbCR.svg 1200w&quot; /&gt;&lt;figcaption&gt;Golub-Kahan data flow&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;图 1：一轮 LSMR 的因果链。矩阵后端只负责两个蓝色 SpMV，旋转和停止条件不应知道 A 的存储格式。&lt;/p&gt;&lt;p&gt;库的矩阵、向量、SpMV 累加和输出均为 FP32。范数由 cuBLAS 以 FP32 输入计算，回到 host 后，旋转与停止规则用 double 标量计算，再把向量系数转换为 FP32。这样没有把整个迭代偷偷提升为 FP64，同时降低连续旋转中 host 标量舍入的影响。FP64 不是这组重建输入的默认路径，而且消费级 Ampere 的 FP64 吞吐代价也不适合被忽略。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. 朴素实现为什么不够成为库&lt;a href=&quot;#3-朴素实现为什么不够成为库&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;直接翻译论文或 CuPy 的 Python 循环，可以很快得到正确结果：每轮分别计算 &lt;code&gt;A @ v&lt;/code&gt;、&lt;code&gt;A.T @ u&lt;/code&gt;，再执行缩放、加法和范数。但它有三个工程问题。&lt;/p&gt;&lt;p&gt;第一，算法层直接持有具体稀疏类型时，CSC、CSR 和 dense 会产生分叉，停止规则容易被复制。第二，&lt;code&gt;u *= -alpha; u += A @ v&lt;/code&gt; 会生成临时向量并多走几遍 global memory。第三，矩阵描述符、SpMV workspace 和迭代向量若跟着函数调用反复创建，分配和 Python 调度会进入热路径。&lt;/p&gt;&lt;p&gt;CuPy 的实现仍然是重要基线，因为它公开了清晰的 LSMR 递推和 SciPy 兼容语义；但“参考递推”与“复刻运行时组织”是两件事。库的目标是让数值流程保持可核验，同时把存储、调度和资源复用下沉。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. 分层数据流&lt;a href=&quot;#4-分层数据流&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;Layered CUDA LSMR architecture&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;700&quot; src=&quot;/_astro/lsmr-layered-architecture.wBjZwOUF_Z4lz9b.svg&quot; srcset=&quot;/_astro/lsmr-layered-architecture.wBjZwOUF_febzi.svg 640w, /_astro/lsmr-layered-architecture.wBjZwOUF_Z1mBN7p.svg 750w, /_astro/lsmr-layered-architecture.wBjZwOUF_2cLaQe.svg 828w, /_astro/lsmr-layered-architecture.wBjZwOUF_Z1ycOOL.svg 1080w, /_astro/lsmr-layered-architecture.wBjZwOUF_Z4lz9b.svg 1200w&quot; /&gt;&lt;figcaption&gt;Layered CUDA LSMR architecture&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;图 2：从稳定 API 到 CUDA backend 的单向依赖。上层只依赖能力，下层可以独立更换实现或 dispatch 策略。&lt;/p&gt;&lt;p&gt;这里借鉴 CUB 的思路，不是照搬它的 &lt;code&gt;Device/Dispatch/Agent&lt;/code&gt; 类名，而是保留“接口、策略、执行机制分离”的关键性质：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Public API 定义尺寸、精度、所有权和 host/device 位置。&lt;/li&gt;
&lt;li&gt;Solver 只看 &lt;code&gt;rows()&lt;/code&gt;、&lt;code&gt;cols()&lt;/code&gt;、&lt;span&gt;&lt;span&gt;AxAx&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 和 &lt;span&gt;&lt;span&gt;ATxA^Tx&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;/li&gt;
&lt;li&gt;Operator 根据 sparse/dense 和方向选择 cuSPARSE 或 cuBLAS。&lt;/li&gt;
&lt;li&gt;Runtime 统一管理 stream、handle、显存池和 RAII buffer。&lt;/li&gt;
&lt;li&gt;Kernel 层只放无法由库调用合并的小向量递推。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;OneFlow 的系统设计同样把 Operator、Kernel、DeviceCtx/stream 分开。这个边界对迭代求解器很实用：算法公式是 Operator 级语义，具体 CUDA 调用和异步执行属于 Kernel/runtime 语义。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. 从接口到执行的逐层实现&lt;a href=&quot;#5-从接口到执行的逐层实现&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;5.1 用 LinearOperator 截断格式依赖&lt;a href=&quot;#51-用-linearoperator-截断格式依赖&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LinearOperator&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;public:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;virtual&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;~LinearOperator&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;default&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;virtual&lt;/span&gt;&lt;span&gt; std::&lt;/span&gt;&lt;span&gt;int64_t&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;rows&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;noexcept&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;virtual&lt;/span&gt;&lt;span&gt; std::&lt;/span&gt;&lt;span&gt;int64_t&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;cols&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;noexcept&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;virtual&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;apply_scaled&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;alpha&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float*&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;beta&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                            &lt;/span&gt;&lt;span&gt;float*&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;virtual&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;apply_transpose_scaled&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;alpha&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float*&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;beta&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                                      &lt;/span&gt;&lt;span&gt;float*&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;接口直接暴露 &lt;span&gt;&lt;span&gt;y←αAx+βyy\leftarrow\alpha Ax+\beta y&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;←&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;β&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，而不是只暴露 &lt;span&gt;&lt;span&gt;y=Axy=Ax&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。原因不是追求抽象完整，而是让 Golub-Kahan 分子&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Avk−αkukAv_k-\alpha_k u_k&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;可以直接映射成一次 cuSPARSE/cuBLAS 调用，避免先生成 &lt;code&gt;Av&lt;/code&gt; 再单独读写 &lt;code&gt;u&lt;/code&gt;。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.2 PImpl 隔离 CUDA ABI 细节&lt;a href=&quot;#52-pimpl-隔离-cuda-abi-细节&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;公共头文件不包含 cuSPARSE descriptor 和内部 buffer。&lt;code&gt;Context&lt;/code&gt;、&lt;code&gt;SparseMatrix&lt;/code&gt;、&lt;code&gt;DenseMatrix&lt;/code&gt;、&lt;code&gt;Solver&lt;/code&gt; 都使用 PImpl。这样使用者看到的是稳定 C++17 接口，CUDA 12.9 的描述符字段、算法枚举和 workspace 查询留在 &lt;code&gt;.cu&lt;/code&gt; 实现中。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5.3 Context 是资源边界&lt;a href=&quot;#53-context-是资源边界&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;一个 Context 拥有一个 stream、一对绑定到该 stream 的 cuBLAS/cuSPARSE handle，以及一个私有 stream-ordered memory pool。矩阵和 Solver 引用它，但不各自创建 runtime。这也明确了并发规则：需要并行 stream 时创建多个 Context，而不是让多个 host 线程竞争同一组可变描述符。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. shape、格式与 dispatch&lt;a href=&quot;#6-shape格式与-dispatch&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;当前 dispatch 有三条路径：CSC 输入构造双格式稀疏算子；CSR 输入构造同一种双格式算子；column-major dense 输入构造 cuBLAS 算子。Solver 不需要 &lt;code&gt;if (is_csc)&lt;/code&gt;。&lt;/p&gt;&lt;p&gt;这与 OneFlow Softmax 文章中的 shape 分段思想一致：工业实现不应假定一个 kernel 对所有数据分布都最优。当前版本先按存储类别分派；后续如果加入按行长方差选择 CSR algorithm，或为极短行增加 warp 专用 kernel，也只修改 Operator 层。&lt;/p&gt;&lt;p&gt;代价同样明确：虚函数调用相对一次大 SpMV 可以忽略，但这套接口不适合在 device 内部逐元素调用；双格式存储还会接近翻倍占用矩阵显存。第二篇会单独量化这项交换。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. 关键 CUDA 调用边界&lt;a href=&quot;#7-关键-cuda-调用边界&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;稀疏后端缓存矩阵和 dense-vector descriptor，只在调用前替换输入输出指针：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cusparseDnVecSetValues&lt;/span&gt;&lt;span&gt;(input, &lt;/span&gt;&lt;span&gt;&lt;span&gt;const_cast&lt;/span&gt;&lt;span&gt;&amp;lt;float*&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(x));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cusparseDnVecSetValues&lt;/span&gt;&lt;span&gt;(output, y);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cusparseSpMV&lt;/span&gt;&lt;span&gt;(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;alpha,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;             &lt;/span&gt;&lt;/span&gt;&lt;span&gt;matrix, input, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;beta, output, CUDA_R_32F,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;             &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CUSPARSE_SPMV_CSR_ALG1, workspace);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;描述符和 &lt;code&gt;workspace&lt;/code&gt; 的创建不在迭代循环内。这里选择 &lt;code&gt;CUSPARSE_SPMV_CSR_ALG1&lt;/code&gt; 是当前 CUDA 12.9/FP32 实测路径，而不是承诺所有 GPU 上都最优；cuSPARSE 文档也明确说明高性能算法不保证逐 bit 可复现。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;8. 验证方法、局限与回退&lt;a href=&quot;#8-验证方法局限与回退&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;框架阶段先用一个 &lt;span&gt;&lt;span&gt;3×23\times2&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 矩阵验证 CSC、CSR、dense 三个后端的 &lt;span&gt;&lt;span&gt;AxAx&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 与 &lt;span&gt;&lt;span&gt;ATxA^Tx&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 完全一致，再用同一 Solver 测 dense b、sparse b 和多列 dense RHS。真实 benchmark 则固定 FP32、相同容差、相同最大迭代数，并同时比较 stop code、迭代数、解差与独立残差。&lt;/p&gt;&lt;p&gt;当前边界包括：仅实数 FP32 与 int32 索引；没有预条件器；多 RHS 是复用 workspace 后逐列求解，并非 block LSMR；当双格式超出显存预算时，应回退到单格式和 transpose SpMV，而不是冒险 OOM。&lt;/p&gt;&lt;p&gt;下一篇进入最关键的数据布局：为什么 CSC 输入仍要生成 CSR(A)，以及怎样让 &lt;span&gt;&lt;span&gt;ATuA^Tu&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 也变成顺序行遍历。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;9. 参考资料&lt;a href=&quot;#9-参考资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1006.0758&quot; target=&quot;_blank&quot;&gt;Fong 与 Saunders：LSMR 原始论文&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cupy/cupy/blob/v14.0.0/cupyx/scipy/sparse/linalg/_solve.py&quot; target=&quot;_blank&quot;&gt;CuPy 14.0.0 LSMR 源码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/cuda/archive/12.9.2/cusparse/index.html&quot; target=&quot;_blank&quot;&gt;NVIDIA cuSPARSE 12.9 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dlog.com.cn/posts/cuda09/cub/&quot; target=&quot;_blank&quot;&gt;dlog：CUB 归约的分层设计&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oneflow.org/a/share/jishuboke/55.html&quot; target=&quot;_blank&quot;&gt;OneFlow：系统设计（下）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oneflow.org/a/share/jishuboke/54.html&quot; target=&quot;_blank&quot;&gt;OneFlow：高效 Softmax CUDA kernel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>大模型FCN算子（GEMM）CUDA实现</title><link>https://chengzipai.xyz/posts/llm-fcn-gemm-cuda/</link><guid isPermaLink="true">https://chengzipai.xyz/posts/llm-fcn-gemm-cuda/</guid><description>从标量基线到 Tensor Core、异步流水、低比特缩放和分段调度：构建一个面向大模型全连接层的工业级 GEMM 算子族。</description><pubDate>Wed, 15 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;无论是 Transformer 的 QKV 投影、MLP 的 up/gate/down projection，还是卷积经 im2col 之后的计算，本质上都在反复做同一件事：&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;D=αAB+βC,A∈RM×K, B∈RK×N.D=\alpha AB+\beta C,\qquad
A\in\mathbb R^{M\times K},\ B\in\mathbb R^{K\times N}.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;β&lt;/span&gt;&lt;span&gt;C&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;GEMM 从全局内存到 CTA、warp 与 MMA 指令级分块的数学数据流图&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;620&quot; src=&quot;/_astro/gemm-hierarchical-tiling.w0S9790n_Z1HFbCR.svg&quot; srcset=&quot;/_astro/gemm-hierarchical-tiling.w0S9790n_Zwh9i1.svg 640w, /_astro/gemm-hierarchical-tiling.w0S9790n_1xXrC7.svg 750w, /_astro/gemm-hierarchical-tiling.w0S9790n_1DY8WE.svg 828w, /_astro/gemm-hierarchical-tiling.w0S9790n_zQ47V.svg 1080w, /_astro/gemm-hierarchical-tiling.w0S9790n_Z1HFbCR.svg 1200w&quot; /&gt;&lt;figcaption&gt;GEMM 从全局内存到 CTA、warp 与 MMA 指令级分块的数学数据流图&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;图 1 把一个输出 tile 的计算拆成三个尺度：CTA 负责 &lt;code&gt;BM × BN&lt;/code&gt; 的输出，warp 消费 CTA tile 的子块，MMA 指令只计算其中的 fragment。沿 K 维遍历时，A/B tile 被重复装载与复用，C tile 一直留在寄存器累加。&lt;/p&gt;
&lt;p&gt;GEMM 不是“写三层循环”这么简单。真正难的是：同一套模型会同时遇到 prefill 的大矩阵、decode 的 skinny GEMM、MoE 的不规则 grouped GEMM，以及 FP4/FP8/INT8 到 FP64 的不同数值约束。为某个方形 FP16 shape 跑满，不等于实现了一个可放进框架的 FCN 算子。&lt;/p&gt;
&lt;p&gt;本文沿用一个很实用的讲解顺序：先算清楚性能上界，再从朴素核函数逐层推出分块、访存、流水和 Tensor Core；最后把它们组织成按形状和精度 dispatch 的算子族。这里不虚构某块 GPU 的绝对跑分，所有“最快”的结论都必须在目标 GPU、目标 CUDA 和真实 shape 上重新测量。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;1. 性能目标到底是什么&lt;a href=&quot;#1-性能目标到底是什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;单次 GEMM 的工作量为：&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;FLOPs=2MNK.\text{FLOPs}=2MNK.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;FLOPs&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;运行时间为 &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 时，吞吐为 &lt;span&gt;&lt;span&gt;2MNK/t2MNK/t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。但只报 TFLOP/s 不足以判断 kernel 好坏，因为它还受矩阵是否足够大、是否对齐、是否发生额外读写、launch 开销和数值精度影响。&lt;/p&gt;&lt;p&gt;一个有用的最小模型是 Roofline：&lt;/p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;P≤min⁡(Pcompute peak, I×BWmemory),P\leq\min(P_{\text{compute peak}},\ I\times BW_{\text{memory}}),&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≤&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;min&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;compute peak&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;I&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;span&gt;W&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;memory&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;其中 &lt;span&gt;&lt;span&gt;II&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;I&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 是算术强度。GEMM 通过 tile 复用 A/B 的元素，通常最终受计算单元约束；而小矩阵、skinny GEMM、拆得过细的 epilogue 则可能重新落回带宽或 launch 受限。&lt;/p&gt;&lt;p&gt;因此，“极致优化”不是只看一项指标，而是同时做到：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;A/B 的全局访存合并且对齐；&lt;/li&gt;
&lt;li&gt;shared memory 的布局没有可避免的 bank conflict；&lt;/li&gt;
&lt;li&gt;Tensor Core 或 CUDA Core 持续有数据可算；&lt;/li&gt;
&lt;li&gt;寄存器、shared memory、CTA 数之间保持可接受的 occupancy；&lt;/li&gt;
&lt;li&gt;输出的 bias、activation、residual、量化尽量在同一次写回中完成；&lt;/li&gt;
&lt;li&gt;对不适合主路径的形状及时换 kernel，而不是硬撑。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. 从朴素实现出发：为什么它离峰值很远&lt;a href=&quot;#2-从朴素实现出发为什么它离峰值很远&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;标量 baseline 的逻辑如下：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span&gt;typename&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;__global__ &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;gemm_naive&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; M, &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; N, &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; K,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                           &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; T&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; A, &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; T&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; B, T&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; D) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; m &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockDim&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; n &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockDim&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (m &lt;/span&gt;&lt;span&gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; M &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; n &lt;/span&gt;&lt;span&gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; N) &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; acc &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;0.&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; k &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;; k &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; K; &lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;k)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;acc &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;[m &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; K &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; k]) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;[k &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; N &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; n]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;[m &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; N &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; n] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;(acc);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;它正确，却几乎没有复用：相邻 thread 会重复读取同一行 A 或同一列 B。即使 L1/L2 能帮上一部分忙，数据搬运仍由缓存偶然性决定，无法稳定接近峰值。优化的第一原则就是把“会被多个输出元素使用的数据”显式搬到片上。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. 第一级：CTA tile 与层次化分块&lt;a href=&quot;#3-第一级cta-tile-与层次化分块&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;一个 thread block 计算 &lt;span&gt;&lt;span&gt;DD&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的 &lt;code&gt;BM × BN&lt;/code&gt; tile，并沿 K 每次推进 &lt;code&gt;BK&lt;/code&gt;。数据层级是：&lt;strong&gt;Global A/B → shared-memory A/B tile → warp tile → registers / MMA fragments → D tile&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;在每个 K tile 中，CTA 协作将 A/B 连续搬入 shared memory；之后每个 warp 读取其中一小块，多个输出元素复用同一份数据。关键参数不是“越大越好”：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BM, BN&lt;/code&gt; 越大，A/B 的复用越好，但累加器和 shared memory 也更多；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BK&lt;/code&gt; 太小，循环与同步开销明显；太大则挤占 shared memory、降低常驻 CTA；&lt;/li&gt;
&lt;li&gt;warp tile 决定寄存器 fragment 大小与并行度；&lt;/li&gt;
&lt;li&gt;instruction tile 必须匹配实际架构和 dtype。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;一个正确的调优流程是先枚举少量合理 tile，而不是从无穷多数字中盲猜。以常见矩阵乘数据通路为例：&lt;code&gt;BM/BN&lt;/code&gt; 取 64、128、256 一类，&lt;code&gt;BK&lt;/code&gt; 对 FP16/BF16 常取 32/64，warp tile 与 MMA 指令 tile 对齐；实际值必须让编译器资源报告和 profile 说话。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. 第二级：访存布局比算术更早决定成败&lt;a href=&quot;#4-第二级访存布局比算术更早决定成败&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;4.1 全局内存：连续、对齐、向量化&lt;a href=&quot;#41-全局内存连续对齐向量化&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;线程应协作读取连续地址，使一个 warp 的访问能尽量合并为少量内存事务。对齐满足时，FP32 可使用 &lt;code&gt;float4&lt;/code&gt;，FP16/BF16 可用成对或更宽的 pack；否则必须有独立的尾部路径，不能用未对齐的强制 reinterpret cast 赌运气。&lt;/p&gt;&lt;p&gt;向量化的价值不只是少几条指令，还在于明确表达连续访问。OneFlow 在优化 Softmax 时也把 half 打包成 half2，借助更高的指令吞吐处理成对元素；GEMM 的 A/B 装载同样应把 dtype、对齐和 layout 放入模板/dispatch 条件，而不是散落在 kernel 分支里。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.2 shared memory：布局必须为消费端服务&lt;a href=&quot;#42-shared-memory布局必须为消费端服务&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;shared memory 不是“放进去就快”。若同一 warp 的线程访问同一 bank 的不同地址，会发生 bank conflict，访问被串行化。常见处理方式包括 padding、swizzle，以及按 &lt;code&gt;ldmatrix&lt;/code&gt;/MMA 的消费顺序重排 layout。&lt;/p&gt;&lt;p&gt;尤其需要避免一种误区：全局内存写入连续，并不保证 shared memory 读取也连续。生产实现会分别设计 global-to-shared 和 shared-to-register 的 layout，并在 Nsight Compute 中检查 shared load/store 的冲突指标。OneFlow 对 shared buffer 调整索引顺序以避开 bank conflict 的案例，是这条原则的一个小而典型的例子。&lt;a href=&quot;https://oneflow.org/a/share/jishuboke/54.html&quot; target=&quot;_blank&quot;&gt;OneFlow Softmax CUDA kernel 优化&lt;/a&gt;&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4.3 寄存器：GEMM 的真正工作台&lt;a href=&quot;#43-寄存器gemm-的真正工作台&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;每个 warp 对应的输出 fragment 长时间留在寄存器，只在 K 循环结束后写回全局内存。任何把中间 &lt;code&gt;A×B&lt;/code&gt; partial 频繁写到 global memory、再由下一 kernel 读取的设计，都会直接破坏 GEMM 的算术强度。&lt;/p&gt;&lt;p&gt;不过，寄存器也不是越多越好。过多 accumulator 会导致 spill 或降低 occupancy；对于 decode 的小 M，可能需要 persistent CTA 或更小 tile 来获得足够并发。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. 第三级：让搬运和计算真正重叠&lt;a href=&quot;#5-第三级让搬运和计算真正重叠&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;同步式 tile loop 是“搬 A/B → 等待 → 计算 → 再搬”的串行流程。现代 GPU 的关键是多阶段流水：当 stage &lt;code&gt;s&lt;/code&gt; 的 fragment 正在 MMA 时，stage &lt;code&gt;s+1&lt;/code&gt; 的 A/B tile 已经在路上。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;// stage 0: async copy A0/B0 -&amp;gt; shared&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;// stage 1: async copy A1/B1 -&amp;gt; shared, compute A0 * B0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;// stage 2: async copy A2/B2 -&amp;gt; shared, compute A1 * B1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;在支持的架构上，可用异步 copy 建立双缓冲或多缓冲；再新的数据通路可以由专门的搬运机制和 warp-specialized producer/consumer 组织。核心不在于记住某个 intrinsic 名称，而在于三个不变量：&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;GEMM K 维累加与多阶段流水：下一 tile 搬运和当前 tile 矩阵乘重叠&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;460&quot; src=&quot;/_astro/gemm-k-accumulation-pipeline.ogg1agfV_4RIcG.svg&quot; srcset=&quot;/_astro/gemm-k-accumulation-pipeline.ogg1agfV_Z1IIXXs.svg 640w, /_astro/gemm-k-accumulation-pipeline.ogg1agfV_Zq8UVz.svg 750w, /_astro/gemm-k-accumulation-pipeline.ogg1agfV_2i7Xxk.svg 828w, /_astro/gemm-k-accumulation-pipeline.ogg1agfV_nHiWI.svg 1080w, /_astro/gemm-k-accumulation-pipeline.ogg1agfV_4RIcG.svg 1200w&quot; /&gt;&lt;figcaption&gt;GEMM K 维累加与多阶段流水：下一 tile 搬运和当前 tile 矩阵乘重叠&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;图 2 中的 &lt;code&gt;C_acc&lt;/code&gt; 是同一输出 tile 的寄存器累加器；它只在所有 K tile 完成后才交给 epilogue。双缓冲的目的不是增加计算量，而是让 &lt;code&gt;load(k+1)&lt;/code&gt; 与 &lt;code&gt;MMA(k)&lt;/code&gt; 重叠。&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;consumer 在读取前确认对应 stage 已完成；&lt;/li&gt;
&lt;li&gt;producer 不覆盖仍被消费的 stage；&lt;/li&gt;
&lt;li&gt;stage 数增加带来的 latency hiding，必须大于它对 shared memory 和 occupancy 的代价。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;CUTLASS 把这些策略封装为可组合的 mainloop、collective 和 epilogue，是阅读工业级 GEMM 流水线的好入口；其近代实现还覆盖了 grouped GEMM、FP8、block-scaled 类型与架构专用调度。&lt;a href=&quot;https://github.com/NVIDIA/cutlass&quot; target=&quot;_blank&quot;&gt;NVIDIA CUTLASS&lt;/a&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. Tensor Core 不是一个 dtype 开关&lt;a href=&quot;#6-tensor-core-不是一个-dtype-开关&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Tensor Core 路径的本质是 warp/warp-group 使用特定矩阵乘累加指令，操作 fragment 而非单个标量。要让它工作，至少要同时满足：dtype、矩阵布局、指令 tile、K 对齐和目标计算能力的约束。&lt;/p&gt;&lt;p&gt;典型策略是：主路径处理满足 tile 对齐的大块，边界使用 predicated load/store 或单独的 residue kernel；不要让每一次 MMA 都包在复杂的逐元素边界判断里。对于常见混合精度，输入可以是 FP16/BF16/TF32/FP8，而 accumulator 通常是 FP32；CUDA Programming Guide 明确说明 BF16 WMMA fragment 以 &lt;code&gt;float&lt;/code&gt; 为累加类型，TF32 需要从 FP32 显式转换得到相应语义。&lt;a href=&quot;https://docs.nvidia.com/cuda/cuda-programming-guide/&quot; target=&quot;_blank&quot;&gt;CUDA C++ Programming Guide&lt;/a&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. 精度矩阵：从 INT4/FP4 到 FP64&lt;a href=&quot;#7-精度矩阵从-int4fp4-到-fp64&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;“支持所有精度”不应理解为一个模板把所有类型硬塞进一个指令序列，而是每种精度都有明确的输入、累加、缩放、输出与 fallback 规则。&lt;/p&gt;




















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;输入 A/B&lt;/th&gt;&lt;th&gt;默认累加&lt;/th&gt;&lt;th&gt;典型用途&lt;/th&gt;&lt;th&gt;实现重点&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;INT4 / INT8&lt;/td&gt;&lt;td&gt;INT32 或 FP32&lt;/td&gt;&lt;td&gt;量化推理&lt;/td&gt;&lt;td&gt;per-channel/per-group scale、零点、饱和及反量化 epilogue&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FP4&lt;/td&gt;&lt;td&gt;FP32 或框架指定精度&lt;/td&gt;&lt;td&gt;超低比特推理&lt;/td&gt;&lt;td&gt;block scale 是数据布局的一部分，不是事后乘法&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FP8 E4M3/E5M2&lt;/td&gt;&lt;td&gt;FP32&lt;/td&gt;&lt;td&gt;训练/推理加速&lt;/td&gt;&lt;td&gt;scale、amax 管理、fast-accum 的误差边界&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FP16 / BF16&lt;/td&gt;&lt;td&gt;FP32&lt;/td&gt;&lt;td&gt;训练与通用推理&lt;/td&gt;&lt;td&gt;MMA + FP32 accumulator；BF16 保留更大指数范围&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TF32 语义&lt;/td&gt;&lt;td&gt;FP32&lt;/td&gt;&lt;td&gt;FP32 范围、可接受 reduced mantissa&lt;/td&gt;&lt;td&gt;仅在允许的数值合同下打开&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FP32&lt;/td&gt;&lt;td&gt;FP32&lt;/td&gt;&lt;td&gt;精度基线、敏感算子&lt;/td&gt;&lt;td&gt;CUDA Core 或适配的 tensor 路径，严测误差&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FP64&lt;/td&gt;&lt;td&gt;FP64&lt;/td&gt;&lt;td&gt;科学计算、高精度参考&lt;/td&gt;&lt;td&gt;走目标硬件支持的双精度路径，吞吐/布局另行调优&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;这里有四个容易被忽略的细节：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;存储与累加分离。&lt;/strong&gt; FP16 输入、FP32 累加不是“可选优化”，而应是通用训练的默认数值合同。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缩放粒度属于 ABI。&lt;/strong&gt; INT4/FP4/FP8 的 scale 按 tensor、channel、group 还是 block 存储，会同时决定精度、访存和 kernel layout；必须在 tensor descriptor 中明确。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;K 方向分割会影响数值。&lt;/strong&gt; split-K 改变累加顺序；高精度或可复现模式应采用固定归约树，必要时使用更高精度 partial。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;低比特不等于总更快。&lt;/strong&gt; 若 shape 太小、scale 读取占主导，或需要单独 dequant kernel，端到端速度可能反而下降；理想做法是把 dequant/scale 融合在加载和 epilogue 中。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;当前 CUTLASS 的功能与变更记录展示了 FP8、NVFP4、MX 格式、block scaling 和 sparse/block-scaled GEMM 等路线；它们说明低比特 GEMM 是一套数据布局与调度问题，而不只是把 &lt;code&gt;float&lt;/code&gt; 换成更短的类型。&lt;a href=&quot;https://github.com/NVIDIA/cutlass/blob/main/CHANGELOG.md&quot; target=&quot;_blank&quot;&gt;CUTLASS changelog&lt;/a&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;8. GEMM 不是一种形状：分段 dispatch 才是通用解&lt;a href=&quot;#8-gemm-不是一种形状分段-dispatch-才是通用解&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;和 OneFlow 的分段 Softmax 一样，GEMM 也不存在一个在所有形状上最优的 kernel。一个实用 dispatcher 至少把以下信息作为 key：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;arch&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;dtypeA&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;dtypeB&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;dtypeD&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;accumulator&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;layoutA&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;layoutB&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;layoutD&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;alignmentA&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;alpha&lt;/span&gt;&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;&lt;span&gt;beta&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;epilogue&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;batch&lt;/span&gt;&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;&lt;span&gt;group&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;deterministic&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;workspace&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;limit&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;对应的主路径可这样划分：&lt;/p&gt;







































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;问题特征&lt;/th&gt;&lt;th&gt;优先策略&lt;/th&gt;&lt;th&gt;原因&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;大 M/N/K，整齐对齐&lt;/td&gt;&lt;td&gt;大 CTA tile + 多阶段 Tensor Core pipeline&lt;/td&gt;&lt;td&gt;复用高、可计算饱和&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;M&lt;/code&gt; 很小、decode skinny GEMM&lt;/td&gt;&lt;td&gt;persistent CTA / 更小 tile / grouped GEMM&lt;/td&gt;&lt;td&gt;避免 CTA 不足与 launch 主导&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;K&lt;/code&gt; 极大，M×N tile 不足&lt;/td&gt;&lt;td&gt;split-K 或 Stream-K&lt;/td&gt;&lt;td&gt;增加并行度，随后规约&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;多个小而异形的 GEMM（MoE）&lt;/td&gt;&lt;td&gt;grouped GEMM&lt;/td&gt;&lt;td&gt;合并 launch，动态平衡工作&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;M/N/K 边界不对齐&lt;/td&gt;&lt;td&gt;主 kernel + residue，或 predicate tile&lt;/td&gt;&lt;td&gt;不让边界条件污染内层主循环&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FP32 高精度或 FP64&lt;/td&gt;&lt;td&gt;独立高精度 kernel&lt;/td&gt;&lt;td&gt;不与低精度 Tensor Core 假设混用&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;code&gt;split-K&lt;/code&gt; 并不是免费午餐：它增加 workspace 或原子/归约开销，只有原始网格并行度不足时才值得使用。Stream-K 的意义也正是在 tile 间重新分配 K 工作，缓解固定 tile 调度的不平衡；它应作为 benchmark 候选，而非默认开关。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;9. 一个可维护的 kernel 骨架&lt;a href=&quot;#9-一个可维护的-kernel-骨架&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;生产代码通常不把所有细节塞进 &lt;code&gt;__global__&lt;/code&gt; 函数，而是把策略变为类型和常量。下面是结构示意：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ElementA&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ElementB&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ElementD&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Accumulator&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Tile&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Layout&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Mainloop&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Epilogue&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;GemmKernel&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;__device__ &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;operator&lt;/span&gt;&lt;span&gt;()(&lt;/span&gt;&lt;span&gt;GemmArgs&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// 1. 根据 CTA 坐标取得 D 的 Tile。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// 2. Mainloop: 预取 A/B，管理 pipeline stage，执行 MMA。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// 3. Epilogue: alpha/beta、bias、residual、activation、量化/转换。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// 4. 只写回最终 D。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;GemmPlan&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;make_plan&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;GemmArgs&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// 静态规则先过滤不合法的 dtype/layout/alignment；&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// 查 shape+arch 的 autotune 缓存；缺失时仅 benchmark 少量候选。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这种分层使主循环只关心“如何高复用地计算”，epilogue 只关心“如何生成最终输出”，dispatcher 则对形状做选择。它也让你能把框架的 bias、GELU/SwiGLU、残差、输出量化等融合进去，而不污染 MMA 内层循环。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;10. 融合 epilogue：节省的往往比 MMA 更真实&lt;a href=&quot;#10-融合-epilogue节省的往往比-mma-更真实&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;以 FCN 为例，常见路径是：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;D &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; A &lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt; W&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;Y &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;activation&lt;/span&gt;&lt;span&gt;(D &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; bias)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;若拆成两个 kernel，D 至少经历一次完整的 global write 与一次 global read。把 &lt;code&gt;alpha/beta + bias + activation + cast/quantize&lt;/code&gt; 放在 GEMM epilogue 中，可以让 accumulator fragment 在寄存器中完成最后变换后只写一次 Y。&lt;/p&gt;&lt;p&gt;但融合有边界：复杂 activation、大量额外输入或分支会提高寄存器占用，可能伤害主 GEMM。判断标准永远是端到端 benchmark，而不是“kernel 数量越少越好”。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;11. 如何验证“快”与“对”&lt;a href=&quot;#11-如何验证快与对&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;基准至少应包含 LLM 常见 shape：prefill 的大 M、decode 的 &lt;code&gt;M=1..16&lt;/code&gt;、MLP 的大 N/K、QKV 的非方阵、MoE 的 grouped GEMM，以及难看的不对齐尾部。每项都要记录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;environment&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;GPU/SM、CUDA/驱动、时钟状态&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;problem&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;矩阵 layout、M/N/K、dtype、accumulator&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;timing&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;warmup、重复次数、CUDA event 时间、总时间、TFLOP/s、workspace&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;correctness&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;最大绝对/相对误差、随机种子、确定性模式&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;正确性基准要独立于被测实现：低精度输入可用 FP32 或 FP64 reference 比较，比较容忍度随 dtype 和 K 长度设置；对 FP8/FP4/INT4，额外测 scale 边界、NaN/Inf、饱和、非整齐 K 和 beta 非零。性能分析使用 Nsight Compute 观察 Tensor Core 活跃度、DRAM 吞吐、shared bank conflict、寄存器 spill、occupancy 和 warp stall 原因。&lt;/p&gt;&lt;p&gt;不要只对一个漂亮的 &lt;code&gt;8192×8192×8192&lt;/code&gt; 报数。真正的大模型推理，往往被 decode、短 batch、量化 scale、融合边界和 grouped workload 决定。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;12. 常见的“优化”陷阱&lt;a href=&quot;#12-常见的优化陷阱&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;用一个 tile 打天下。&lt;/strong&gt; 大矩阵最优 tile 在 skinny GEMM 上可能只会浪费线程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无条件加深 pipeline。&lt;/strong&gt; stage 多会占用更多 shared memory，可能使常驻 CTA 下降。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;只测 kernel，不测 epilogue/量化/转换。&lt;/strong&gt; 用户感知的是端到端时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;默认 split-K。&lt;/strong&gt; 没有并行度问题时，额外规约就是纯负担。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;将 TF32/FP8 当作无损 FP32。&lt;/strong&gt; 数值合同必须由模型和测试决定。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;把未对齐指针强转成 vector 类型。&lt;/strong&gt; 这不是优化，是未定义行为风险。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;忽略 launch 开销。&lt;/strong&gt; 对 decode 或小 GEMM，CUDA Graph、grouped/persistent 调度常比更大的 MMA tile 重要。&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;总结&lt;a href=&quot;#总结&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;高性能 GEMM 的路径可以概括为：用 CTA/warp/instruction 三层 tile 建立复用，用对齐向量化和无冲突 shared layout 喂饱计算单元，用异步多阶段流水隐藏搬运延迟，用 Tensor Core 与混合精度匹配硬件能力，最后用 shape-aware dispatch 覆盖大矩阵、skinny、split-K 与 grouped workload。&lt;/p&gt;&lt;p&gt;对于大模型 FCN，真正可上线的版本还必须把 FP4/INT4、FP8、FP16/BF16、TF32、FP32、FP64 的数值合同和 fallback 写清楚，并把 bias/activation/quantize 融进合适的 epilogue。所谓“极致优化”，从来不是某个花哨 intrinsic，而是一套在真实输入、真实数值约束和真实硬件上持续测得最快的系统工程。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;参考资料&lt;a href=&quot;#参考资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dlog.com.cn/posts/cuda11/matmul/&quot; target=&quot;_blank&quot;&gt;dlog：CUDA学习之路[11]：矩阵乘法计算详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://oneflow.org/a/share/jishuboke/54.html&quot; target=&quot;_blank&quot;&gt;OneFlow：如何实现一个高效的 Softmax CUDA kernel？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/NVIDIA/cutlass&quot; target=&quot;_blank&quot;&gt;NVIDIA CUTLASS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/NVIDIA/cutlass/blob/main/CHANGELOG.md&quot; target=&quot;_blank&quot;&gt;CUTLASS 变更记录&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/cuda/cuda-programming-guide/&quot; target=&quot;_blank&quot;&gt;CUDA C++ Programming Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>通用稀疏矩阵乘法CUDA算子实现</title><link>https://chengzipai.xyz/posts/universal-sparse-matmul-cuda/</link><guid isPermaLink="true">https://chengzipai.xyz/posts/universal-sparse-matmul-cuda/</guid><description>从 CSR/COO 的 SpMV，到面向多右端项的 SpMM：格式、线程映射、精度策略和自适应调度如何共同决定稀疏算子的上限。</description><pubDate>Sun, 05 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;稠密矩阵乘法的优化，核心是在有限的片上存储里尽可能多地复用数据；稀疏矩阵乘法却刚好相反：数据位置是不规则的、每一行工作量不相同，算术强度往往又低得可怜。把一个稠密 GEMM 的 tile 套到 CSR 上，通常只会得到一个更复杂、更慢的 kernel。&lt;/p&gt;
&lt;p&gt;本文把稀疏矩阵乘法拆为两个最常见的算子：&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;y=Ax(SpMV),C=AB(SpMM).y=Ax\quad\text{(SpMV)},\qquad C=AB\quad\text{(SpMM)}.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(SpMV)&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;C&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(SpMM)&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;CSR 格式的单行 SpMV：行偏移确定非零段，warp lane 分担 gather 与 shuffle 归约&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;590&quot; src=&quot;/_astro/csr-spmv-warp-reduction.BSmgI8IO_1toXSW.svg&quot; srcset=&quot;/_astro/csr-spmv-warp-reduction.BSmgI8IO_1mHws3.svg 640w, /_astro/csr-spmv-warp-reduction.BSmgI8IO_32mkz.svg 750w, /_astro/csr-spmv-warp-reduction.BSmgI8IO_1gdXw0.svg 828w, /_astro/csr-spmv-warp-reduction.BSmgI8IO_UriW7.svg 1080w, /_astro/csr-spmv-warp-reduction.BSmgI8IO_1toXSW.svg 1200w&quot; /&gt;&lt;figcaption&gt;CSR 格式的单行 SpMV：行偏移确定非零段，warp lane 分担 gather 与 shuffle 归约&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;图 1 展示 CSR SpMV 的基本数学映射：&lt;code&gt;row_offsets[i:i+1]&lt;/code&gt; 给出第 i 行的非零元区间；warp 的各 lane 并行计算部分和，最后只在 warp 内做 shuffle 归约并写出一个 &lt;span&gt;&lt;span&gt;yiy_i&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。这也是短行不需要 shared memory 的原因。&lt;/p&gt;
&lt;p&gt;其中 &lt;span&gt;&lt;span&gt;A∈RM×KA\in\mathbb R^{M\times K}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 为稀疏矩阵，&lt;span&gt;&lt;span&gt;x∈RKx\in\mathbb R^K&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，&lt;span&gt;&lt;span&gt;B∈RK×NB\in\mathbb R^{K\times N}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。目标不是制造一个“万能 kernel”，而是搭建一个&lt;strong&gt;按稀疏格式、行长度分布、右端项宽度和精度自动选路的算子族&lt;/strong&gt;。这才是工业框架中通用稀疏算子的正确打开方式。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;先说结论：稀疏优化是在和不规则性谈判&lt;a href=&quot;#先说结论稀疏优化是在和不规则性谈判&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;假设 CSR 有 &lt;code&gt;nnz&lt;/code&gt; 个非零元。一次 FP32 SpMV 至少要读取 value、column index、向量元素，并写回一个结果。即便不计缓存未命中，浮点运算也只有大约 &lt;code&gt;2 * nnz&lt;/code&gt; 次；相对于数据移动，它天生接近带宽受限。&lt;/p&gt;&lt;p&gt;SpMM 的情况更好。每读取一次 &lt;span&gt;&lt;span&gt;AikA_{ik}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ik&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，可以把 &lt;span&gt;&lt;span&gt;Bk,:B_{k,:}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的一段复用到多个输出列，&lt;span&gt;&lt;span&gt;NN&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 越大，计算与访存的比值越高。因此下面三条是全文的主线：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;格式要服从结构。&lt;/strong&gt; COO 方便构造，CSR 适合行方向 SpMV/SpMM，BSR/Blocked-ELL 才有机会把结构化块交给 Tensor Core；不能把格式转换的代价藏起来。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;线程映射要服从行长度。&lt;/strong&gt; 一 warp 一行、一个 CTA 一行、一个 CTA 多行、长行分段，适用的行长度区间完全不同。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调度要服从问题本身。&lt;/strong&gt; 平均 &lt;code&gt;nnz/row&lt;/code&gt; 不够，方差、P99 行长、列索引局部性、&lt;code&gt;N&lt;/code&gt;、dtype、对齐和 batch 都是 dispatch key。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;这也是 OneFlow 优化 Softmax 时最值得借鉴的思想：不是执着于一种实现，而是按形状分段，利用寄存器、shared memory、warp 原语和占用率约束选择真正可启动、可跑满的方案。不同的是，稀疏场景的“形状”还多了稀疏模式本身。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;1. 数据格式不是文件格式，而是执行计划&lt;a href=&quot;#1-数据格式不是文件格式而是执行计划&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;1.1 CSR：默认主路径&lt;a href=&quot;#11-csr默认主路径&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;CSR 使用三段数组：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;row_offsets&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;M + 1&lt;/span&gt;&lt;span&gt;]        &lt;/span&gt;&lt;span&gt;第 i 行位于 [row_offsets[i], row_offsets[i+1])&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;col_indices&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;nnz&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;values&lt;/span&gt;&lt;span&gt;:      [&lt;/span&gt;&lt;span&gt;nnz&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;它的好处是同一行的 value 与 index 连续，天然适合输出按行写回；缺点是行长可能极不均衡。绝大多数“普通稀疏”输入先进入 CSR 主路径，基准实现也应先从它开始。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;1.2 COO：输入友好，执行不应死守 COO&lt;a href=&quot;#12-coo输入友好执行不应死守-coo&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;COO 的 &lt;code&gt;(row, col, value)&lt;/code&gt; 三元组适合图边列表、动态 append 和分块拼接，但随机写回 &lt;code&gt;y[row]&lt;/code&gt; 往往需要原子操作。对于静态矩阵，预处理成按 &lt;code&gt;(row, col)&lt;/code&gt; 排序的 CSR；对于在线构造的 COO，采用 &lt;code&gt;warp-aggregated atomic&lt;/code&gt; 或分段归约，并把转换成本单独计入 benchmark。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;1.3 BSR / Blocked-ELL：为块结构准备的快速通道&lt;a href=&quot;#13-bsr--blocked-ell为块结构准备的快速通道&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;当非零元以 &lt;span&gt;&lt;span&gt;br×bcb_r\times b_c&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;r&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 小块出现时，BSR 把一个索引摊薄到一个稠密小块上。对于固定块、固定宽度模型层，它不仅降低 index 开销，还能让块内计算变得规整。Blocked-ELL 则在每个 block-row 中填充等数量的块，适合块分布较均匀的结构化稀疏。&lt;/p&gt;&lt;p&gt;请注意：&lt;strong&gt;通用非结构化 CSR 不能直接获得 Tensor Core 加速。&lt;/strong&gt; 需要 BSR、2:4 structured sparsity 或其它满足硬件约束的布局；否则所谓“Tensor Core 稀疏加速”通常只是营销话术。cuSPARSE 的通用接口也把 COO、CSR、Blocked-ELL 明确区分为不同格式与算法路径。&lt;a href=&quot;https://docs.nvidia.com/cuda/cusparse/storage-formats.html&quot; target=&quot;_blank&quot;&gt;NVIDIA cuSPARSE 格式文档&lt;/a&gt;&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;1.4 SELL-C-&lt;span&gt;&lt;span&gt;σ\sigma&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;σ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;：用可控填充换取规则访存&lt;a href=&quot;#14-sell-c-σsigmaσ用可控填充换取规则访存&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;对行长差异很大但行可重排的矩阵，可在长度相近的窗口 &lt;span&gt;&lt;span&gt;σ\sigma&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;σ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 内排序，再把每 &lt;span&gt;&lt;span&gt;CC&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;C&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 行切成切片。SELL 牺牲少量 padding，换得同一 warp 跨行访问的连续性。它很适合短行图数据或有限元网格；但若行重排会破坏外部语义或 padding 比例太高，就应回退到 CSR。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;2. SpMV：把一行的归约做对&lt;a href=&quot;#2-spmv把一行的归约做对&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;2.1 朴素版本为什么不够&lt;a href=&quot;#21-朴素版本为什么不够&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;一个 thread 负责一整行，逻辑最简单：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; p &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;row_offsets&lt;/span&gt;&lt;span&gt;[row]; p &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;row_offsets&lt;/span&gt;&lt;span&gt;[row &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;]; &lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;p)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;sum &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;values&lt;/span&gt;&lt;span&gt;[p] &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;col_indices&lt;/span&gt;&lt;span&gt;[p]];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;[row] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; sum;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;但行长超过几十时，一个 thread 串行读取，延迟无法隐藏；行长很短时，又会浪费一个 block 中的大量线程。优化的第一步不是上 shared memory，而是给一行匹配合适的并行粒度。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2.2 短行：一个 warp 处理一行&lt;a href=&quot;#22-短行一个-warp-处理一行&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;当 &lt;code&gt;nnz_per_row&lt;/code&gt; 大致不超过 32 或 64，最自然的映射是一个 warp 一行。lane &lt;code&gt;t&lt;/code&gt; 处理 &lt;code&gt;p = begin + t, begin + t + 32, ...&lt;/code&gt;，最后用 shuffle 做树形归约：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span&gt;typename&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;typename&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Acc&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;__device__ __forceinline__ Acc &lt;/span&gt;&lt;span&gt;warp_sum&lt;/span&gt;&lt;span&gt;(Acc v) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;#pragma&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unroll&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; delta &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;; delta &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;; delta &lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;__shfl_down_sync&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;0x&lt;/span&gt;&lt;span&gt;ffffffff&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, v, delta);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; v;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span&gt;typename&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;typename&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Acc&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WARPS_PER_CTA&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;__global__ &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;csr_spmv_warp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int*&lt;/span&gt;&lt;span&gt; __restrict__ row_offsets,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                              &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int*&lt;/span&gt;&lt;span&gt; __restrict__ col_indices,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                              &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; __restrict__ values,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                              &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; __restrict__ x,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                              &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; __restrict__ y, &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; m) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; lane &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;31&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; warp &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; row &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;blockIdx&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; WARPS_PER_CTA) &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; warp;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (row &lt;/span&gt;&lt;span&gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; m) &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Acc sum &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Acc&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; p &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;row_offsets&lt;/span&gt;&lt;span&gt;[row] &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; lane; p &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;row_offsets&lt;/span&gt;&lt;span&gt;[row &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;]; p &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;sum &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;static_cast&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Acc&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;values&lt;/span&gt;&lt;span&gt;[p]) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;static_cast&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Acc&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;col_indices&lt;/span&gt;&lt;span&gt;[p]]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;sum &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;warp_sum&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;Acc&lt;/span&gt;&lt;span&gt;&amp;gt;(sum);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (lane &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;[row] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;static_cast&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;(sum);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这里没有 &lt;code&gt;__syncthreads()&lt;/code&gt;，也没有 shared memory。warp 内 shuffle 比 block 归约更轻，且多 warp CTA 可以同时服务多行，是短行 SpMV 的第一选择。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2.3 中长行：一个 CTA 一行，但不要盲目增大 block&lt;a href=&quot;#23-中长行一个-cta-一行但不要盲目增大-block&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;当行长达到几百或几千，一个 warp 不够。可以用 128/256/512 threads 的 CTA 处理一行：每个 warp 局部归约，warp 0 再归约 warp sums。block size 不能写死：它同时影响每个 SM 的常驻 CTA 数、寄存器压力和同步点的空闲时间。&lt;/p&gt;&lt;p&gt;实践中应在初始化阶段对候选 &lt;code&gt;128, 256, 512&lt;/code&gt; 查询 occupancy，结合行长区间选择；这和 OneFlow 在 block reduce 中用可启动 CTA 数约束 block size 的思路一致。对于很长的一行，CTA 数太少也会让整个 GPU 吃不饱。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2.4 超长行：分段，再归并&lt;a href=&quot;#24-超长行分段再归并&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;一条 10 万非零元的行不能只分配一个 CTA。把它切成 &lt;code&gt;SEGMENT_NNZ&lt;/code&gt; 的 segment，每个 CTA 输出一个 partial sum，第二个小 kernel 再归约；若只允许一次 launch，则对同一行做 &lt;code&gt;atomicAdd&lt;/code&gt;，但需评估原子竞争。典型选择是：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;极少数长行：partial buffer + 第二阶段归约，性能更稳定；&lt;/li&gt;
&lt;li&gt;多数行都超长：直接按 tile 设计 CTA-per-segment，避免“行”成为唯一调度单位；&lt;/li&gt;
&lt;li&gt;结果对严格可复现敏感：不要使用浮点 atomic 作为默认路径，固定二叉归约顺序。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2.5 索引访问的现实&lt;a href=&quot;#25-索引访问的现实&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;values[p]&lt;/code&gt; 和 &lt;code&gt;col_indices[p]&lt;/code&gt; 连续，容易合并；&lt;code&gt;x[col_indices[p]]&lt;/code&gt; 却是 gather。可做的优化包括行内列排序、对热点向量使用只读缓存语义、预取下一批 index/value、以及把索引压缩为 32-bit（维度允许时）。但不要把 &lt;code&gt;__ldg&lt;/code&gt; 当魔法：随机列、工作集远大于 L2 时，主要瓶颈仍然是 DRAM 延迟。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;3. SpMM：右端项宽度改变了一切&lt;a href=&quot;#3-spmm右端项宽度改变了一切&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;SpMM 计算 &lt;span&gt;&lt;span&gt;Ci,n=∑k∈N(i)Ai,kBk,nC_{i,n}=\sum_{k\in\mathcal N(i)}A_{i,k}B_{k,n}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;C&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;∑&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;∈&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。同一个 &lt;code&gt;A[i,k]&lt;/code&gt; 可用于 &lt;code&gt;N_TILE&lt;/code&gt; 个列，因而可以把 &lt;span&gt;&lt;span&gt;BB&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的连续列放入寄存器累加：&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img alt=&quot;CSR SpMM 中一个稀疏值复用一段连续的 B 行，形成多个输出列累加器&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;510&quot; src=&quot;/_astro/csr-spmm-reuse.BozF1QZi_Q2jNf.svg&quot; srcset=&quot;/_astro/csr-spmm-reuse.BozF1QZi_Z1aMJ3W.svg 640w, /_astro/csr-spmm-reuse.BozF1QZi_dvQPi.svg 750w, /_astro/csr-spmm-reuse.BozF1QZi_1T4n4N.svg 828w, /_astro/csr-spmm-reuse.BozF1QZi_Z20FUT7.svg 1080w, /_astro/csr-spmm-reuse.BozF1QZi_Q2jNf.svg 1200w&quot; /&gt;&lt;figcaption&gt;CSR SpMM 中一个稀疏值复用一段连续的 B 行，形成多个输出列累加器&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;图 2 的关键差别在于右端项不再是一个标量：一次读取 &lt;span&gt;&lt;span&gt;Ai,kA_{i,k}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 后，连续的 &lt;span&gt;&lt;span&gt;Bk,n:n+NtileB_{k,n:n+N_{tile}}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 同时更新多个寄存器累加器，因而将 index 与稀疏 value 的读取开销摊薄到多个输出列。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;span&gt;typename&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;typename&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Acc&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;N_TILE&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;__global__ &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;csr_spmm_row_tile&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/* CSR A, dense B, dense C */&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// 一个 CTA 可处理一行或一组短行；每个 warp 持有若干输出列。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// 对每个 A(i,k)，协作读取连续的 B(k, n:n+N_TILE)，&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// 以 Acc 累加到寄存器 fragments，最后一次性写 C。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;真正的实现不能只写这个空壳，至少还需要下面四层策略。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;3.1 &lt;code&gt;N&lt;/code&gt; 很小：沿行并行，避免寄存器爆炸&lt;a href=&quot;#31-n-很小沿行并行避免寄存器爆炸&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;N=1&lt;/code&gt; 就是 SpMV；&lt;code&gt;N=2/4/8&lt;/code&gt; 时每线程持有的 accumulator 很少，应优先沿 &lt;code&gt;nnz&lt;/code&gt; 方向协作，把 CTA 的线程给长行。若仍强行让一个 thread 存很多 &lt;code&gt;C&lt;/code&gt; 的列，寄存器压力会降低 occupancy，得不偿失。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.2 &lt;code&gt;N&lt;/code&gt; 中等：一 warp 一行 × 一列 tile&lt;a href=&quot;#32-n-中等一-warp-一行--一列-tile&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;当 &lt;code&gt;N=16..128&lt;/code&gt;，每个 warp 处理一行和一个连续 &lt;code&gt;N_TILE&lt;/code&gt;。&lt;code&gt;B[k, n:n+N_TILE]&lt;/code&gt; 是连续的，适合 &lt;code&gt;half2&lt;/code&gt;、&lt;code&gt;float4&lt;/code&gt; 或 &lt;code&gt;int4&lt;/code&gt; 风格的向量化 load；累加 fragment 放寄存器。每个非零元的 index 开销被多个输出列分摊，这是 CSR SpMM 最常见的甜点区。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.3 &lt;code&gt;N&lt;/code&gt; 很大：二维 CTA 与 CTA-per-row-group&lt;a href=&quot;#33-n-很大二维-cta-与-cta-per-row-group&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;N&lt;/code&gt; 很大时，单个 CTA 负责一行会产生太多输出列。把 &lt;code&gt;N&lt;/code&gt; 分块，并让 CTA 负责 &lt;code&gt;(row_group, n_tile)&lt;/code&gt;；短行合并成 row group，长行独占多个 CTA。此处必须保证 C 的写回是唯一所有者，或明确安排 reduction 阶段，避免无意义的原子累加。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.4 块稀疏：才值得谈 Tensor Core&lt;a href=&quot;#34-块稀疏才值得谈-tensor-core&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;对 BSR，外层遍历非零 block，内层是小型稠密 GEMM。此时可以：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;将 A block、B tile 异步搬到 shared memory；&lt;/li&gt;
&lt;li&gt;以 &lt;code&gt;ldmatrix&lt;/code&gt;/fragment 组织矩阵片段；&lt;/li&gt;
&lt;li&gt;使用适配架构的 WMMA/MMA/WGMMA 指令；&lt;/li&gt;
&lt;li&gt;用双缓冲或多阶段流水重叠搬运和计算。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;如果稀疏模式满足硬件支持的 2:4 结构化规则，也可进入专用稀疏 Tensor Core 路径。CUTLASS 已提供 dense、block-sparse、grouped GEMM 等可组合的参考实现；它是研究 tile 布局与流水线的好教材，但上线时仍要在目标 GPU 和实际形状上 profile。&lt;a href=&quot;https://github.com/NVIDIA/cutlass&quot; target=&quot;_blank&quot;&gt;CUTLASS 文档&lt;/a&gt;&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;4. 一个真正通用的 dispatch 设计&lt;a href=&quot;#4-一个真正通用的-dispatch-设计&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;把所有情况塞进模板参数会造成编译爆炸；反过来，运行时每一步动态判断也会拖慢热路径。一个平衡的设计是：首次见到矩阵时提取轻量 profile，构造稳定的 dispatch key。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;format&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;dtype&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;index_width&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;M&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;K&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;avg_nnz&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;p95_nnz&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;max_nnz&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;row_length_cv&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;sorted_columns&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;block_shape&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;alignment&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;arch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;建议的规则表如下。&lt;/p&gt;












































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;首选实现&lt;/th&gt;&lt;th&gt;退化/备注&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;CSR，短行，&lt;code&gt;N=1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;warp-per-row SpMV&lt;/td&gt;&lt;td&gt;多 warp/CTA，shuffle 归约&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CSR，长行，&lt;code&gt;N=1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;CTA-per-row 或 segmented SpMV&lt;/td&gt;&lt;td&gt;极长行走 partial reduction&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CSR，&lt;code&gt;N=8..128&lt;/code&gt;&lt;/td&gt;&lt;td&gt;row × N-tile SpMM&lt;/td&gt;&lt;td&gt;B 连续列寄存器化&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CSR，短行占多数且方差大&lt;/td&gt;&lt;td&gt;SELL 或 CTA-per-row-group&lt;/td&gt;&lt;td&gt;先检查 padding 成本&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BSR / Blocked-ELL&lt;/td&gt;&lt;td&gt;block sparse SpMM&lt;/td&gt;&lt;td&gt;可选择 Tensor Core 路径&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;COO，动态输入&lt;/td&gt;&lt;td&gt;COO segmented / warp atomic&lt;/td&gt;&lt;td&gt;后台合并为 CSR&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;nnz/(M*K)&lt;/code&gt; 接近稠密&lt;/td&gt;&lt;td&gt;稠密 GEMM&lt;/td&gt;&lt;td&gt;转换后直接走 GEMM 常更快&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;首次 profile 可以缓存到矩阵 descriptor；动态稀疏矩阵则按版本号失效缓存。对线上模型，再加一个小型 autotune：只在候选的 2~4 个 kernel 中用 CUDA event 测量，缓存最快配置，绝不在每次调用都 benchmark。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;5. 从低精度到高精度：存储精度和累加精度必须分开&lt;a href=&quot;#5-从低精度到高精度存储精度和累加精度必须分开&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;














































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;A/B 存储&lt;/th&gt;&lt;th&gt;建议累加&lt;/th&gt;&lt;th&gt;适用场景&lt;/th&gt;&lt;th&gt;要点&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;INT8&lt;/td&gt;&lt;td&gt;INT32 / FP32&lt;/td&gt;&lt;td&gt;量化推理&lt;/td&gt;&lt;td&gt;scale 可按 tensor、channel 或 block；先定义溢出策略&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FP8 / INT4&lt;/td&gt;&lt;td&gt;FP32（或按误差预算）&lt;/td&gt;&lt;td&gt;低比特推理、块稀疏&lt;/td&gt;&lt;td&gt;scale 元数据必须随 block 布局一起设计&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FP16 / BF16&lt;/td&gt;&lt;td&gt;FP32&lt;/td&gt;&lt;td&gt;训练与常规推理&lt;/td&gt;&lt;td&gt;&lt;code&gt;half2&lt;/code&gt;/BF16 向量化；不要用 FP16 累加替代 FP32 默认值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TF32 输入语义&lt;/td&gt;&lt;td&gt;FP32&lt;/td&gt;&lt;td&gt;FP32 范围、可放宽 mantissa&lt;/td&gt;&lt;td&gt;仅在架构与数值约束满足时启用&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FP32&lt;/td&gt;&lt;td&gt;FP32&lt;/td&gt;&lt;td&gt;基准与高精度主路径&lt;/td&gt;&lt;td&gt;行内规约顺序影响 bitwise 一致性&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FP64&lt;/td&gt;&lt;td&gt;FP64&lt;/td&gt;&lt;td&gt;科学计算&lt;/td&gt;&lt;td&gt;通常更受带宽和较低双精度吞吐约束&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;对 SpMV，低精度不一定自动更快：index 和随机 &lt;code&gt;x&lt;/code&gt; gather 仍是固定成本，value 减半却不等于端到端时间减半。对块稀疏 SpMM，低精度更有价值，因为它能减轻 A/B tile 搬运并匹配矩阵乘指令。所有低精度路径都应以更高精度 reference 校验，并报告相对误差、最大误差与是否允许非确定性。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;6. 框架级融合与内存管理&lt;a href=&quot;#6-框架级融合与内存管理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;稀疏算子常常位于 &lt;code&gt;SpMM + bias + activation&lt;/code&gt;、消息传递聚合、embedding 聚合或 attention 的投影附近。若中间张量会立即被消费，融合 epilogue 可以少一次 C 的全局内存往返。但融合的边界要克制：过多分支会增加寄存器占用，导致主 kernel 降速。&lt;/p&gt;&lt;p&gt;工程上建议把算子拆为：&lt;/p&gt;&lt;p&gt;执行链为：&lt;strong&gt;descriptor/profile → format conversion/cache → dispatch → main kernel → optional reduction → optional fused epilogue&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;所有临时缓冲区通过框架 allocator 或 stream-ordered memory pool 管理；不要在每次 SpMV/SpMM 调用中 &lt;code&gt;cudaMalloc&lt;/code&gt;。同样，不要为了一次调用把 CSR 无条件转换成 BSR——格式转换要么被长期复用，要么本身就是亏损交易。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;7. 性能与正确性要一起测&lt;a href=&quot;#7-性能与正确性要一起测&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;不要只报“GFlop/s”。稀疏计算里名义 FLOPs 容易掩盖填充、格式转换和原子冲突。推荐至少输出：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;matrix&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;M、K、nnz、density、avg/p95/max nnz per row、格式&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;operator&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;SpMV/SpMM、N、dtype、index width、是否排序、是否转换&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;performance&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;端到端时间、kernel 时间、转换摊销时间、有效带宽、有效 GFLOP/s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;correctness&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;相对 FP64/FP32 reference 的 atol/rtol、最大误差、确定性&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;environment&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;GPU、SM、CUDA、驱动、时钟策略、warmup/重复次数&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;有效带宽可用“实际读写字节 / kernel 时间”估算，但请明确它是否包含 index、输出、partial buffer 和格式转换。用 Nsight Compute 观察 &lt;code&gt;dram__throughput&lt;/code&gt;、warp 执行效率、寄存器数、occupancy、L2 命中和长行 kernel 的负载均衡；这比猜测某个 intrinsic 是否“更快”可靠得多。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;8. 常见误区&lt;a href=&quot;#8-常见误区&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;“CSR + Tensor Core”&lt;/strong&gt;：CSR 本身不提供规则的矩阵片段；需要 BSR 或受支持的结构化稀疏。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“行越长 block 越大”&lt;/strong&gt;：大 block 可能减少常驻 CTA，并增加同步停顿；应以 profile 和 occupancy 选取。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“FP16 一定两倍快”&lt;/strong&gt;：SpMV 常受 index 和随机 gather 限制，低精度收益可能很小。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“COO atomic 总能接受”&lt;/strong&gt;：高冲突行会让 atomic 成为串行点；分段归约更可控。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“格式转换免费”&lt;/strong&gt;：一次性矩阵转换很可能比计算本身还贵。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“只用平均行长做选择”&lt;/strong&gt;：同样平均值的均匀矩阵与幂律图，最优 kernel 可以完全不同。&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;总结&lt;a href=&quot;#总结&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;稀疏矩阵乘法没有一个能统治所有输入的 kernel。可维护、高性能的实现应该把问题拆成三件事：用 descriptor 识别结构，用 format 和线程映射承接结构，用 dispatch/autotune 选择实测最快的实现。&lt;/p&gt;&lt;p&gt;对 &lt;code&gt;SpMV&lt;/code&gt;，核心是让每一行获得恰当的 warp/CTA/segment 粒度；对 &lt;code&gt;SpMM&lt;/code&gt;，核心是借助右端项宽度提高复用，并在块结构存在时才进入 Tensor Core 路径。把格式转换、精度、确定性和 benchmark 口径都放进设计，才是“通用”二字真正的含义。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;参考资料&lt;a href=&quot;#参考资料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://oneflow.org/a/share/jishuboke/54.html&quot; target=&quot;_blank&quot;&gt;OneFlow：如何实现一个高效的 Softmax CUDA kernel？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/cuda/cusparse/generic-api/sparse-matrix.html&quot; target=&quot;_blank&quot;&gt;NVIDIA cuSPARSE：Sparse Matrix APIs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/cuda/cusparse/storage-formats.html&quot; target=&quot;_blank&quot;&gt;NVIDIA cuSPARSE：Storage Formats&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/NVIDIA/cutlass&quot; target=&quot;_blank&quot;&gt;NVIDIA CUTLASS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/cuda/cuda-programming-guide/&quot; target=&quot;_blank&quot;&gt;CUDA C++ Programming Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>使用CUDA实现并极致优化softmax</title><link>https://chengzipai.xyz/posts/draft/</link><guid isPermaLink="true">https://chengzipai.xyz/posts/draft/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h1&gt;这篇文章是草稿&lt;a href=&quot;#这篇文章是草稿&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;这篇文章目前处于草稿状态，尚未发布。因此，它不会对普通读者可见。内容仍在进行中，可能需要进一步编辑和审查。&lt;/p&gt;&lt;p&gt;当文章准备发布时，您可以在 Frontmatter 中将 “draft” 字段更新为 “false”：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;草稿示例&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;published&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;2024-01-11T04:40:26.381Z&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;tags&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;Markdown&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;博客&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;演示&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;category&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;示例&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;draft&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;</content:encoded></item></channel></rss>