一种 DeepSeek V3.2 的融合算子策略的尝试

Oct 13, 2026

English version

代码:EdgePro001/FusedIndexTopK(本文测量的是 v0.3.0,commit 05b44daa)。 本文只覆盖 prefill 侧的算子工作。文中数字都来自原始实验结果,并由脚本逐项核对过。

TL;DR

1 引言

1.1 问题

DSA 的打分公式是:

It,s=∑j=164wt,j⋅ReLU ⁣(qt,j⋅ks)I_{t,s} = \sum_{j=1}^{64} w_{t,j} \cdot \mathrm{ReLU}\!\left(\mathbf{q}_{t,j} \cdot \mathbf{k}_{s}\right)

其中 tt 是 query 位置,ss 是历史 token,jj 是 Indexer head。

每个 query t 要对所有合法历史 token s 打分,再选出分数最大的 K=2048 个 token 交给稀疏 MLA。主注意力因此只随 K 增长,但 Indexer 的打分仍随历史长度增长,整个 causal prefill 的打分总量是二次的。

表 1 是原生 vLLM 在真实语料上的成本归因:六种完整输入长度,同一 normal-A 输入包,Nsight Systems 按 NVTX 归因到 Indexer 的打分与 TopK。

完整输入长度Indexer 累计 GPU 时间(ms)非通信 kernel 累计时间(ms)占比
8K291.15375.65.42%
16K1105.211492.29.62%
32K4236.825244.816.78%
64K16703.258884.828.37%
128K66721.3151246.244.11%
约 160K104917.9210734.249.79%

表 1:原生 vLLM 的 Indexer 工作量占比。6×H20,TP2 / PP3,eager,并发 1,chunked prefill 8192。占比的分母是六张卡的 kernel 时间之和,不是 TTFT,不能直接套 Amdahl 定律。

常规实现分两步:DeepGEMM 打分 kernel 写出 [Q,N][Q, N] 的 FP32 分数矩阵,再由独立 TopK kernel 读回。以 Q=4096、N=131072 为例,分数矩阵 2 GiB,写一次读一次共 4 GiB,而最终输出的 int32 索引只有 32 MiB。

1.2 设计目标与约束

1.3 贡献

  1. 一个适合流水化的精确 TopK:采样估计筛选阈值,全行只做”比较 + 追加”,再在小候选集上用 radix 找第 KK 大;用”数量足够 + 集合完整”的证书判定快路径,失败则精确 repair(第 3 节)。
  2. 一个 warp 专用化的融合算子:TMA、Math、TopK 三类 warp 各司其职,用 ready / free 双缓冲跨 query 重叠;又依次消除了写候选争用、读空槽、溢出整行重算和调度尾波四类低效(第 4 节)。
  3. 用干预实验做归因:Math-only 对照、SM 分配 trace、改变 CTA 数的干预,把每项收益归到具体机制,并排除了几个看似合理的错误解释(第 5、7 节)。
  4. 从算子到整模型的验证:冻结公开版本,用 240 组真实激活测完整算子,再在 vLLM 里测 TTFT,并用量级分析核对两者是否一致(第 6 节)。

矩阵计算的主体,即 TMA 搬运、WGMMA 指令、SMEM 描述符与 swizzle,沿用 DeepGEMM;radix 选择、warp collective 都基于已有方法。本项目的工作在于把两者结合时的候选布局、片上生产—消费同步、容量补救、形状调度,以及证据驱动的性能验证。

2 背景:硬件与算术强度

2.1 硬件

所有实验都在 NVIDIA H20-3e 上进行:

H20 的算力约为 H100 的七分之一,带宽反而更高(H100 SXM 为 3.35 TB/s),所以在 H100 上访存受限的很多计算,到 H20 上会变成计算受限。

2.2 Indexer 打分是计算受限的

一个 key 对一个 query 行的打分:64 个 head 各做一次 128 维点积,即 2×64×128=163842 \times 64 \times 128 = 16384 FLOP。一个 key 要读 128 B 的 FP8 向量加 4 B 缩放系数,共 132 B。所以:

强度≈16384 FLOP132 B≈124 FLOP/B  >  拐点 62 FLOP/B\text{强度} \approx \frac{16384\ \text{FLOP}}{132\ \text{B}} \approx 124\ \text{FLOP/B} \;>\; \text{拐点}\ 62\ \text{FLOP/B}

