docs: T17 process-per-GPU results — measured throughput-neutral
Records the key empirical finding: process-per-GPU is statistically identical to thread-per-GPU at this scale (thread 5.27x vs proc 5.31x @8, <1% noise; all 8 GPUs 95-99% util). The residual ~5.3x@8 non-linearity is the NCCL/PCIe communication wall, NOT single-CUDA-context launch/cuBLAS serialization as the old KI-5/T11 note speculated — measurement falsifies that hypothesis (same methodology as T11 falsifying "bucket the all-reduce"). Correctness all green: proc==thread loss 1.5e-7, cross-rank 1.2e-7, full regression + xserv md5 b04fc9f9 identical. Closes the process-per-GPU backlog item (measured no-op); default training path unchanged. evolution.md Infra row + README T17 row + known-issues entry. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,26 @@ _(KI-1 fixed in T10. KI-5 fixed in T11. KI-2 fixed in T12. **KI-3(激活重计
|
||||
|
||||
## Fixed
|
||||
|
||||
### process-per-GPU(torchrun 式独立 CUDA context)— `CLOSED / 实测负结果` (T17)
|
||||
- **背景**:KI-5(T11)修掉 per-op `cudaMalloc` 串行后,8 卡 scaling 从 ~1.3× 恢复到 **~5×@8**,但残留 ~5×@8 非完美线性。T11 doc / KI-5「残留」推测下一步是 **process-per-GPU**(每 rank 独立进程 + 独立 CUDA context,torchrun 式)——理由是「N rank 线程共享单 CUDA primary context,kernel-launch/cuBLAS 仍在 context 级串行」。**T17 把这条 torchrun 式链路落地并实测,证伪了该推测。**
|
||||
- **实现([docs/16-process-per-gpu.md](16-process-per-gpu.md))**:`xtrain-distributed` 加 `proc.rs`——`launch_processes` 每卡 spawn 一个 worker 进程(re-exec current_exe + `XTRAIN_{RANK,WORLD,LOCAL_RANK,NCCL_ID}` env);**launcher 一次性铸 `ncclUniqueId` 后 hex 编码注入子进程 env**(无共享 FS/TCP、无轮询、无竞态——id 在子进程出生前就原子就绪);worker 读 env → bind device(独立 CUDA context)→ `DdpContext::init` + `build_model` + `train_rank` **全部复用 T8 零改动**。新 `train_ddp_mp` bin + `ddp_proc` test;**保留 thread-per-GPU 旧路径**(回归 baseline)。scope=process-per-GPU only(ZeRO-1 用户 drop)。
|
||||
- **正确性(全绿,无回归)**:proc vs 单卡 loss `5.67e-7`、**proc vs thread-per-GPU `1.5e-7`**(两路数值同量级)、跨 rank `1.19e-7`(<1e-6);全回归套 `--test-threads=1` 全绿 + **xserv 闭环 v3 重导 md5 逐位一致 `b04fc9f9`**(T17 不碰任何数值路径)。
|
||||
- **实测结果(关键,dash5 8× RTX 5090, dim384 per-rank batch32 seq256, steady-state)**:
|
||||
|
||||
| world | thread-per-GPU (`train_ddp`) | speedup | process-per-GPU (`train_ddp_mp`) | speedup |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 93257 | 1.00× | 92952 | 1.00× |
|
||||
| 2 | 149747 | 1.61× | 148809 | 1.60× |
|
||||
| 4 | 278276 | 2.98× | 273308 | 2.94× |
|
||||
| 8 | **491360** | **5.27×** | **493128** | **5.31×** |
|
||||
|
||||
(world=8 各重复 2 次:thread 493671/493292、proc 491102/494123——**两路差异 <1%,落在噪声内**。)
|
||||
- **诊断(证伪原推测)**:process-per-GPU world=8 跑时 `nvidia-smi` 抽样 **8 卡全部 95–99% util**(每卡 ~23GB)——GPU **已 compute-bound 喂满、非串行空转**(KI-5「1–2/8 在忙」的串行病 T11 allocator 已治好)。8 卡满载却仍只 5.3× ⇒ 缺的 ~35% 吞吐去向**每步 grad all-reduce + 本机 PCIe-only 拓扑在 8 rank 下的通信开销**(T11 早点明的「~7% all-reduce + PCIe 余量」那一层,8 卡放大),换独立 context 不动这一层。**结论:本尺度(dim384–1024、单机 8× PCIe RTX 5090)残留非线性是通信/拓扑墙,不是 launch 模型**——要再逼近线性须动 all-reduce overlap / NVLink 互联(非本尺度优先)。
|
||||
- **方法论一致**:T11 实测证伪「分桶 all-reduce」、T17 实测证伪「process-per-GPU 解残留串行」——两次都靠 measure 推翻假设而非硬上(profile/measure-first)。**净价值**:落地 torchrun 式 process-per-GPU 标准链路(项目本职「学训练全栈」)+ 把这个误导性 backlog 项**实测钉死关闭**。**默认训练路径不变**(thread-per-GPU),process-per-GPU 作并列可选路径留档。
|
||||
- **commit**:见 T17 提交链(`distributed: process-per-GPU launcher + worker` / `distributed: train_ddp_mp bin` / `test: process-per-GPU DDP correctness` / 设计文档 `docs: Phase T17 — process-per-GPU DDP design`)。
|
||||
|
||||
---
|
||||
|
||||
### KI-3 · 激活重计算(gradient checkpointing)— `FIXED` (T13)
|
||||
- **触发点(v8 surfaced)**:容量轴放大到 dim1024(核心 ~210M+)测是否 capacity-limited。autograd tape 为反向保存所有中间激活,激活显存随 dim 线性增长——dim768 bf16 batch32 已 31.1GB(T12 甜点区),**dim1024 batch32 再次 OOM**(实测撞 32100/32607MiB → `OutOfMemory`)。
|
||||
- **设计(per-block gradient checkpointing,opt-in,[docs/12-activation-recompute.md](12-activation-recompute.md))**:新增 `xtrain_autodiff::checkpoint(segment_fn, input, params)` 高阶原语(类比 `torch.utils.checkpoint`)。**前向**:把 input/params detach 成局部 leaf 跑 `segment_fn`,只取输出值,局部 tape 立即 drop → 段内激活释放(不留在外层 tape);checkpoint 节点 parents=[input, ..params]。**反向**:从保存的 input + 未变的 param 值重跑 `segment_fn` 重建局部 tape,用上游 grad seed(`Var::backward_seeded`,新增——段输出非标量)回传,恢复的 input/param 梯度 push 给真 parents,局部 tape drop → 重算激活释放。模型每个 transformer block 前向用它包裹(`--recompute` flag,默认关)。切粒度 = 每 block。
|
||||
@@ -68,7 +88,7 @@ _(KI-1 fixed in T10. KI-5 fixed in T11. KI-2 fixed in T12. **KI-3(激活重计
|
||||
→ **单卡 40226→92638 tok/s (~2.3×)**;**8 卡 49K→461K tok/s (9.4×)**,scaling 从 ~1.3× 封顶恢复到 **~5×@8**;8 卡 `nvidia-smi` 抽样 **全 8 卡 95–99% util**(KI-5 时只 1–2/8 忙)。loss 轨迹逐位对住(单卡 10.9026→4.8453 before/after 一致)。
|
||||
- **正确性(全绿,无回归)**:15 算子 grad-check、5 结构、GEMM 对 cuBLAS、batched==looped、overfit 27/27、AdamW GPU bit-exact + host 对 torch、checkpoint 逐位、DDP loss 对单卡 **5.67e-7** + 跨 rank diff 0.0(loosened `<1e-6`)、**xserv 闭环**(v3 ckpt 重导 safetensors 与 registry md5 逐位一致 + xserv 加载服务贪心 "Once upon a time," 对住)。
|
||||
- **顺手**:DDP `ddp_correctness` 的 cross-rank `==0.0` → `<1e-6`(本机 PCIe-only NCCL run-to-run 跨 rank 非逐位可复现,diff≤1.2e-7 几 ULP 无害,承重闸门是 loss-match 5.67e-7);`ddp_throughput_scaling` 扩到 world=8。
|
||||
- **残留**:~5×@8 非完美线性(grad all-reduce ~7% + 8 卡 PCIe/launch 余量),但弱扩展悬崖已消。v4 若要更高线性度,下一步是 **process-per-GPU**(每 rank 独立 CUDA context,torchrun 式)。
|
||||
- **残留**:~5×@8 非完美线性(grad all-reduce ~7% + 8 卡 PCIe/launch 余量),但弱扩展悬崖已消。曾以为下一步是 **process-per-GPU**(每 rank 独立 CUDA context,torchrun 式)——**T17 实测证伪该方向**(见下方「process-per-GPU(T17)」):残留是**通信/PCIe 墙**,不是单 CUDA context 的 launch/cuBLAS 串行。
|
||||
- **commit**:见 T11 提交链(`cuda: device caching allocator` / `perf: KI-5 …` 那条带 before/after)。
|
||||
- **历史诊断保留如下**(证伪「分桶 all-reduce」的过程):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user