三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

使用 NVIDIA Nsight Aftermath排查 Shader 错误导致的 GPU Hung

使用 NVIDIA Nsight Aftermath排查 Shader 错误导致的 GPU Hung

使用 NVIDIA Nsight Aftermath 排查 Shader 错误导致的 GPU Hung

一、问题背景:为什么 GPU Hung 难以调试?

在现代图形渲染管线(D3D12/Vulkan)中,GPU Hung(设备丢失/挂起) 是最棘手的问题之一。当 GPU 因 Shader 错误(如无限循环、非法内存访问、寄存器溢出)而挂起时,CPU 端通常只能收到一个模糊的 DXGI_ERROR_DEVICE_REMOVEDVK_ERROR_DEVICE_LOST,而 GPU 端的执行状态对开发者完全黑盒。

Nsight Aftermath 是 NVIDIA 提供的 GPU 崩溃/挂起诊断工具,能够捕获 GPU 崩溃转储(Crash Dump),将 GPU 微观执行状态映射回 Shader 源码,从而精确定位问题。

二、Aftermath 核心工作流程

Aftermath 提供两种工作模式:

模式 1:GPU Crash Dump Monitor(免代码集成)

适合快速诊断,无需修改应用程序代码:

  1. 启动 GPU Crash Dump Monitor(随 Nsight Graphics 安装)
  2. 配置崩溃转储目录和 Shader Debug 信息目录
  3. 设置 Aftermath 模式为 Global(全局监控)或 Whitelist(指定应用)
  4. 运行目标程序,复现 GPU Hung
  5. 自动生成的 .nv-gpudmp 文件可直接在 Nsight Graphics 中打开分析

模式 2:SDK 集成(生产环境推荐)

在引擎中直接集成 Aftermath SDK:

// 初始化 Aftermath
GFSDK_Aftermath_Result result = GFSDK_Aftermath_DX12_Initialize(GFSDK_Aftermath_Version_API,GFSDK_Aftermath_FeatureFlags_EnableMarkers | GFSDK_Aftermath_FeatureFlags_GenerateShaderDebugInfo,nullptr  // 使用默认回调
);// 注册资源(可选,用于追踪内存错误)
GFSDK_Aftermath_DX12_RegisterResource(device, resource, "MyTexture");// 在关键渲染节点插入标记
GFSDK_Aftermath_SetEventMarker(pCommandList, "DrawShadowPass", 0);

崩溃时,应用会自动输出 .nv-gpudmp.nvdbg 文件。


三、Shader 级调试:关键配置

3.1 生成 Shader Debug 信息

这是定位 Shader 错误的必要前提。Aftermath 需要两级 Debug 信息:

