数据搬运优化¶
乒乓双缓冲¶
原理¶
使用两个 UB Tile 交替工作,将 TLOAD(MTE2)和 TSTORE(MTE3)重叠:
时间 →
MTE2: [TLOAD ping] [TLOAD pong] [TLOAD ping] ...
MTE3: [TSTORE ping] [TSTORE pong] ...
↑ 无重叠 ↑───── 重叠区 ──────↑
实现模式¶
TileData pingTile(ROWS, COLS);
TileData pongTile(ROWS, COLS);
TASSIGN(pingTile, 0x0);
TASSIGN(pongTile, TILE_UB_BYTES);
// 方式 1:使用内置 ping-pong(推荐)
comm::TPUT(dstG, srcG, pingTile, pongTile);
comm::TGET(dstG, srcG, pingTile, pongTile);
// 方式 2:手动 ping-pong(更灵活)
for (int i = 0; i < num_chunks; i++) {
bool use_ping = (i % 2 == 0);
TileData &curTile = use_ping ? pingTile : pongTile;
event_t curEv = use_ping ? EVENT_ID0 : EVENT_ID1;
if (i > 0) {
TileData &prevTile = use_ping ? pongTile : pingTile;
event_t prevEv = use_ping ? EVENT_ID1 : EVENT_ID0;
wait_flag(PIPE_MTE2, PIPE_MTE3, prevEv);
TSTORE_IMPL<...>(prevDst, prevTile);
set_flag(PIPE_MTE3, PIPE_MTE2, prevEv);
wait_flag(PIPE_MTE3, PIPE_MTE2, prevEv);
}
TLOAD(curTile, srcG_i);
set_flag(PIPE_MTE2, PIPE_MTE3, curEv);
}
// 刷新最后一个 tile
何时使用乒乓¶
| 场景 | 建议 |
|---|---|
| 大量小块传输(多次 TLOAD/TSTORE) | 强烈推荐 |
| 单次大块传输 | 不需要(内置指令已自动分块) |
| UB 空间紧张 | 使用单缓冲 |
| 传输量 > 2 × Tile 大小 | 推荐 |
内置 vs 手动乒乓¶
- 内置(TPUT/TGET 的 ping-pong 重载):简单场景,自动处理流水线同步
- 手动:需要在 TLOAD/TSTORE 之间插入自定义逻辑(如 AtomicAdd 选择)
Tile 大小选择¶
| 考虑因素 | 影响 |
|---|---|
| UB 容量 | Tile 不能超过 UB 大小(典型 ~192KB) |
| 传输效率 | 大 Tile:更少的传输次数,更高效率 |
| 重叠粒度 | 小 Tile:更早开始通信 |
| 对齐 | 32B 对齐(行方向) |
| 乒乓 | 需要 2× Tile 空间 |
推荐基线(half 类型):
UB 约 192KB
乒乓模式需要 2 × Tile
单 Tile ≤ 96KB
128 × 256 × 2B = 64KB → 安全,乒乓后 128KB
64 × 512 × 2B = 64KB → 安全
256 × 256 × 2B = 128KB → 单缓冲可用,乒乓危险
数据对齐¶
// Tile 列数需要 32B 对齐
constexpr int alignedCols = ((cols * sizeof(T) + 31) / 32) * (32 / sizeof(T));
// Tile 间间隔向上对齐到 1024B
constexpr size_t TILE_UB_BYTES = ((M * N * sizeof(T) + 1023) / 1024) * 1024;
GM 数据布局¶
通信数据在 GM 上的布局影响传输效率:
- 连续布局:最佳,TPUT/TGET 一次传输完成
- 带步长布局:自动分块按行传输,有额外开销
- 异步传输:必须一维连续(TPUT_ASYNC/TGET_ASYNC 的约束)