3、NVIDIA Nsight Systems入门:安装与配置、基本界面介绍、首次性能追踪

说实话,Nsight Systems 是我日常工作中用得最多的工具之一。它不像 Nsight Compute 那样盯着单个 kernel 看,而是从全局视角帮你梳理整个应用的性能瓶颈。说白了,它就是 GPU 性能分析的「全景相机」。

我记得第一次用这个工具时,差点被它的界面吓到——怎么这么多面板?但用顺手之后,你会发现它其实非常直观。今天我们就从零开始,把它装好、配好,然后跑一次完整的性能追踪。

3.1 安装与配置

安装这块其实没什么坑,但有几个细节我踩过,得跟你提个醒。

3.1.1 系统要求

先看看你的环境是否满足条件:

组件 最低要求 推荐配置
操作系统 Windows 10 / Ubuntu 18.04 Windows 11 / Ubuntu 22.04
GPU NVIDIA Kepler 架构及以上 Turing 或 Ampere 架构
CUDA 版本 CUDA 10.0+ CUDA 11.8+
磁盘空间 2 GB 10 GB(用于保存 trace 文件)
注意: 我曾经在 Ubuntu 20.04 上装过旧版 Nsight Systems,结果死活打不开界面。后来发现是缺少 libxcb-xinerama0 这个库。如果你遇到类似问题,先跑一下 sudo apt install libxcb-xinerama0

3.1.2 下载与安装

去 NVIDIA 开发者官网下载 Nsight Systems。我个人习惯用命令行安装,干净利落。

# Ubuntu / Debian 系
sudo dpkg -i NsightSystems-linux-public-2023.3.1.97-3304643.deb

# 或者用 runfile 安装
chmod +x NsightSystems-linux-public-2023.3.1.97-3304643.run
sudo ./NsightSystems-linux-public-2023.3.1.97-3304643.run

Windows 用户直接双击 exe 安装包就行,一路 Next。嗯,这里要注意:安装路径不要有中文,否则可能报奇怪的错误。

3.1.3 环境变量配置

装完之后,建议把 nsys 命令行工具加到 PATH 里。我一般这样配:

# 编辑 ~/.bashrc 或 ~/.zshrc
export PATH=/opt/nvidia/nsight-systems/2023.3.1/bin:$PATH

# 验证是否安装成功
nsys --version

如果看到版本号输出,说明装好了。如果提示「command not found」,检查一下安装路径对不对。

小技巧: 我个人习惯把 nsys 的路径写进 alias,比如 alias nsys='/opt/nvidia/nsight-systems/2023.3.1/bin/nsys',省得每次敲长路径。

3.2 基本界面介绍

打开 Nsight Systems,你会看到这样一个界面。别慌,我们一个一个面板来看。

3.2.1 主窗口布局

整个界面分成四个主要区域:

  • 菜单栏和工具栏:最上面一排,文件、编辑、视图这些。常用的就是「File > Open」和「File > New Project」。
  • 项目浏览器:左侧面板,显示你打开过的 trace 文件和项目结构。
  • 时间轴视图:中间最大的区域,这是核心。所有 GPU 活动、CPU 调用、内存操作都在这里以时间线的形式展示。
  • 详细信息面板:右侧或底部,当你点击时间轴上的某个事件时,这里会显示它的详细参数。

你想想看,这就像看一部电影的剪辑软件——时间轴是主战场,其他面板都是辅助信息。

3.2.2 时间轴视图详解

时间轴视图里,每一行代表一个「轨道」。常见的轨道有:

  • CUDA HW:显示 GPU 硬件上的活动,比如 kernel 执行、内存拷贝。
  • CUDA API:显示 CPU 端调用的 CUDA API 函数,比如 cudaMemcpy、cudaLaunchKernel。
  • NVTX:如果你在代码里加了 NVTX 标记,这里会显示自定义的事件范围。
  • Threads:显示 CPU 线程的活动,比如函数调用栈。

我记得第一次看这个时间轴时,发现 kernel 执行和内存拷贝之间有明显的空隙。当时我以为是 GPU 在偷懒,后来才发现是 CPU 端提交命令太慢,导致 GPU 饿着了。这就是 Nsight Systems 的价值——让你看到「看不见的等待」。

3.2.3 常用操作

几个我每天都会用的操作:

  • 缩放:滚轮缩放时间轴,或者按住 Ctrl 拖动鼠标框选区域。
  • 测量:按住 Shift 然后拖动,可以测量两个事件之间的时间差。
  • 搜索:按 Ctrl+F 搜索 kernel 名称或 API 函数。
  • 导出:File > Export 可以导出为 CSV 或 JSON 格式,方便做进一步分析。
核心观点: Nsight Systems 的界面设计理念是「从宏观到微观」。先看整体时间轴,找到热点区域,再放大看细节。不要一上来就盯着某个 kernel 看,那样容易迷失。