层级 说明 生成方式
Shader IL 调试信息 将 GPU 微码映射回 DXIL/SPIR-V Aftermath 驱动自动生成 .nvdbg 文件
源码调试信息 将 DXIL/SPIR-V 映射回 HLSL/GLSL 编译器生成(dxc -ZiglslangValidator -g

D3D12 编译示例:

# 方式1:完整 Blob(推荐用于调试阶段)
dxc -Zi -T ps_6_6 -Fo shader.bin shader.hlsl# 方式2:分离调试信息(推荐用于发布版调试)
dxc -Zi -T ps_6_6 -Fo shader.bin -Fd debugInfo\ shader.hlsl

Vulkan 编译示例:

glslangValidator -V -g -o shader.spv shader.vert
# 或使用 DXC 编译 SPIR-V
dxc -spirv -Zi -T ps_6_6 -Fo shader.spv shader.hlsl

3.2 启用额外 Shader 错误报告

在 Crash Dump Monitor 设置中勾选 "Enable Additional Shader Error Reporting",或在 SDK 中启用对应标志。这会使 GPU 进入特殊模式,对以下情况抛出异常而非静默忽略:

  • 内存未对齐访问(如读取非 4 字节对齐的 float4
  • 越界内存访问(Shared Memory、Thread Local Memory、Constant Buffer)
  • 纹理格式/布局不兼容访问
  • 调用栈深度超限

⚠️ 注意:此功能需要驱动 R515 或更高版本,且可能暴露原本被硬件静默忽略的潜在 Bug。

3.3 启用 SM 寄存器数据收集

System Settings 中启用 "Enable SM Register Data Collection"(R535+ 驱动,R550+ 默认开启)。这会在 SM(Streaming Multiprocessor)发生故障时收集寄存器值,对分析 Shader 执行状态至关重要。


四、分析 GPU 崩溃转储:实战步骤

4.1 打开转储文件

在 Nsight Graphics 中打开 .nv-gpudmp 文件,首先查看 Dump Info 标签页的 Exception Summary

  • Device Hung:GPU 无响应,通常由 Shader 无限循环或超长执行导致
  • Page Fault:非法内存访问
  • Shader Fault:Shader 执行错误

4.2 定位问题 Shader:Active Warps / Faulted Warps

这是排查 Shader Hung 的核心视图

Crash Info 标签页中:

区域 作用
Active Warps 崩溃时正在执行的 Shader Warp,若 GPU Hung 通常有 Warp 卡在循环中
Faulted Warps 触发错误的 Warp,显示错误类型、Shader Hash、GPU PC 地址
Active/Faulted Warps 可展开查看每个 Warp 的详细状态

关键列说明:

  • GPU PC Address:GPU 程序计数器,点击可跳转到 Shader View
  • Shader Hash:用于匹配对应的 Shader 二进制文件
  • Shader Location:若调试信息完整,直接显示 HLSL/GLSL 源码行号

4.3 Shader View:源码级定位

点击 Warp 条目后,Shader View 会显示:

  1. GPU 微码指令(最底层)
  2. DXIL/SPIR-V 中间指令
  3. HLSL/GLSL 源码(若编译时带 -Zi-g

排查重点:

  • 若 PC 地址停在循环跳转指令 → 无限循环
  • 若 PC 地址停在纹理采样指令 → 纹理越界或格式错误
  • 若 PC 地址停在除法/开方指令 → 除零或非法数学操作

五、典型 Shader Hung 场景与排查方法

场景 1:无限循环(最常见)

现象:GPU 无响应,Active Warps 显示大量 Warp 卡在相同 PC 地址。

排查方法

  1. 在 Shader View 中查看该 PC 地址对应的源码行
  2. 检查循环条件是否依赖了可能永不满足的数据(如 while (particle.life > 0)life 被错误初始化)
  3. 检查线程发散(Divergence)导致的某些 Warp 无法退出循环

场景 2:非法内存访问(Page Fault)

现象:Exception Summary 显示 Page Fault,Faulted Warps 有具体错误。

排查方法

  1. 查看 Page Fault 区域的虚拟地址和访问类型(Read/Write)
  2. 查看 Page Fault Resource History,识别被访问的资源
  3. 检查 Shader 中数组/缓冲区索引是否越界:
    // 危险代码
    float4 data = myBuffer[instanceID * 4 + threadID]; // 若 instanceID 非法则越界
    

场景 3:寄存器压力导致超时

现象:复杂 Shader(如大量光线追踪或嵌套循环)导致 GPU 看门狗超时。

排查方法

  1. 检查 Active Warps 是否集中在复杂计算 Shader
  2. 使用 Nsight Graphics 的 GPU TraceFrame Profiler 分析 Shader 复杂度
  3. 优化:减少寄存器使用、拆分 Pass、降低线程组大小

六、常见问题与解决方案

问题 1:Shader Hash 显示 "N/A"

如开发者论坛报告,某些情况下 Aftermath 无法捕获 Compute Shader 的 Hash。

解决方案

  • 确保使用 Aftermath SDK 2024.1+
  • 检查是否启用了 GFSDK_Aftermath_FeatureFlags_GenerateShaderDebugInfo
  • 确认 Shader 是通过标准编译流程加载(非手动拼接字节码)

问题 2:无法映射到源码行号

解决方案

  1. 在 Nsight Graphics Search Path Settings 中正确配置:

    • Shader Binaries:存放 .bin / .spv 的目录
    • Separate Shader Debug Information:存放 .pdb / .lld 的目录
    • NVIDIA Shader Debug Information:存放 .nvdbg 的目录
    • Shader Source:存放 .hlsl / .glsl 的目录(通常不需要,若使用 #line 指令则需要)
  2. 确保编译时使用了正确的 Debug 标志(-Zi 对应 D3D12,-g 对应 Vulkan)

问题 3:启用 Debug 信息后驱动崩溃

已知问题:某些 FP16 操作在生成 Shader Debug Symbol 时可能导致驱动崩溃。

规避方案

  • 临时禁用 "Collect Line Tables"(Frame Debugger/Profiler 设置中)
  • 禁用 Aftermath 的 "Generate Shader Debug Information"
  • 更新到最新驱动版本

实战
光追shader CBV使用DescriptorTable绑定,在遇到CB访问越界 导致的gpuhung

image

相关资源

  • GPU Crash Dump 设置指南
  • GPU Crash Dump Inspector UI 参考
  • GPU Crash Dump Monitor 设置

这篇文章涵盖了从环境配置、SDK 集成、Shader 编译参数设置,到崩溃转储分析的全流程。如果你需要针对特定场景(如光线追踪 Shader 或计算 Shader)的更深入内容,可以告诉我,我可以进一步补充。

← 返回列表