同步与算法优化¶
同步开销优化¶
Barrier 合并¶
将多个 phase barrier 合并为一个:
优化前:[RS] → [Barrier] → [local reduce] → [Barrier] → [AG]
优化后:[RS with AtomicAdd] → [Barrier] → [AG]
^^^^^^^^^^^^^^^^^^^^^
RS 和 Reduce 融合为 TPUT<AtomicAdd>
通过使用 AtomicAdd 在 RS 阶段直接累加,消除了独立的 Reduce 阶段及其 barrier。
信号压缩¶
减少跨 rank 通知次数:
优化前:每个 tile 完成都通知远端 → N_tiles × nranks 次 TNOTIFY
优化后:所有 tile 完成后通知一次 → nranks 次 TNOTIFY
Block 角色优化¶
只让 block 0 执行跨 rank 信号,其他 block 等待本地广播标志:
Block 0: TNOTIFY(remote) × (nranks-1) → TWAIT(local) × (nranks-1) → Set local flag
Block 1~N: TWAIT(local flag) ← 一次 TWAIT 而非 nranks 次
TTEST vs TWAIT 选择¶
| 场景 | 推荐 | 原因 |
|---|---|---|
| 确定必须等待(barrier) | TWAIT | 硬件自旋,更节能 |
| 轮询+做其他工作 | TTEST | 可交错执行 |
| 就绪队列消费 | TTEST | 先检查再处理 |
减少 dcci 调用¶
dcci 刷新缓存行是标量操作,频繁调用影响性能:
// 优化前:每次读队列数据都 dcci
for (int i = 0; i < count; i++) {
dcci(&queue->data[i], SINGLE_CACHE_LINE);
process(queue->data[i]);
}
// 优化后:使用 TTEST 硬件指令代替 dcci + 软件比较
comm::Signal sig(&queue->count);
if (comm::TTEST(sig, expected, comm::WaitCmp::GE)) {
dcci(&queue->data[head], SINGLE_CACHE_LINE);
process(queue->data[head]);
}
算法选择¶
AllReduce 分解策略¶
| 策略 | 通信量 | 延迟 | 适用场景 |
|---|---|---|---|
| ReduceScatter + AllGather | 2(N-1)/N × S | 2(N-1) steps | 中大数据量 |
| Ring AllReduce | 2(N-1)/N × S | 2(N-1) steps | 大数据量,带宽受限 |
| 内置 TREDUCE + TBROADCAST | N × S | 2 steps | 小数据量,root 带宽足够 |
| TPUT\<AtomicAdd> RS + TPUT AG | 2(N-1)/N × S | 可重叠 | 通算融合场景 |
其中 S = 数据总大小,N = rank 数。
RS 实现:AtomicAdd vs 独立 Reduce¶
AtomicAdd 方式(推荐用于融合):
- RS 阶段使用 TPUT<AtomicAdd> 直接累加到 owner
- 无需独立 Reduce 阶段和额外 barrier
- FP16 下有累积精度损失
独立 Reduce 方式: - RS 只做 scatter(无归约) - owner 本地执行 TLOAD + TADD + TSTORE 归约 - 精度更好,但需要额外阶段和 barrier
AG 实现¶
- TPUT 直写:owner rank 主动写到所有远端(推荐)
- TGET 拉取:各 rank 从 owner 拉取
- TBROADCAST:owner 使用内置集合通信广播
通常选择 TPUT 直写,因为 owner 知道数据就绪时机,无需额外通知。