框架运行时、数据与性能

11 课 PyTorch 运行时底层、分布式通信与异构高频数据管线

框架运行时核心线

从 PyTorch 用户代码往下讲:Dispatcher、Autograd 图、torch.compile、分布式 Collective 的语义约定;再扩展到多模态数据加载(GPUDirect Storage)、CUDA IPC 共享内存的泄漏防护和动态形状的符号特化。

学习目标

  1. 理解 PyTorch Dispatcher、Autograd Engine 与自定义算子注册;

  2. 掌握 torch.compile 的 Graph Break 定位、Guard 机制与动态 Shape 优化;

  3. 掌握 Process Group、Rendezvous 握手与 Collective 拓扑成本模型;

  4. 掌握 PyTorch Profiler、CUDA Allocator 内存池与流水线性能排障;

  5. 掌握 GPUDirect Storage 零拷贝 DMA、CUDA IPC 跨进程生命周期,以及如何抑制动态形状 Guard 膨胀。


课程目录

课程名称 模块归属
第 1 课:PyTorch 执行栈、Dispatcher 与 Autograd 框架运行时底层机制
第 2 课:torch.compile:Graph Break、Guard 与动态 Shape 编译优化底层机制
第 3 课:Process Group、Rendezvous 与 Collective 契约 分布式通信运行时
第 4 课:Collective 成本模型与拓扑选择 分布式通信运行时
第 5 课:数据分片、Shuffle 与精确 Resume 数据输入流水线
第 6 课:存储→CPU→Pinned Memory→GPU 流水 数据输入流水线
第 7 课:Profiler、Timeline 与 CUDA Allocator 内存池与执行分析
第 8 课:可复现性、回归定位与性能排障 生产排障实战
第 9 课:异构多模态高频数据 Pipeline:GPUDirect Storage 与零拷贝流式加载 高性能数据与通信进阶
第 10 课:跨进程共享内存(IPC)生命周期管理与防泄漏机制 高性能数据与通信进阶
第 11 课:动态形状(Dynamic Shapes)深度处理:TorchDynamo 特化与 Guard 膨胀抑制 高性能数据与通信进阶

核心架构图稿

NCCL 通信拓扑与集合通信算法
① Ring 拓扑
GPU0 → GPU1 → GPU2 → GPU3 → GPU0
NVLink / PCIe 双向连接,数据沿环单向流动。每步传 1/N 数据,延迟随 N 线性增长。
② Tree 拓扑
根 GPU0 → GPU1、GPU2 → GPU3…GPU6
Reduce:叶 → 根逐层聚合;Broadcast:根 → 叶逐层分发。
延迟 O(log N),适合小消息或节点很多的场景。
③ Ring AllReduce = ReduceScatter + AllGather(N = 4)
初始:每卡 4 个 chunk
chunk a chunk b chunk c chunk d
GPU0 a0 b0 c0 d0
GPU1 a1 b1 c1 d1
GPU2 a2 b2 c2 d2
GPU3 a3 b3 c3 d3
Phase 1:ReduceScatter,N−1 步
chunk a chunk b chunk c chunk d
GPU0 A* · · ·
GPU1 · B* · ·
GPU2 · · C* ·
GPU3 · · · D*
每步把一个 chunk 发给下一张卡并累加,结束时每卡持有 1 个完整归约的 chunk。
Phase 2:AllGather,N−1 步
chunk a chunk b chunk c chunk d
GPU0 A* B* C* D*
GPU1 A* B* C* D*
GPU2 A* B* C* D*
GPU3 A* B* C* D*
每步把完整 chunk 转发给下一张卡,结束时每卡拥有全部结果。
A* = a0+a1+a2+a3,B*、C*、D* 同理。
每卡发送量 2(N−1)/N × 数据量,共 2(N−1) 步。带宽项与 N 基本无关,所以大消息用 Ring。
④ 集合通信原语对比
原语 输入 输出 一句话
Broadcast root 有 A 每卡都有 A root → all 复制
Reduce 各卡有 A、B、C root 得到 A+B+C all → root 聚合
AllGather 各卡有 A、B、C 之一 每卡都有 A B C 拼接,不做运算
ReduceScatter 各卡都有 A B C 三段 第 i 卡得到第 i 段的和 A* / B* / C* 归约后切片分发
AllReduce 各卡有完整张量 每卡都有全量和 = ReduceScatter + AllGather
⑤ NCCL 怎么选算法
小消息、rank 多:倾向 Tree,延迟 O(log N)。
大消息:倾向 Ring,带宽利用最好。
切换点没有固定值(不是固定 256 KB),由 NCCL 的调优模型按消息大小、rank 数和拓扑估算。
可用 NCCL_ALGO=Ring / Tree 手动指定做对比实验。
拓扑感知
启动时探测 NVLink / NVSwitch / PCIe / IB / RoCE。
节点内优先走 NVLink 建 ring / tree;节点间用 IB / RoCE 建 channel。
多个 channel 并行,用满多条链路。
Double Binary Tree:两棵互补的树各传一半数据,让 Tree 也能接近满带宽。
核心关系:拓扑决定连接 → 连接组成 channel → channel 承载算法 → 算法决定通信效率。