这是”每个 key 只被一个 query 行使用”的保守下限。prefill 里一个 key 被大量 query 行复用,实际的 HBM 强度更高。64 个 head 共用同一份 key(MQA),是强度高的根本原因。

这决定了优化方向。 128K 时,写出再读回 4 GiB 分数矩阵,在 4.8 TB/s 下约需 0.9 ms;而未融合方案的完整耗时是 33.738 ms(表 11),这部分搬运约占 2.7%。所以融合的主要收益不会来自省带宽,而要来自让 TopK 不再与打分串行。第 5 节的版本轨迹证实了这一点。

2.3 问题定义

精确性的检查标准:

3 精确 TopK:先让选择跟得上

融合的前提是 TopK 跟得上打分的速度,否则候选会堆积,反过来让 Math 停下来等。所以第一阶段先在完整分数上优化独立 TopK(Q=4096,K=2048)。

3.1 反例:在线维护

最直接的思路是边扫描边维护候选,依据是 TopK(A∪B)=TopK(TopK(A)∪B)\mathrm{TopK}(A \cup B) = \mathrm{TopK}\big(\mathrm{TopK}(A) \cup B\big)。

第一版:每线程在寄存器里维护 Top-16。 每接受一个新值,就要重新遍历局部数组找最小值。N=128K 时的 NCU 数据:

第二版:改成 SMEM 上的小根堆。 维护降为 O(log⁡L)O(\log L),输入读取改为 warp 连续:

结论:只要扫描与在线维护耦合在一起,降低复杂度也消除不了维护本身。

3.2 采样阈值:把维护问题改成筛选问题

每个 query 先在扫描前估计一个固定的筛选阈值 τ\tau:

  1. 采样估阈值:分散抽取约 0.5% 的 token,按样本分布估计 τ\tau,目标保留约 4096 个候选,是 KK 的两倍,用来吸收采样误差。
  2. 全行筛选:固定 τ\tau 扫描整行,把所有 score≥τ\text{score} \ge \tau 的元素追加进候选集 CC。扫描中只有比较、计数和写入,没有有序状态要维护。
  3. 精确选择:在 CC 上用四轮 8-bit radix,找到精确的第 KK 大 θ\theta,再按 θ\theta 输出。

正确性证书。 设 C={(score,index):score≥τ}C = \{(\text{score}, \text{index}) : \text{score} \ge \tau\} 被完整保存,且 K≤∣C∣≤容量K \le |C| \le \text{容量}。那么全行的第 KK 大一定 ≥τ\ge \tau,阈值以下的元素不可能进入 TopK,所以

TopK(全行)=TopK(C)\mathrm{TopK}(\text{全行}) = \mathrm{TopK}(C)

快路径失败只有两种情况:

两种都交给精确 repair。采样只影响快路径能否成功,不影响答案是否精确。

radix 部分把浮点分数转成保序的 32-bit 整数,从高字节到低字节每轮统计 256 个桶。最后剩下的 rank 正好是”还需要从等于 θ\theta 的元素中选几个”,所以不需要排序。

效果:128K 时从堆版的 4.2200 ms 降到 2.7478 ms。配对 NCU 显示执行指令 1.565B → 1.007B,shared loads 196.89M → 7.87M,occupancy 不变,收益来自不再维护堆。

3.3 资源门槛:驻留看门槛,不看用量

每个候选存 score 和 index 共 8 B。把候选容量从 16384 调到 14080,并约束寄存器分配后:

反例:继续减少 SMEM,只存 index(68224 B)。1024 线程的 CTA 已经把驻留上限卡在 2 个,没有带来更多并行,radix 却要反复从显存取回 score。结果八个真实测试点全部变慢 2.60%~13.54%。

3.4 指令级优化

3.5 阶段结果

NFlashInfer(ms)本项目 TopK(ms)加速
16K0.6600.6472%
64K1.5061.14931%
128K2.4941.65151%
160K3.2191.85274%

表 2:独立 TopK 与 FlashInfer FilteredTopK。真实 Layer-0 分数,每个 N 取两组输入的均值;加速 = FlashInfer ÷ 本项目 − 1。FlashInfer 是同协议、同一 block 的单次对照,只覆盖 Layer 0;深层分数分布不同,不外推为”全面领先”。

TopK 已经跟得上,但独立 TopK 改变不了”分数矩阵先写出、再读回、两段串行”的结构。

