B200 · BLACKWELL GB100 · 特性专题
TMA 增强 · + Cluster 16
★ Blackwell 搬运主线 · device 端改 tensormap · gather4/scatter4 · nonportable cluster 8→16
是什么
DEFINITIONHopper TMA 的全部能力(1D–5D bulk 搬运 / multicast / mbarrier 完成计数)在 Blackwell 原样继承,叠加三件新东西[2]:
① tensormap.replace——tensor map(拷贝描述符)可以在 kernel 内原地改写:global 基址、维度、stride、boxDim 都能换,不再必须回 host 重编码。② tile::gather4 / scatter4——按索引数组一次搬 4 行非连续行(MoE 专家行聚合 / embedding 查表场景的原生指令)。③ cluster nonportable 上限 8→16——16 个 CTA 的 DSMEM 共享域(portable 上限仍为 8)。
为什么(vs Hopper TMA)
RATIONALE · VS SM_90 TMA| 维度 | Hopper (sm_90) | Blackwell (sm_100) |
|---|---|---|
| 换 tensor map | 回 host 重新 cuTensorMapEncodeTiled | tensormap.replace 在 kernel 内原地改[2] |
| 非连续行搬运 | 软件循环逐行发 TMA / gather 索引展开 | tile::gather4 / scatter4 按索引数组搬 4 行 |
| cluster 上限 | 8 portable / 16 nonportable | 同 8/16;但 multicast mask 16-bit 与 16 CTA 对齐,DSMEM 域实用价值放大 |
| 变长序列 / 动态 shape | 每变一次 shape 一次 host 往返 | kernel 内热更新,LLM decode 变 batch 零往返 |
| 典型受益算子 | 规则 tile GEMM / attention | + MoE 行聚合、embedding 查表、变长 batch |
一句话:Hopper TMA 解决「规则 tile 搬得快」,Blackwell 补上「不规则访问与动态描述符」——这两块以前只能退回逐线程访存或 host 干预。
关键数字
KEY NUMBERS · CONSTRAINTS| 项 | 值 / 约束 | 注 |
|---|---|---|
| replace 可改字段 | global_address / globalDim / globalStrides / boxDim / elementStrides | tensormap.replace.tile.*.global.b1024 |
| replace 可见性 | 需 fence proxy(tensormap.cp_fenceproxy) | 改完必须 fence 再发 cp.async |
| gather4 粒度 | 一次 4 行(tile 第 0 维),行号来自索引数组 | 索引可为 smem / global,行内连续 |
| scatter4 对称 | 4 行写回不连续目标行 | 与 gather4 同族,方向相反 |
| cluster 维度 | portable ≤ 8 · nonportable ≤ 16 | 16 需 cudaFuncAttributeNonPortableClusterSizeAllowed |
| multicast mask | 16-bit(每位 1 CTA) | 恰好覆盖 16-CTA cluster |
| Hopper 遗产约束 | boxDim ≤ 256/维 · stride 16B 倍数 · 单线程发射 | 全部沿用,见 H200 TMA 特性页 |
可编译示例
COMPILABLE EXAMPLE · VERBATIM① Kernel 内热更新 tensor map(免 host 往返)
// 逐字对齐 PTX ISA tensormap.replace 语义(sm_100+):
if (tid == 0) {
// 换基址(变 batch / 换 buffer 时);dims/strides/boxDim 同族指令
asm volatile("tensormap.replace.tile.global_address.global.b1024.b64"
" [%0], %1;"
:: "l"(&tmap), "l"(new_ptr));
// 改完必须 fence proxy,之后的 cp.async.bulk.tensor 才能看到新值
asm volatile("tensormap.cp_fenceproxy.global.shared::cta.b1024.b64"
" [%0], [%1], %2;"
:: "l"(&tmap), "l"(smem_tmap_copy), "r"(size));
}
__syncthreads();
② gather4:按索引数组一次搬 4 行(MoE 行聚合)
// idx_smem: 4 个行号(uint64);每行 = boxDim[0] 连续元素
if (elect_one_sync()) {
asm volatile(
"cp.async.bulk.tensor.2d.tile::gather4"
".shared::cluster.global.mbarrier::complete_tx::bytes"
" [%0], [%1, {%2}], [%3], [%4];"
:: "r"(smem_dst), "l"(&tmap), "r"(col0),
"r"(idx_smem), "r"(mbar) : "memory");
}
// scatter4 对称:.tile::scatter4 写回 4 条不连续目标行
③ 16-CTA nonportable cluster(DSMEM 域翻倍)
// host:显式 opt-in 才能用 16
cudaFuncSetAttribute(kernel,
cudaFuncAttributeNonPortableClusterSizeAllowed, 1);
cudaLaunchKernelEx(&cfg, kernel, args); // cfg.clusterDim = {16,1,1}
// device:16 CTA 的 DSMEM 邻居直访(同 Hopper 语义)
cg::cluster_group c = cg::this_cluster();
int* nb = c.map_shared_rank(smem, 15); // rank 0..15
注意事项 / 陷阱
PITFALLS · CHECKLIST
CAUTION · 陷阱清单
- replace 后必须 fence proxy(tensormap.cp_fenceproxy),且要跨线程可见(__syncthreads)——漏 fence 后续 TMA 读到旧 map,静默错数据。
- tensor map 本体仍是 host 编码、64B 对齐、__grid_constant__ 传入;replace 只改字段不重建结构。
- gather4 固定 4 行粒度:行数不是 4 的倍数需 padding 索引;索引数组元素为行号(坐标第 0 维),行内仍要求连续+对齐约束。
- 16-CTA cluster 是 nonportable:不保证在所有 sm_100 设备可调度(资源不足直接 launch 失败),fallback 逻辑要自己写。
- multicast + 16 CTA 时 mask 16 位正好用满;跨 cluster multicast 依旧不存在。
- gather/scatter 走 sm_100/sm_103 专属:编译目标写成 sm_90 会静默编不过或运行期非法,检查 -arch。
数据源
SOURCES- PTX ISA — tensormap.replace / tile::gather4 / tile::scatter4(指令语义与约束)
- Blackwell Tuning Guide(cluster 8/16 portable 规则)
- Triton 官方教程 — TMA gather/scatter(MoE 场景实战用法)
- CUTLASS copy_sm100_tma.hpp(sm_100 TMA 变体 inline asm)