GPU 计算调度与占用率
GPU Compute Scheduling & Occupancy
GPU 用大量统一的 ALU 以 SIMD/SIMT 方式锁步执行着色程序,ALU 与寄存器文件、L1、本地数据存储、纹理单元等组成多处理器 (MP),由硬件 warp 调度器零开销地切换 warp 以隐藏纹理和内存访问的长延迟。能同时驻留的 warp 数受寄存器等资源限制,用占用率衡量;占用率低会妨碍延迟隐藏,但过高也可能抖动缓存。本页还讨论像素按 quad 调度和 GPU→CPU 回读延迟。
统一 ALU 与多处理器(23.2 节)
- 一个 ALU(也叫 SIMD lane)为一个实体(顶点或片元)执行程序,主要包含浮点单元(遵循 IEEE 754,最复杂的指令之一是融合乘加 FMA)和整数单元,以及移动/比较、加载/存储、分支和超越函数(某些架构把超越函数等不常用操作放到少量共享的特殊单元 SU 中服务更多 ALU)。
- ALU 采用少量流水级(如 4~10 级):n 级流水理想上吞吐提高 n 倍(流水并行),每级硬件更少也允许更高时钟频率。
- 与 CPU 核心不同,没有分支预测、寄存器重命名、深流水等,芯片面积主要用于复制 ALU 和加大寄存器文件以便切换 warp。例如 GTX 1080 Ti 有 3584 个 ALU。
- ALU 按如 32 个一组锁步执行构成 SIMD 引擎,加上调度器、L1、本地数据存储 (LDS)、纹理单元 (TX)、SU 组成多处理器(NVIDIA 称流式多处理器,Intel 称执行单元,AMD 称计算单元)。NVIDIA 称 warp,AMD 称 wave/wavefront。
- 利用的并行性:线程级(顶点、片元相互独立)、数据级(一条指令作用于所有 lane)、指令级(独立指令同时执行)。
warp 调度
warp 调度器接收大块工作,分成 warp 分配给 MP、为线程分配寄存器并排定优先级。通常下游工作优先于上游(像素着色优先于顶点着色),因为管线末端的阶段不太会阻塞前面的阶段,可避免停顿。MP 可驻留成百上千个线程;当前 warp 执行预期长延迟的纹理加载时,专用硬件调度器可零开销换入另一个就绪 warp。
像素按 quad 调度:warp 宽 32 时一次调度 8 个 quad。设计取舍:整个 warp 锁定于一个三角形(实现简单,但小三角形效率低),或允许每个 quad 来自不同三角形(更复杂,但小三角形更高效)。更高一级还有全局调度器把工作分给各 warp 调度器。
延迟与占用率(23.3 节)
纹理单元返回过滤颜色可能要数百甚至上千个时钟周期,不隐藏就会让内存访问主导执行时间。定义
是 MP 允许的最大 warp 数, 是当前活跃 warp 数,受寄存器、纹理采样器、L1、插值量等影响。例:,寄存器 256 kB,SIMD 宽 32,若只受寄存器限制:
| 每线程寄存器数(32 位) | 占用率 | |
|---|---|---|
| 27 | (超过 32) | 1,理想 |
| 150 | ,可能妨碍延迟隐藏 |
取舍:
- 一般原则是追求高占用率;低占用率时着色器请求纹理时更可能没有别的 warp 可切换。
- 占用率过高而着色器内存访问很多时可能抖动缓存。
- 另一种隐藏方式是发出内存请求后继续执行同一 warp 中不依赖结果的指令;循环展开能产生更长的独立指令链(提高指令级并行),但用更多临时寄存器——有时低占用率反而更高效。
- 架构设计要平衡最大 warp 数、寄存器数和其他共享资源。
CPU-GPU 回读延迟
把 GPU 与 CPU 看作异步工作的两台计算机,通信需要代价;改变信息流方向会严重伤害性能:从 GPU 读回数据前可能要冲刷管线,CPU 只能等待。Intel GEN 这类 CPU 与 GPU 同片、共享内存模型的架构中,低级缓存共享(高级缓存不共享),这种延迟大大降低,例如光线可在 GPU 与 CPU 核心之间零成本往返以加速光线追踪。不会造成 CPU 停顿的回读机制例子是遮挡查询:发出查询后偶尔检查结果是否可用,期间 CPU 和 GPU 都继续做别的工作。
flowchart LR A["warp A 发出纹理请求"] --> B["调度器零开销换入就绪 warp B"] B --> C["warp B 执行 ALU 指令"] C --> D["纹理数据返回, warp A 再次就绪"] D --> E["按优先级: warp 类型, 指令类型, 公平性 选择下一个"]
如上图,足够多的活跃 warp 是隐藏延迟的前提。
出处
- realtime_rendering_4ed.pdf 第 23 章 Graphics Hardware