4 融合算子的设计

4.1 分工与计算映射

角色线程负责
TMA1 warp异步搬运 Q、KV tile
Math8 warp(2 个 warpgroup)WGMMA 打分、head 归约、按 τ\tau 筛选候选
TopK3 warpradix 精确选择、输出索引

表 3:一个 CTA 内的角色,共 384 线程,每个 SM 一个 CTA。TMA 与 TopK 共用一个 128 线程的 warpgroup。

KV tile 为 128 行,两个 warpgroup 各负责 64 行。WGMMA 的形状是 m64nNk32:

每个 warp 拿 16 行 KV,head 归约在寄存器里完成:每个 lane 先累加自己的 16 列,再用两次 shfl_xor 在 4 个 lane 间求和。所以每个 warp 对每个 query 恰好得到 16 个最终分数,一次 ballot 就能完成筛选。分数在寄存器里就地归约、就地筛选,不必写出,这是把筛选放进 epilogue 的前提。

TMA 与 WGMMA 之间沿用 DeepGEMM 的 stage 环:每级一对 full / empty barrier,再加 phase 位区分轮次。我们先在原版 DeepGEMM 上测了这一级:KV stage 从 1 级到 2 级,延迟降低 13.1%(16K)/ 24.3%(128K),第 3 级没有收益,Tensor 指令族活动率约 95%。这一级已接近峰值,剩余空间在它后面新接的一级:Math ↔ TopK。

4.2 双缓冲:Math 与 TopK 跨 query 重叠

第一次把候选和 TopK 放进同一个 CTA 时,真实 N16K 输入耗时 6.616 ms。同一输入重测的有效吞吐只有 147 TFLOPS,比未融合方案的 176 还低。原因是 Math 算完一批 query,必须等 TopK 选完才能写下一批:省掉了显存往返,也失去了并行。

改法是给候选两个槽位。第 bb 批 query 使用槽位 b mod 2b \bmod 2,phase 位为 ⌊b/2⌋ mod 2\lfloor b/2 \rfloor \bmod 2:

指标串行跨 query 重叠
完整算子耗时5.498 ms3.848 ms(−30.0%)
Eligible warps / scheduler0.2690.446
Issue slots busy24.32%35.34%
Achieved occupancy18.71%18.20%

表 4:同一布局下只改”Math 是否等 TopK”的消融。H20,Q4096 / N16K,合成输入,含采样与 repair。

occupancy 不变,能发射指令的 warp 变多,收益来自减少等待,而不是提高驻留。

4.3 候选布局:warp 私有段

每行候选区分成 8 段,每个 Math warp 一段,每段 736 项,每行共 5888 项。每个 warp 用 ballot 加 popcount 在寄存器里维护自己段的计数,直接算出写入位置,不再向全 CTA 共享的计数器做 atomic 申请。

代价是段之间不能互借容量:某段满了,即使别的段还有空位,也只能按溢出处理。把同一 warp 原先的两个 368 项小段合成一个 736 项大段后,四组 160K 真实输入的完整耗时降低 0.04%~4.37%。

4.4 按每段的实际数量扫描

TopK 原先遍历整个预留容量,逐个判断位置是否有效。改成按每段的实际 count 遍历后(Q4096 / N16K):

解读:Math 本来几乎不等 TopK,推进速度由 Math 决定。TopK 已被流水线藏住,剩余损失在异常路径与任务调度。

4.5 溢出备用区:避免整行重算

160K 真实开发集中,只有 0.664%(544 / 81920)的行候选溢出,却让 20 个输入里只有 6 个快过 DeepGEMM + DeepSelect。原因是溢出的行要丢弃候选、整行重新打分。先对失败分类:

失败原因(共 544 行)行数
单段溢出,但整行总数未超过容量449
整行候选总数超过容量95
候选不足 K0

表 5:160K 开发集的失败分类。

449 行正是 4.3 节”段间不能互借”的代价。改法是保留 SMEM 正常路径,把少量溢出项写进显存中的备用区(每段 256 个位置),TopK 合并两处候选直接完成精确选择。备用区也装不下或候选不足 K 时,仍走原来的精确 repair。

方案整行重算行数完整耗时
丢弃后重算54442.072 ms
保存后合并040.387 ms
DeepGEMM + DeepSelect—41.830 ms

表 6:Q4096 / N160K,5 层 × 4 组真实输入。原本无溢出的 6 个 case 只变化约 0.011%。