3.3 首次性能追踪

理论说完了,我们来实战。我会用一个简单的 CUDA 程序做演示。

3.3.1 准备测试程序

先写一个简单的向量加法程序,保存为 vector_add.cu

#include <cuda_runtime.h>
#include <stdio.h>

__global__ void vec_add(float *a, float *b, float *c, int n) {
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    if (idx < n) {
        c[idx] = a[idx] + b[idx];
    }
}

int main() {
    int n = 1 << 20;  // 1M 个元素
    size_t bytes = n * sizeof(float);

    float *h_a, *h_b, *h_c;
    float *d_a, *d_b, *d_c;

    // 分配主机内存
    h_a = (float*)malloc(bytes);
    h_b = (float*)malloc(bytes);
    h_c = (float*)malloc(bytes);

    // 初始化数据
    for (int i = 0; i < n; i++) {
        h_a[i] = 1.0f;
        h_b[i] = 2.0f;
    }

    // 分配设备内存
    cudaMalloc(&d_a, bytes);
    cudaMalloc(&d_b, bytes);
    cudaMalloc(&d_c, bytes);

    // 拷贝数据到 GPU
    cudaMemcpy(d_a, h_a, bytes, cudaMemcpyHostToDevice);
    cudaMemcpy(d_b, h_b, bytes, cudaMemcpyHostToDevice);

    // 启动 kernel
    int threads = 256;
    int blocks = (n + threads - 1) / threads;
    vec_add<<<blocks, threads>>>(d_a, d_b, d_c, n);

    // 拷贝结果回 CPU
    cudaMemcpy(h_c, d_c, bytes, cudaMemcpyDeviceToHost);

    // 验证结果
    printf("c[0] = %f\n", h_c[0]);

    // 清理
    cudaFree(d_a);
    cudaFree(d_b);
    cudaFree(d_c);
    free(h_a);
    free(h_b);
    free(h_c);

    return 0;
}

编译它:

nvcc -o vector_add vector_add.cu

3.3.2 运行性能追踪

现在用 nsys 来追踪这个程序。最基本的命令是:

nsys profile -o vector_add_report ./vector_add

解释一下参数:

  • profile:告诉 nsys 我们要做性能追踪。
  • -o vector_add_report:指定输出文件名为 vector_add_report,默认会生成 .nsys-rep 文件。
  • ./vector_add:要追踪的可执行文件。

运行后,你会看到类似这样的输出:

Collecting data...
Processing events...
Generated: /home/user/vector_add_report.nsys-rep

嗯,这里要注意:如果程序运行时间很短(比如几毫秒),nsys 可能采集不到足够的数据。我建议在测试程序里加一些循环,让 GPU 多跑几次。

3.3.3 打开并分析报告

用 Nsight Systems GUI 打开生成的 .nsys-rep 文件:

nsys-ui vector_add_report.nsys-rep

或者直接在 GUI 里 File > Open。

打开后,你会看到时间轴视图。放大到 kernel 执行的部分,你应该能看到:

  • 两个 cudaMemcpy 操作(Host to Device)
  • 一个 vec_add kernel 执行
  • 一个 cudaMemcpy 操作(Device to Host)

这就是一个典型的「三段式」GPU 工作流:数据上传 → 计算 → 结果下载。

关键观察: 看看 kernel 执行和内存拷贝之间有没有空隙。如果有,说明你的程序在「串行化」这些操作。理想情况下,你应该用 CUDA Stream 让它们重叠执行。

3.3.4 常用追踪选项

nsys 有很多选项,我常用的几个:

选项 作用 示例
--trace=cuda,osrt 只追踪 CUDA 和操作系统运行时调用 nsys profile --trace=cuda,osrt ./app
--stats=true 在终端输出统计摘要 nsys profile --stats=true ./app
-c cudaProfilerApi 通过 cudaProfilerStart/Stop 控制追踪范围 nsys profile -c cudaProfilerApi ./app
--duration=10 只追踪前 10 秒 nsys profile --duration=10 ./app
避坑指南: 我曾经在追踪一个大型应用时,忘了加 --trace 限制,结果 nsys 采集了所有系统调用,生成的文件有 20 多 GB。打开时直接卡死。建议第一次跑时先用 --trace=cuda 缩小范围。

3.4 本章小结

今天我们走完了 Nsight Systems 的入门流程:安装、界面认识、第一次性能追踪。你想想看,其实核心就三件事:装好工具、看懂时间轴、跑一次 trace。

我个人觉得,Nsight Systems 最厉害的地方不是它有多少功能,而是它让你「看到」程序的执行过程。很多性能问题,光看代码是看不出来的,必须跑一次 trace 才能发现。

下一章我们会深入时间轴视图,学习如何解读那些花花绿绿的条条块块。到时候我会分享一些我实际项目中遇到的「诡异」性能问题,保证让你大开眼界。


专注资料整理