NCCL 通信拓扑与集合通信算法 · Excalidraw 源文件

PyTorch Eager vs torch.compile:执行路径与编译栈
Eager 模式:动态逐行执行
Python forward 逐行运行
每一行 Python 都立即执行
Dispatcher 调 ATen / cuDNN / cuBLAS
每个 op 单独进入 PyTorch dispatcher
Kernel 逐个 launch
pointwise、reduction、matmul 等按 op 边界执行
Autograd 动态记录 backward
运行时构建 autograd graph,backward 动态执行
优点:调试直观、Python 灵活、无编译冷启动
代价:Python/dispatcher 开销多,op 边界阻碍 fusion
核心区别:Eager 是 Python 逐行调度 ATen 算子;Compile 先捕获可编译子图,再 lowering、fusion、codegen,缓存后复用
Compile 模式:捕获子图 + 编译执行
用户代码
model = torch.compile(model)
第一次调用
触发 JIT 捕获和编译
TorchDynamo
Frame Eval hook 读取 Python bytecode,捕获 FX Graph
Guards + Graph Break
shape、dtype、Python 状态不匹配会 fallback 或 recompile
校验
AOTAutograd
训练时捕获 forward/backward graph,做 functionalization 和 decompositions
PrimTorch / ATen IR
复杂 op 拆成更小 primitive,便于 backend 处理
TorchInductor
fusion、layout、loop-level IR、调度优化
Codegen Backend
GPU: Triton kernel
CPU: C++ / OpenMP
之后再次调用:guard 命中 -> 直接复用缓存的 compiled callable
guard 失败或形状模式不匹配 -> 重新编译或回退 eager
关键对比:什么时候快,什么时候慢
执行粒度
Eager: op by op
Compile: graph/subgraph
性能来源
fusion 减少 kernel launch
降低 Python/dispatcher 开销
首次调用成本
Compile 有 tracing/codegen/autotune 冷启动
Eager 几乎无编译等待
动态性
Eager 最灵活
Compile 靠 guards 保证图仍然有效
训练 backward
Eager: autograd 动态图
Compile: AOTAutograd 预先捕获 backward 段
Graph Break
print、数据相关 Python 分支、unsupported op
会切成多个子图或回退 eager
适合场景
重复执行的模型训练/推理
算子多、融合收益明显
调试建议
backend=eager 测 Dynamo
backend=aot_eager 测 AOTAutograd
backend=inductor 测完整编译
一句话流程:Python 代码 -> Dynamo 捕获 FX 子图 -> AOTAutograd 处理训练图 -> Inductor 优化融合 -> Triton/C++ 执行 -> guard 命中则缓存复用

PyTorch Eager vs Compile 原理详解 · Excalidraw 源文件