土法炼钢兴趣小组的算法知识备份

【GPU 算子工程】Nsight 调优工作流:Compute 与 Systems 怎么读

文章导航

分类入口
gpuarchitecture
标签入口
#cuda#nsight-compute#nsight-systems#profiling#ncu#nsys#stall-reasons

目录

Nsight 调优工作流:Compute 与 Systems 怎么读

Roofline 篇 给了优化方向,但要把瓶颈定位到具体的 kernel、具体的指令或访存行为,得靠 profiler。NVIDIA 的两个工具分工明确:Nsight Systems 看全局时间线,Nsight Compute 看单个 kernel 的细节。这一篇讲它们各管什么、关键指标怎么读,以及没有完整工具链时怎么用 CUDA event 做轻量测量。

一、两个工具的分工

工具 粒度 回答的问题
Nsight Systems(nsys 整个程序时间线 时间花在哪?哪个 kernel/拷贝/同步占大头?CPU 和 GPU 是否互相等待?
Nsight Compute(ncu 单个 kernel 这个 kernel 为什么慢?受算力还是访存限制?warp 在等什么?

正确顺序是先 Systems 后 Compute:先用 Systems 找出真正占时间的 kernel(优化一个只占总时间 2% 的 kernel 没意义),再用 Compute 深挖那个 kernel。这对应一条通用原则——先定位热点,再优化热点。

二、Nsight Systems:时间线视角

nsys 抓取程序运行的时间线,把 CUDA API 调用、kernel 执行、内存拷贝、CPU 线程活动画在同一条时间轴上。典型用法:

nsys profile -o report ./my_app

时间线上要找的几类问题:

Systems 的产出是一份”时间预算表”:告诉你接下来该把精力放在哪个 kernel 上。

三、Nsight Compute:单 kernel 深挖

锁定热点 kernel 后,用 ncu 对它做详细分析:

ncu --set full -o kernel_report ./my_app
# 或只看某个 kernel、某些指标
ncu -k my_kernel --metrics sm__throughput.avg.pct_of_peak_sustained_elapsed,\
dram__throughput.avg.pct_of_peak_sustained_elapsed ./my_app

Compute 会重放 kernel 多次采集硬件计数器。要看的核心指标分几组:

1. 两个吞吐率:先判断算力还是访存

哪个接近 100%,瓶颈就在哪。这等价于把 kernel 定位到 Roofline 的哪条屋顶上:DRAM 吞吐打满 → memory-bound;SM 吞吐打满 → compute-bound;两个都不高 → 是延迟暴露或并行不足的问题,往下看 stall。

2. Warp stall reasons:warp 在等什么

当两个吞吐都不高,说明 SM 大量周期里没指令可发,warp 都在 stall。Compute 会归因每个周期 warp 卡在什么上,常见几种:

stall reason 是 Compute 最有价值的输出:它把”慢”翻译成具体原因。

3. occupancy 与资源

Compute 报告 achieved occupancy(实际驻留 warp)和 theoretical occupancy(受寄存器/shared 限制的上限),以及每线程寄存器、每 block shared memory。两者差距大说明负载不均或尾部效应;理论 occupancy 低说明被资源卡住(第 06 篇)。注意结合 stall 判断 occupancy 够不够——如果 Long Scoreboard 占比低,occupancy 即使不高也够用。

4. 访存细节

l1tex__lts__(L2)相关指标能看缓存命中率;l1tex__data_bank_conflicts_pipe_lsu_mem_shared 直接报 shared memory 的 bank conflict 数。怀疑访问模式问题时看这些。

四、一个标准排查流程

flowchart TD
  A["nsys: 找占时间最多的 kernel"] --> B["ncu: 看 SM/DRAM 吞吐"]
  B -->|"DRAM 接近峰值"| C["memory-bound:<br/>减少访存/融合/合并"]
  B -->|"SM 接近峰值"| D["compute-bound:<br/>换更高吞吐指令/Tensor Core"]
  B -->|"两者都低"| E["看 stall reasons"]
  E -->|"Long Scoreboard"| F["访存延迟暴露:<br/>提 occupancy/改善合并"]
  E -->|"Barrier"| G["同步/负载不均"]
  E -->|"bank conflict 高"| H["加 padding 改 shared 布局"]

这个流程把前面几篇的优化手段串成了可执行的决策树:profiler 给证据,优化手段对症下药。

五、没有完整工具链时的轻量替代

Nsight Compute/Systems 依赖 CUDA 工具链和相应权限,在受限环境(如部分容器、本系列使用的 WSL2 + NVRTC 环境)里不一定能跑——在 WSL2 上 ncu --set full 常因权限不足或硬件计数器不可用而直接失败,这正是本系列用 CUDA event 计时兜底的原因。这种情况下,CUDA event 计时是最小可用的测量手段,也是本系列所有性能数字的来源:

cudaEvent_t start, stop;
cudaEventCreate(&start); cudaEventCreate(&stop);
// 预热若干次后:
cudaEventRecord(start);
my_kernel<<<grid, block>>>(...);
cudaEventRecord(stop);
cudaEventSynchronize(stop);
float ms;
cudaEventElapsedTime(&ms, start, stop);  // GPU 侧耗时,毫秒

要点:

event 计时给不了 stall reason、缓存命中这些细节,但”这个 kernel 多快、贴没贴到带宽/算力屋顶”这类一阶问题它完全够用。能用 ncu 时优先 ncu,受限时用 event 计时兜底。

六、小结与下一步

工具和方法论备齐,从下一篇开始进入真正的算子实现。先从最基础的协作模式——Reduction 与 Scan 开始,它是理解 warp 级原语和 shared memory 协作的入口。

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .