内容创建/渲染

强大的着色器见解:通过 NVIDIA Nsight Graphics 使用着色器调试信息

随着光线追踪成为现代游戏引擎中的主要渲染技术,单个 GPU RayGen 着色器现在可以执行帧的大部分光线模拟。为了管理这种复杂程度,有必要在 HLSL 或 GLSL 源代码级别观察着色器性能的分解。因此,着色器分析器现在是优化光线追踪的必备工具。

在本文中,我将向您展示如何使用 NVIDIA Nsight Graphics 的 GPU Trace Profiler 来分析低级别的着色器性能,以及如何启用 DirectX 编译器 (DXC) 的调试信息选项 -Zi。在整个博文中,我将使用以下缩写:

没有着色器调试信息的 GPU Trace

Path Tracing SDK 示例使用嵌入式着色器调试信息编译所有着色器 (-Zi) 作为 DXC 命令行选项,CMake 文件 中进行了配置。如果不需要 -Zi 选项,可以从 Visual Studio 解决方案中删除它并进行重建。

我还使用默认设置 (启用了 Real-Time Shader Profiler 并锁定了 GPU 时钟),从修改后的 Path Tracing SDK 演示应用中生成了 GPU Trace。图 1 展示了在选中 PathTrace 标记的工具中的效果。

Screenshot of the Nsight Graphics GPU Trace Profiler, with metric graphs on top and the real-time shader profiler panel on the bottom right.
图 1.无着色器调试信息的 NVIDIA Nsight Graphics GPU Trace 默认视图

热点不显示任何 HLSL,仅显示 DXIL 链接。单击顶部热点的 DXIL 链接,工具会跳转到 DXIL 行,Sample%Stall reason%s要知道此线映射到哪条 HLSL 线很有挑战性 (图 2)。

Screenshot of GPU Trace without shader debugging information.
图 2.在没有着色器调试信息的情况下,Shader Source 部分中只有 DXIL 可用

查看底部面板中的 Shader Pipelines 选项卡 (图 3),可以看到相关列包含以下警告:“Shader bytecode not contain debug info,recompile the shader with enabled debug info to 解决此问题。”

creenshot with tooltip that reads, “Shader bytecode does not contain debugging information. Recompile the shader with debug info enabled to solve this issue.”
图 3.关于“Shader Pipelines”(着色器管线) 部分中缺少着色器调试信息的警报

GPU Trace Profiler 在 SASS 级别收集其着色器分析数据,SASS 是在 GPU 上执行的低级指令集。它始终可以将 SASS 级别的分析数据与 DXIL (或 SPIR-V) 中间语言关联起来。

但是,要使 GPU Trace Profiler 将分析数据与高级语言 (HLSL 或 GLSL) 关联,DXIL 必须包含着色器调试信息。具体来说,DXIL 必须包含 HLSL 源代码和将 HLSL 行与 DXIL 行关联的行表。请参阅 着色器编译部分,了解如何在 NVIDIA Nsight Graphics 用户指南中根据 HLSL 的编译方式启用着色器调试信息。

在开发过程中,我建议将着色器调试信息嵌入到 DXIL Blob 中。也就是说,使用 -Zi -Qembed_debug 而不是着色器 PDB,这样您的 GPU Trace 文件就是独立的。有关详细信息,请参阅 microsoft/DirectXShaderCompiler 在 GitHub 上发布。

使用此方法时,您无需手动跟踪使用哪种追踪的着色器 PDB.如果嵌入着色器调试信息会导致 DXIL Blob 过大或出现问题,您还可以配置 DXC,将着色器调试信息作为单独的着色器 PDB 文件写入到文件夹中,-Zi-FdDXC 选项。在这种情况下,您需要在加载 GPU Trace 文件之前,在 Nsight Graphics Options 中配置单独着色器调试信息的搜索路径。

包含着色器调试信息的 GPU Trace

图 4 展示了在 Visual Studio 解决方案中使用原始版本重建演示应用后的 Shader Pipelines 部分,以及 DXC 命令行参数 -Zi -Qembed_debug,用于光线追踪着色器。这些设置通过 GPU Trace Profiler 捕捉了新的追踪。

Screenshot showing that the Correlation column now contains HLSL/DXIL green icons for all shaders, except for the unknown samples.
图 4.启用后,所有着色器都具有 HLSL 相关性-Zi“Shader Pipelines”(着色器管线) 部分

通过单击“Bottom-Up Calls”(自下而上调用) 选项卡,您现在可以轻松查看昂贵的 HLSL 函数、它们执行的 GPU 工作类型以及在较高水平限制它们的因素 (图 5)。请注意,在未加载调试符号时,不存在“Bottom – Up Calls”(自下而上调用) 选项卡以及“Top – down Calls”(自上而下调用) 选项卡。

Screenshot showing HLSL function names along with their corresponding filenames and line numbers, and their percentage of total samples and issue stall reasons.
图 5.HLSL 级别的自下而上调用

在本示例中,“Bottom-Up Calls”(自下而上调用) 部分中的第三个 HLSL 函数是随机数生成器,bhos_sobol获取 4.5%的 PathTrace 标记,以及 60%的 HLSL 函数的顶部问题停滞 (NOINST) (通常等待指令缓存丢失)。

在图 6 中,HLSL 视图显示,展开循环的主体是产生所有延迟的地方,顶部 SM 问题停滞原因是 NOINST.这可以通过存在多次迭代的展开循环来解释,该循环会生成许多硬件指令,并对 GPU 的指令缓存造成压力。

Screenshot of HLSL implementation of the hbos_sobol function.
图 6.HLSLbhos_sobol函数

由于指令缓存受限,此函数的一种可能优化策略是在结构化缓冲区中预计算其输出值。SDK 版本 v1.2.0 已支持此路径,尽管默认情况下未启用此路径。

// In Config.h

#define  USE_PRECOMPUTED_SOBOL_BUFFER       1               // see NoiseAndSequences.hlsli - still experimental, faster but lower quality and more RAM - not a clear win



// In NoiseAndSequences.hlsli

uint bhos_sobol(uint index, uniform uint dimension)

{

    return SOBOL_PRECOMPUTED_BUFFER[ (index % SOBOL_PRECOMPUTED_INDEX_COUNT) + SOBOL_PRECOMPUTED_INDEX_COUNT * dimension ];

}

结束语

在使用 NVIDIA Nsight Graphics GPU Trace 的实时着色器分析器时,请确保在右下角面板的“Shader Pipelines”部分中,所有着色器都已启用 HLSL 相关。如果发现有样本显著但 HLSL 相关缺失的着色器,请按照 NVIDIA Nsight Graphics 用户指南中的说明,在启用调试信息的情况下重新编译这些着色器。然后,捕捉一个新的 GPU 追踪。

相较于在启用 HLSL 关联的情况下重新运行,尝试在不使用 HLSL 关联的情况下使用着色器分析器数据将节省时间。HLSL 调试数据对于 Nsight Graphics Shader Debugger 等未来功能至关重要,使您能够正确调试着色器代码,以及 NVIDIA Nsight Aftermath

致谢

我要感谢 Aurelio Reis、Avinash Baliga、Axel Mamode、Robert Jensen、Iain Cantlay、Filip Strugar、Ivan Fedorov 和 Juha Sjoholm 为本文做出的贡献。

 

Tags