2. Nsight Systems快速上手
Nsight Systems 是 NVIDIA 提供的系统级性能分析工具,它回答的第一个问题不是“这个内核为什么慢”,而是“这段时间里 GPU 到底在忙什么、CPU 在等什么、数据搬了多少”。它通过采样与追踪相结合的方式,把 CPU 线程、CUDA API、内核执行、内存拷贝、同步事件统一放到一条时间轴上,因此特别适合做宏观瓶颈定位。本节的目标是让你能独立完成一次完整采集:装好工具、用命令行或 GUI 采集一个 CUDA 程序、打开时间线、并快速读出内核与内存拷贝的分布特征。
安装与配置
Nsight Systems 的安装有三条常见路径。第一,随 CUDA Toolkit 一起安装,Linux 下通常位于 /usr/local/cuda/bin/nsys,Windows 下位于 CUDA 安装目录的 nsight-systems 子目录。第二,从 NVIDIA 官网单独下载 Nsight Systems 安装包,这种方式可以拿到比 CUDA 自带版本更新的功能。第三,在容器或远程服务器上,只安装命令行版本 nsys,采集后用本地 GUI 打开报告。
安装完成后先做两件事:确认版本、确认权限。执行 nsys --version 应输出类似 NVIDIA Nsight Systems version 2024.x.x 的信息。权限方面,Linux 下普通用户采集 GPU 指标需要访问性能计数器,通常要设置 perf_event_paranoid 或使用 sudo;如果只采集 CUDA API 与内核时间线,一般不需要额外提权。远程采集时,建议在目标机上只跑 nsys profile,把生成的 .nsys-rep 文件拷回本地用 GUI 分析,避免远程图形界面的开销干扰数据。
nvidia-smi 确认当前 GPU 上没有别的计算进程。命令行采集:一条命令拿到时间线
最常用的采集命令是 nsys profile。假设我们有一个编译好的 CUDA 程序 vec_add,它执行一次向量加法,包含一次 H2D 拷贝、一次内核、一次 D2H 拷贝。采集命令如下:
nsys profile \
--trace=cuda,nvtx,osrt \
--sample=cpu \
--output=vec_add_report \
--force-overwrite=true \
./vec_add 1048576
这里几个参数值得解释。--trace=cuda,nvtx,osrt 指定追踪 CUDA API、NVTX 标记和操作系统运行时调用;--sample=cpu 打开 CPU 采样,用于观察 CPU 侧热点;--output 指定输出文件名,实际会生成 vec_add_report.nsys-rep;--force-overwrite=true 允许覆盖同名文件。程序参数 1048576 表示向量长度,属于示例参数,实际运行时按你的程序接口调整。
采集结束后,命令行会打印一段摘要,包括内核数量、内存拷贝次数、总耗时等。如果只想快速看统计而不打开 GUI,可以用 nsys stats:
nsys stats --report cuda_gpu_kern_sum,cuda_gpu_mem_time_sum vec_add_report.nsys-rep
其中 cuda_gpu_kern_sum 汇总每个内核的调用次数与总耗时,cuda_gpu_mem_time_sum 汇总内存拷贝的方向与耗时。这两个报告是识别宏观分布最快的手段。
GUI 基本操作
在本地打开 Nsight Systems GUI,选择 File → Open 载入 .nsys-rep 文件。界面主要分三块:上方是时间线视图,左侧是进程/线程树,右侧是事件详情面板。时间线视图里,每一行代表一个 CPU 线程或一条 GPU 流,横向是时间,色块代表事件。CUDA API 调用显示在 CPU 线程行上,内核和内存拷贝显示在 GPU 流行上。
常用操作包括:鼠标滚轮缩放时间轴,按住中键拖动平移,双击某个色块可以跳转到对应事件并在右侧查看参数。顶部工具栏的 Events View 可以切换到表格模式,按耗时排序内核和拷贝。对于初学者,建议先看 GPU 行上的色块分布,再看 CPU 行上是否有长时间等待。
时间线阅读:内核与内存拷贝的宏观分布
打开报告后,先看 GPU 行。典型的一次向量加法采集会呈现这样的结构:最左侧一个较短的 H2D 拷贝块,中间一个内核块,右侧一个 D2H 拷贝块。如果内核块很长而拷贝块很短,说明计算是主要开销;如果拷贝块与内核块长度相当,甚至拷贝更长,说明数据传输是瓶颈,需要考虑使用 pinned memory 或减少拷贝次数。
再看 CPU 行。CUDA API 调用(如 cudaMemcpy、cudaLaunchKernel)会以细长色块出现。如果 CPU 行上出现大段空白,说明 CPU 在等待 GPU 完成,此时 GPU 可能已经空闲,属于同步等待造成的利用率下降。如果 CPU 行上 API 调用密集且 GPU 行有空隙,说明启动开销或同步策略有问题。
下面这张图展示了一次示例采集的宏观时间线结构,用于对照理解内核与内存拷贝在时间轴上的相对位置和长度关系。
从图中可以看到,示例程序在 H2D 拷贝之后、内核启动之前,CPU 行上有一段“等待 GPU”的空白,GPU 行上也出现了“GPU 空闲”区间。这说明程序在拷贝与内核之间存在同步点,导致 GPU 短暂闲置。实际分析时,这类空隙就是优化切入点:能否用异步拷贝 cudaMemcpyAsync 配合流来重叠传输与计算。
用统计报告快速定位
时间线适合看结构,统计报告适合看占比。执行 nsys stats 后,cuda_gpu_kern_sum 会给出类似下面的示例输出(数值为示例,非实测):
Time (%) Total Time (ns) Instances Avg (ns) Name
-------- --------------- --------- -------- ----
62.3 1,245,000 1 1245000 vec_add_kernel
21.1 422,000 1 422000 [CUDA memcpy H2D]
16.6 332,000 1 332000 [CUDA memcpy D2H]
这张表直接告诉你:内核占总 GPU 时间的 62.3%,两次拷贝合计约 37.7%。如果目标是提升整体性能,优先优化内核;如果拷贝占比超过一半,则应先处理数据传输。注意 Instances 列,如果某个内核被调用上千次而每次耗时很短,说明启动开销可能成为问题,需要合并内核或使用 CUDA Graph。
一次完整采集的检查清单
- 确认
nsys --version可用,远程采集时确认目标机权限。 - 用
nsys profile --trace=cuda,nvtx,osrt --sample=cpu -o 报告名 ./程序 参数采集。 - 用
nsys stats --report cuda_gpu_kern_sum,cuda_gpu_mem_time_sum先看统计占比。 - GUI 打开报告,先看 GPU 行色块分布,再看 CPU 行等待与空隙。
- 记录内核总时间、拷贝总时间、GPU 空闲区间,作为后续优化的基线。
完成以上步骤,你就已经具备用 Nsight Systems 做宏观瓶颈定位的能力。下一阶段的分析会深入到单个内核内部,而本节建立的“时间线 + 统计占比”视角,是后续所有深入分析的基础参照。