开发集从 6/20 变为 20/20 胜出。在不参与开发的独立 holdout(五层、六个原生 N,共 120 个输入)上,16K~160K 为 100/100 胜出,8K 为 0/20(平均慢 4.26%)。8K 的问题由后面的 BLOCK_Q=1 和输出路径优化解决,公开版在 8K 也快于基线(表 11)。

4.6 每批一个 query:让各 SM 的工作均衡

kernel 要等最忙的 SM 做完。query 以每批 BLOCK_Q 行为一个任务分给 SM:Q=512、78 个 SM 时平均 6.56 行。BLOCK_Q=2 时每个 SM 的行数只能是偶数,%smid / %globaltimer 实测有 22 个 SM 拿 8 行。改成 BLOCK_Q=1 后,最忙的 SM 只拿 7 行(44 个 SM)。

排除错误解释。 Tensor 指令族活动率从 79.6% 升到 91.4%,看起来像”更窄的 MMA 更高效”。但绝对的 Tensor active cycles 两版完全相同,活动率上升只是因为分母变小;每个 query 的 Math 周期也不变(1.058M → 1.060M)。

干预验证。 保持输入和 kernel 不变,只改变持久 CTA 的数量:

CTA 数每批 2 query每批 1 query
1568 行 · 4.807 ms7 行 · 4.207 ms
1288 行 · 4.812 ms8 行 · 4.787 ms
1048 行 · 4.822 ms10 行 · 5.962 ms
9610 行 · 5.975 ms10 行 · 5.967 ms

表 7:最忙 SM 的行数与主 kernel 耗时。

耗时只取决于最忙 SM 的行数,与每批几行无关:

Tkernel≈0.6 ms×max⁡SM(行数),4.2074.807=0.875=78T_{\text{kernel}} \approx 0.6\ \text{ms} \times \max_{\text{SM}} (\text{行数}), \qquad \frac{4.207}{4.807} = 0.875 = \frac{7}{8}

在 420 组真实输入上,Q2 ÷ Q1 的几何平均为:Q=8 与 Q=64 约 1.77×,Q=512 约 1.15×,Q≥1024 约 1.02×~1.04×,最终索引集合全部一致。

5 离天花板还有多远

5.1 版本轨迹

为了看各步优化加起来走了多远,我们用同一份真实输入、同一套计时协议,把未融合方案和每个历史版本重新测了一遍。

有效吞吐只数因果掩码内真正需要的打分,时间是完整算子(含采样、主 kernel 和 repair):

有效吞吐=2⋅64⋅128⋅∑t(kend(t)−kstart(t))完整算子耗时\text{有效吞吐} = \frac{2 \cdot 64 \cdot 128 \cdot \sum_{t} \left(k_{\text{end}}(t) - k_{\text{start}}(t)\right)}{\text{完整算子耗时}}

图 1

图 1:H20-3e 上的 roofline 与版本轨迹。左:所有版本的算术强度相同(约 124 FLOP/B),都在拐点 62 右侧的计算受限区。右:同一输入、同一协议下的有效吞吐(eager),空心点为未融合的 DeepGEMM + torch.topk,虚线为 DeepGEMM + DeepSelect。

形状未融合(torch.topk)各融合版本公开版 v0.3.0DeepGEMM + DeepSelect
Q4096 / N16K(1 份)176(59%)R17a 147 → R17b 251 → R17c 254 → R17f 255262(88%)226
Q4096 / N160K(20 份)199(67%)R17j 263 → R17k 267271(92%)259
Q512 / N128K(1 份)171(58%)R17k 220251(85%)217

表 8a:有效 FP8 吞吐(TFLOPS,eager),括号内为占 296 TFLOPS 规格峰值的比例。CUDA Graph 下与 eager 只差 1~2 TFLOPS。

5.2 Math-only 对照:选择还露在外面多少时间

在公开版主 kernel 的副本上,保留 TMA 加载、WGMMA 和 barrier,删去分数归约、候选生成与 TopK。WGMMA 的累加结果算成 checksum 写出,防止编译器删掉矩阵计算。在 Q4096 / H128K 上用 NCU 核对,两版的动态 QGMMA(68,190,208 条)与 TMA 加载(4,265,984 条)逐项相同,总 SASS 指令减少 85.4%。

Q历史长度删掉全部选择工作后,主 kernel 快了
8192128K0.20%
4096128K0.31%
409624K1.64%
512128K2.00%
5128K21.75%

表 9:Math-only 对照。合成输入,与未改动版同轮交替计时。

指令少了 85%,时间只少 0.31%:长历史时,选择工作几乎都不在关键路径上。注意这个数是”固定当前矩阵路径时,选择露在外面的时间”,不是选择本身的耗时,也不是所有优化的上界。短历史时矩阵计算不够把选择盖住,删掉选择仍能快 21.75%。

5.3 主 kernel 的算力利用

QN有效 TFLOPS占峰值用到的 SMTopK 忙碌比例
40968K26489.1%780.85
409616K27392.2%780.43
409632K27793.5%780.19
409664K27994.1%780.09
4096128K27994.4%780.05
4096160K28295.2%780.04
512128K26188.1%780.05
64128K22074.4%640.04
8128K289.4%80.04

表 10:公开版主 kernel(不含采样与 repair),真实 replay 行,固定阈值,20 组计时。Q4096 的六行来自同一次测量(2026-10-13);后三行来自更早的一次测量(2026-10-05),两次都测过的 Q4096 / N8K 为 89.1% 与 88.7%、N32K 均为 93.5%,可作为两次之间可重复性的参考。TopK 忙碌比例 = TopK warp 处理候选的时间 ÷(处理时间 + 等待候选就绪的时间),取自单独的插桩运行,只用来看趋势。

Q4096 时 78 个 SM 都有活,主 kernel 从 8K 的 89.1% 随长度上升到 160K 的 95.2%。最后一列给出了原因:8K 时 TopK warp 有 85% 的时间在处理候选,选择几乎跟不上打分;到 64K 以后只剩不到 10%,大部分时间在等 Math 产出下一批候选。这与 5.2 节的结论一致:历史越长,每行的矩阵计算越多,越能把选择盖住。

Q 小于 SM 数时,按 query 并行的任务不够分:Q64 只用到 64 个 SM,Q8 只用到 8 个,这时 TopK 再闲也无济于事,瓶颈是并行度。另外,在 2026-10-05 的测量中,Q128 / Q256(N128K)虽然用满了 SM,却只有 75.1% / 76.8%:128、256 行不能被 78 整除,最忙的 SM 要多算一行,属于 4.6 节的尾波问题。

小结:长上下文、大 Q 的主场景下,流水线是满的,这条路线已接近天花板;再要大收益,只能少做矩阵乘。剩下的边界是”短历史藏不住选择”和”小 Q 并行度不够”。

6 评估

6.1 设置

6.2 算子性能

N本项目(ms)DeepGEMM + DeepSelect(ms)加速
8K1.7951.8721.04×
16K3.6854.2581.16×
32K7.7228.6941.13×
64K15.76117.1311.09×
128K31.91233.7381.06×
160K39.83641.8701.05×

表 11:Q4096 完整算子耗时(CUDA Graph)。每个 N 为 20 组输入中位数的算术平均;加速 = 基线 ÷ 本项目。

Q组数相对 DeepGEMM + DeepSelect(几何平均)
64601.561×
512601.125×
40961201.086×

表 12:按 Q 分组的逐 case 加速比几何平均。1.086× 不能直接说成”耗时降低 8.6%”。

vLLM 常用的 chunked prefill 预算是 8192 个 token,所以 Q8192 是实际会出现的形状。现有真实激活每份只采集了 4096 个 query,Q8192 只有合成输入:

N本项目(ms)DeepGEMM + DeepSelect(ms)加速
16K6.2167.3561.18×
32K14.16316.2741.15×
64K30.05732.8001.09×
128K62.25665.1331.05×
160K77.70481.4741.05×

表 12b:合成 Q8192(CUDA Graph),两个随机种子的中位数取平均。Q8192 / N8K 因部分行的有效 key 少于 K 而不测。合成输入不能替代真实激活,这里只用来确认趋势与 Q4096 一致。

6.3 正确性

这些检查不等于对每一行都做了独立 oracle,也不证明模型生成结果逐 token 相同。

6.4 端到端:TTFT

设置:

输入长度原生 vLLMDeepGEMM + DeepSelect本项目相对原生
8K2.7512.7622.761未调用融合路径
16K4.0294.0864.022−0.19%
32K6.6536.7736.628−0.36%
64K12.96313.22012.883−0.62%
128K29.88630.43329.396−1.64%

表 13:TTFT(秒),两份输入的中位数取平均。逐 case 的配对 bootstrap 95% 区间都很窄(例如 128K 为 1.0162×~1.0169×),但这只反映同一会话内的可重复性,两份输入不代表语料整体。

6.5 量级核对

端到端收益应当约等于 Indexer 的占比乘以算子相对原生的节省:

ΔTTFT≈Indexer 占比×相对原生的节省\Delta\text{TTFT} \approx \text{Indexer 占比} \times \text{相对原生的节省}
输入长度原生 Indexer 占比相对原生的节省估算实测 TTFT 降低
16K9.62%5.99%≈ 0.6%0.19%
32K16.78%4.33%≈ 0.7%0.36%
64K28.37%3.42%≈ 1.0%0.62%
128K44.11%4.43%≈ 2.0%1.64%

表 14:节省是实际调用的多种 Q/N 上、融合版相对原生减少的 Indexer GPU 工作量,含采样、repair 与接入检查。

两者同一量级,而且都随长度增长。实测低于估算,原因有几个:

这说明端到端收益的上限由 Indexer 的占比决定。

7 经验:预期与实测不一致的地方

尝试预期实测收获
堆维护降到 O(log⁡L)O(\log L),追上 FlashInfer指令减半,128K 仍为 4.220 ms,慢于 FlashInfer降复杂度不等于消除维护
只存 index少用 SMEM,应当更快八个测试点全部变慢 2.60%~13.54%资源要看门槛,不看用量
首次片上融合省掉显存往返,应当更快6.616 ms,慢于未融合方案(147 对 176 TFLOPS)融合要设计谁等谁
按实际数量扫描TopK 快 26%,整体也应明显变快完整算子只快 1.09%TopK 已被流水线藏住
每批一个 query更窄的 MMA 更高效每 query 周期不变,收益来自最忙 SM 少算一行指标要靠干预实验验证
手写减指令指令更少,应当更快静态 SHFL 20 → 15、FADD 30 → 25,完整耗时没有可靠改善指令数不等于时间

表 15:六次被数据推翻的判断。每行对应前文一节,口径各不相同,数字不跨行比较。

一条贯穿的经验:先找到决定总时间的那条路径,再动手。一个指标变好时,要先问它在不在这条路径上,再问变好的是分子还是分母。

8 局限

9 相关工作

10 结论

省掉中间矩阵只是起点。在 H20 上,Indexer 打分是计算受限的,融合的价值主要在于让精确选择与打分重叠,而不是节省带宽。为了做到这一点,我们先把 TopK 从”在线维护”改成”采样筛选加小集合精确选择”,再用 warp 专用化和双缓冲把它放进打分流水线,并依次消除写候选争用、读空槽、溢出重算和调度尾波。最终,完整算子达到 FP8 峰值的约 92%,长历史时选择几乎完全隐藏,在真实激活上稳定快于未融合方案,并在 vLLM 中转化为与估算一致的 TTFT 收益。

剩下的空间,在 prefill 侧要靠少做矩阵乘;小 Q 和 decode 侧则需要沿 KV 维度拆分的并行方式。

附录 A:复现信息

项值
公开版本v0.3.0,05b44daa14991d241de26162aa1bcb773cb6dafb
DeepGEMM7c95b14aa4a66edd7b682e5acdde62351ca81197
DeepSelect0f03b68748b304863fdf0181a11458d04ae533a9
算子测试环境NVIDIA H20-3e,PyTorch 2.10.0+cu130
端到端环境vLLM 0.28.0,PyTorch 2.13.0+cu132,6×H20-3e,TP2 / PP3

附录 B:计时口径

章节口径
3(独立 TopK)TopK 阶段的 CUPTI kernel 时间之和,含采样、筛选、选择、输出和 repair;真实 Layer-0 分数 replay
4(融合设计)完整算子的 CUDA Event 热态中位数,24 组交替;cycles 来自单独的插桩构建
5.1(版本轨迹)完整算子,eager,CUDA Event;同一输入、交替轮换
5.2、5.3(主 kernel)只计主 kernel,不含采样与 repair
6.2(算子)完整算子,CUDA Graph,7 组配对
6.4(端到端)整模型 TTFT,eager,并发 1,8 轮 Williams 轮换

不同口径的数字只在同一口径内比较。