这篇文章最初发表在 NVIDIA 技术博客上。
NVIDIA 提供了大量的图形调试工具,包括 NVIDIA Nsight System 用于 CPU 调试,Nsight Graphics 用于 GPU 调试。而 Nsight Aftermath 则可用于分析崩溃转储文件。
推荐
- 始终检查验证层,并确保它们不会输出任何错误。
- 使用 Nsight Aftermath 进行详细的 DirectX 12 或 Vulkan GPU 异常调试。
- 使用 Nsight Aftermath Monitor 是一种简单的入门方法,无需集成代码。
- 如需进一步控制 GPU 崩溃转储功能,请考虑使用 Aftermath SDK 将崩溃转储功能集成到您自己的代码中。
- 由于没有相关的运行时成本,因此始终可以启用崩溃转储生成。正如稍后指出的,调试检查点可能会产生可测量的 CPU 开销,因此不应用于交付应用程序。
- 您可以使用 API 中提供的回调函数将崩溃转储保存到本地磁盘,或将其推送到云端。
- 有关更多信息,请参阅 Nsight Aftermath SDK 产品页面。
- 使用调试检查点来隔离问题。
- 这些 API 支持在 GPU 命令流中插入检查点,从而将崩溃缩小到命令流的某些子部分。
- 使用 Nsight Aftermath 支持的 API。想要了解更多信息和示例,请访问 NVIDIA/nsight-aftermath-samples GitHub 存储库。
- 或者,使用 DirectX 12 跨供应商解决方案:
- 使用
ID3D12GraphicsCommandList2::WriteBufferImmediate
或 DRED。 - 不支持将其与 Nsight Aftermath 结合使用,因此最好避免混合使用。
- 使用
- 在引擎中添加运行时标志以切换此功能。
- 这些标记并非免费,并且会产生相关的运行时成本(包括序列化 GPU、CPU 调用的开销以及捕获调用堆栈的时间)。
- 默认情况下,保持启用可能会导致严重的性能损失。
- 请参阅我们的不推荐部分。
- 使用调试信息构建着色器。
- 使用/Zi 进行编译,以将调试信息嵌入着色器二进制文件。
- 这在使用 NVIDIA Nsight Graphics 等调试工具时非常有用。
- 此外,Nsight Aftermath 可以使用此信息为您提供源级 GPU 崩溃信息。
- 使用 Nsight Aftermath 崩溃转储文件识别崩溃期间发生的错误类型。
- 设备挂起:
- 由于单个命令列表的执行时间超过几秒钟,因此可能会出现这些情况。
- 在驱动程序和 GPU (TDR) 没有明显反馈的情况下,Microsoft Windows 会在几秒钟后终止驱动程序。
- 在极端工作负载(大规模像素过度绘制或光线追踪加速结构降低)的情况下也会发生这种情况。
- 分页错误
- 这些问题是由无效的内存访问引起的:越界读取/写入或无效的资源。
- 有关更多信息,请参阅 如何设置和检查 GPU 崩溃转储。
- 设备挂起:
- 针对图形和计算相关问题的通用调试建议:
- 在 GPU 访问数据时,检查所有引用内存是否始终有效且正确。
- 检查描述符是否指向已完全分配和初始化的正确资源。
- 检查数据读取和写入是否越界。
- 使用 Nsight Aftermath 的调试检查点和 GPU 崩溃转储功能缩小崩溃位置。
- DirectX 12:调试层可以在这里提供帮助,但对于这些问题,必须启用基于 GPU 的验证,这通常会使应用程序在复杂场景中的运行速度极慢。它在单元测试或回归测试中仍然有用。
- 针对 NVIDIA RTX 相关问题的通用调试建议:
- 检查输入的顶点或索引数据是否均有效。
- 无效的索引可能会导致 GPU 构建器核函数崩溃。
- 无效的顶点可能会影响加速结构,并导致性能极其缓慢。
- 将光栅化程序中可用的三角形或三角形断开连接的技巧无法按预期在加速树中发挥作用,因此可能会导致大问题。检查是否未使用此类技巧,例如断开连接或删除几何图形。只能使用有效的几何图形。
- 在构建器或光线追踪内核引用数据时,检查内存是否仍然有效。
- 检查光线追踪内核使用的所有纹理和缓冲区是否都有效。
- 检查描述符是否正确,以及着色器绑定表是否有效。
- 调试检查点对于调试光线追踪工作负载没有用,因为 RT 内核中发生的间接可能会触及数千个着色器排列。它最多可以判断崩溃是在构建器还是光线追踪内核中发生的。
- 而是使用 Nsight Aftermath 崩溃调试来大致了解崩溃情况:
- 分页错误:与内存相关的问题,通常是越界读取 -- 写入或尝试访问已删除或尚未复制到 GPU 的资源。
- GPU 挂起 (TDR):无限循环、过于复杂的着色或过多的光线。
- 提供一种简化代码和绑定要求的方法可能很有用,例如禁用纹理或减少着色器排列。
- 例如,让调试视图仅显示质心(无着色器绑定表要求)。
- 检查外观是否损坏的几何图形或由于三角形数据损坏而导致性能严重下降的点。
- 在仅采用光线追踪的视图中直观验证动态源的输出,例如变形的几何图形或蒙皮网格。
- 完全禁用动态几何图形也有助于隔离此类问题。
- 例如,让调试视图仅显示质心(无着色器绑定表要求)。
- 检查输入的顶点或索引数据是否均有效。
- 在应用程序中为以下内容添加标志,以简化调试:
- 在队列级别序列化 GPU/CPU.
- 在命令列表级别序列化 GPU/CPU.
- 禁用异步计算。
- 禁用异步复制。
- 在命令列表(NULL UAV/内存屏障)中添加计算、分配和复制调用之间的完整屏障。
- 采取其他措施消除并行性。当 GPU 同时运行多个工作负载时,很难进行调试并找出问题的根源。
- 请勿默认启用这些建议。它们应严格仅限调试标志。减少并行性会显著降低性能。
不推荐
- 使用过多的调试检查点。
- 它们的 CPU 和 GPU 性能成本不容忽略。
- 小心谨慎。每帧瞄准 100 欧元,最好更少。
- 最好不要为最终用户(仅限开发者或 QA)使用它们,或者在检测到 GPU 挂起时启用它们。您还可以让最终用户选择切换它们。
- 假设 CPU 调用堆栈会告诉您有关 GPU 问题的任何信息。
- 当调用堆栈指向驱动程序时崩溃,通常表现为随机图形 API 调用因内部设备丢失事件而失败。
- 使用 Nsight Aftermath 崩溃转储文件或调试检查点来确定故障发生的位置。
- 在单台机器上进行测试(不包括硬件性能不佳的影响)。
- 内存(CPU 或 GPU)损坏、超频和冷却不良都会导致随机错误。Nsight Aftermath 无法将这些错误与有效错误区分开来。
- 一个明显的迹象可能是,崩溃是随机发生的,在单台机器上的 GPU 上没有任何模式,而在另一台具有类似规格的机器上没有任何模式。
- 尝试在多台具有相似硬件、软件和驱动版本的计算机上验证结果。
- 允许用户运行非常过时的 NVIDIA 驱动
- 过时的驱动程序可能会有意想不到的行为,并且更难以从中获得可靠的崩溃转储文件。
- 找到可靠运行的驱动程序版本。显示一个弹出窗口,其中显示当驱动程序版本早于该版本时,驱动程序已过时。不要阻止用户运行应用程序或游戏,但不要阻止他们这样做,因为这会导致系统不稳定。
致谢
感谢 Patrick Neill、Jeffrey Kiel、Justin Kim、Andrew Allan 和 Louis Bavoil 在本文中的帮助。