GPU编程PPT2
GPU编程PPT2
CUDA Optimization Techniques / CUDA 优化技术
COMP52315 GPU Programming
Lecturer: Christopher Marcotte
Email: christopher.marcotte@durham.ac.uk
📚 Recap / 复习
- Concurrency vs. Parallelism / 并发 vs. 并行
- Flynn’s Taxonomy / Flynn 分类法
- GPU Architecture / GPU 架构:
- Streaming Multiprocessors (SMs): FPUs, LD/ST, SFUs, Tensor Cores
流多处理器:浮点单元、加载/存储单元、特殊函数单元、张量核心 - Cache / 缓存
- Warp Schedulers / Warp调度器
- Global Memory / 全局内存
- Streaming Multiprocessors (SMs): FPUs, LD/ST, SFUs, Tensor Cores
- SIMT Model / SIMT 模型:
- Kernel function executed by a grid of thread blocks
内核函数由线程块网格并行执行
- Kernel function executed by a grid of thread blocks
- CPU vs GPU:
- CPU: latency-driven / 延迟驱动
- GPU: throughput-driven / 吞吐驱动
🔧 Performance Optimization Tooling / 性能优化工具
Optimization Cycle / 优化周期
- Write baseline code / 编写初始代码
- Tune kernel configuration / 调整内核配置
- Profile to find hotspots / 使用分析器识别热点
- Identify performance limiters / 找出性能瓶颈
- Optimize code / 优化代码
Nsight Compute (ncu
)
- 设备端 CUDA 分析器
- 支持 GUI 和 CLI
- 使用硬件计数器和软件插装来获取性能指标
- 提供基于规则的优化建议
- 注意不要和 Nsight Systems 混淆(后者用于系统级性能分析)
🎯 Occupancy / 占用率
- 活跃 warp 数量与 SM 最大 warp 数的比例
- 会随时间和 SM 不同而变化
- 占用率低 → 指令发射效率低,难以隐藏延迟
- 限制因素:
- 每线程使用的寄存器数量
- 每线程块的线程数
- 使用的共享内存大小
- ncu 可预测并报告占用率
🚦 Application Performance Characteristics / 程序性能特征
- Memory-bound / 内存受限型:内存带宽接近上限
- Compute-bound / 计算受限型:指令吞吐接近上限
- Latency-bound / 延迟受限型:主要瓶颈为延迟/同步/等待
- 性能瓶颈依赖于执行阶段和代码区域
📋 ncu Profiling Commands / ncu
分析命令
1
2
3
4
nvcc -lineinfo saxpy.cu -o saxpy # 编译,包含源码行号
ncu -o saxpy_prof_report saxpy # 生成默认分析报告
ncu --set full -o full_prof_report saxpy # 全指标分析
ncu --section MemoryWorkloadAnalysis -o mem_prof_report saxpy # 特定分析
Docs:
- https://docs.nvidia.com/nsight-compute/NsightComputeCli/index.html
- https://developer.nvidia.com/tools-downloads
⚙️ Kernel Configuration / 内核配置
- 启动更多线程以隐藏延迟
- BLOCK_SIZE: 线程块内线程数应为32的倍数(warp)
- GRID_SIZE: 线程块数量建议为 SM 数的倍数
- 上限估算: [ \left( rac{ ext{maxThreadsPerMultiprocessor}}{ ext{BLOCK_SIZE}} ight) imes ext{multiProcessorCount} ]
🔀 Branch Divergence / 分支发散
原因
- Warp 中线程需要执行相同指令
- 条件语句使线程走不同路径 → 部分线程被屏蔽等待
示例
1
2
3
4
5
6
// 发散版本
if (gid % 2 == 0) array[gid] = 0;
else array[gid] = 1;
// 非发散版本
array[gid] = gid % 2;
避免方式
- 拆成多个内核函数
- 条件分支对齐 warp 边界
- 使用数学表达式代替条件语句(如 sigmoid)
🧠 Memory Optimization / 内存优化
手动 vs 管理内存
Host (CPU) | Bus (PCIe/NVLink) | Device (GPU) |
---|---|---|
cudaMalloc/copy | ⬅️➡️ | cudaMalloc |
cudaMallocManaged 自动管理 |
🧮 Shared Memory / 共享内存
- 相当于手动管理的缓存(每线程块可重用)
- 分为多个 memory bank,应避免 bank 冲突(连续访问最佳)
示例
1
2
__shared__ float s[1024]; // 静态分配
extern __shared__ float s[]; // 动态分配,调用时指定大小
🧩 Types of Parallelism / 并行类型
- Data Parallelism / 数据并行:相同操作处理多个数据
- Task Parallelism / 任务并行:分为不同任务并分析依赖
- Pipelining / 流水线并行:数据通过多个阶段流动
🔗 Task Parallelism / 任务并行
- 使用任务图表达:
- 节点表示任务,边表示依赖
- 支持不同粒度:
- 函数级:任务为函数调用
- 操作级:任务为运算操作
🔁 Dynamic Parallelism / 动态并行
- 可在设备端内核中再发起内核
- 适用于递归问题
- 避免返回 CPU 同步,提高效率
示例:
1
2
3
4
5
6
__global__ void factorial(const int N, int *f){
if (N >= 1) {
*f *= N;
factorial<<<1,1>>>(N-1, f);
}
}
编译时加
--rdc=true
使设备端代码可重定位
🌀 Stream Parallelism / 流并行
- 同一 stream 内操作按顺序执行
- 不同 stream 可并行执行
- CUDA stream = 一列按顺序执行的任务
⛓️ Asynchronous Task Graphs / 异步任务图
- 任务图包含:
- CUDA 内核
- 主机函数
- 内存拷贝/分配
- 子任务图
执行流程:
- 创建任务图
- 实例化图为可执行形式
- 启动任务图
📝 文档链接:
- https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#creating-a-graph-using-graph-apis
- https://www.olcf.ornl.gov/wp-content/uploads/2021/10/013_CUDA_Graphs.pdf
本文由作者按照 CC BY 4.0 进行授权