图形开发者和发烧友的一大消遣方式是比较 GPU 的规格,并惊叹于每一代新一代产品中着色器核心、RT 核心、万亿次浮点运算能力和整体计算能力的不断增加。实现这些数字所代表的最大理论性能是图形编程领域的一大关注点。大量渲染数据(例如三角形、像素和光线)流经高度并行的 GPU 计算管线,就像在制造工厂的一组装配线上一样。最大吞吐量要求工厂持续运行,不会中断工作或设备闲置。
本文介绍了 Nsight Graphics 2024.3 中的几个新功能,帮助您了解和管理这些虚拟装配线,并为游戏和图形应用程序创建优化的并行工作负载。
每个线程束的活动线程直方图
线程束 是一组 32 个线程,构成可编程着色器的基本执行单元。使用 HLSL 或 GLSL 编写的光线追踪、计算、顶点、像素和其他类型的着色器可编译为机器指令,并最终在线程束大小的硬件组上运行。线程束中的线程并行运行,数百个线程束本身并行运行。当可编程着色成为工作负载的限制因素时,高效运行线程束对于达到峰值性能至关重要。
线程束在名为 Streaming Multiprocessor (SM) 的硬件单元上运行,并使用名为 Single Instruction, Multiple Threads (SIMT) 的计算模型执行。每个线程束一次在其所有线程上发出一条指令,且每个线程都有自己的操作数。例如,如果一行着色器代码添加两个数字,则在一个线程束中,加法指令开始在所有 32 个线程中同时运行,从而从 64 个输入中生成 32 个唯一的和。
线程束以次优方式运行的一种方法是通过着色器代码中的 if 语句或控制流分支导致线程差异。编译器可以通过在 if 语句下运行所有代码块,然后忽略未使用的结果,或使用展开的循环来完全避免分支。但是,当真正的动态分支被编译下来并在执行时遇到时,并且条件表达式在线程束中的所有线程之间不是统一的,则线程束必须一次同时执行 if-body 和 else-body。
同样,在 SIMT 模型中一次只能发出一条指令,因此 SM 必须屏蔽不适用于分支活动端的线程。有关现代 NVIDIA GPUs 中线程束指令调度的更完整说明,请参阅 NVIDIA Tesla V100 GPU 架构 (第 26 页)。
图 1 显示了线程束中线程发散的简化可视化,线程束的假设大小为 8 个线程。大写字母表示程序伪代码中的语句。由于发出每个指令时线程执行的空闲通道,吞吐量会降低。
请注意,这不同于前面提到的以无分支方式在 if 语句中运行两个块。真正的分支可以避免线程未执行的任何副作用。更重要的是,当驱动分支的条件表达式有良好的 warp 级分布时,动态分支可以成为制胜法。条件表达式得到的齐次结果越多,差异就越小,因此对吞吐量的影响就越小。在 vertex 和 pixel shaders 中, warp 会根据 locality of vertices 和 pixels 进行分组。在 ray tracing 和 compute shaders 中,用户可以更明确地控制工作分组方式。
影响线程差异性能的其他因素包括任何分支下着色器指令的总体百分比,以及特定机器指令及其操作类型。了解实际影响的唯一方法是,在测量整体性能时能够跟踪 warp 线程效率,并关联其中一个线程的变化。
这是新的 Active Threads per Warp 直方图的用武之地。Nsight Graphics 的 GPU Trace 工具中的 Shader Profiler 视图中现已提供此紧凑图形,包括着色器工作流、自上而下、自下而上、热点和源/反汇编。它说明了线程差异对任何给定着色器、函数或单个源代码行的总体影响。
如图 2 所示,直方图右侧的值 (接近 32) 表示指令执行效率更高。显示的值根据执行每个代码块时的性能计数器采样得出近似值。弹出工具提示会更详细地显示直方图。当启动 GPU Trace 时,必须将“Timeline Metrics”设置设置为“Top-Level Triage”或“Ray Tracing Triage”(如果可用),并启用“Real-Time Shader Profiler”。
如果函数存在性能瓶颈,且每个线程束的活动线程数不足,则应考虑改进线程束一致性或减少分支的策略。有关光线追踪工作负载,请参阅 Shader Execution Reordering(SER),它专为解决光线追踪着色器中的线程和数据分散问题而设计。其他算法更改可能会提高线程执行的一致性;例如,使用不同的光线采样模式。对于任何类型的着色器,还可以通过在 D3D12 或 Vulkan 中将分支转换为线程束感知着色器代码来提高效率。
直方图的分布揭示了代码块的行为是否一致,并且查看每个线程束的活动线程数达到或接近 100% 也可能验证线程发散不是最初被怀疑的限制因素。
图 3 说明了路径追踪等高级照明技术如何在二次光线从场景中物体反弹时导致着色器发散。SER 提高了执行一致性,因为使用相同命中着色器的光线可以在线程束级别更好地利用 SIMT。当 SER 正常工作时,您应该会看到“Active Threads per Warp”得到改进。
在更高层次上,改善整体着色时间需要理解和减少 warp 失速。当 warp 达到长延迟运算时,尤其是内存访问和纹理获取等操作,会停止。当一个 warp 停止时,可以为下一个指令安排另一个 warp。但是,这只能购买如此多的并行性。如果过多的 warp 处于静止状态,则 SM 未得到充分利用,甚至会处于空闲状态。延迟的长度取决于许多因素,例如内存查找所达到的缓存级别 (如果有)。
GPU Trace 一直提供用于分析这些延迟的工具,但箭袋中的新箭头是 Warp Latency 直方图,该直方图以前曾作为单个平均 Warp Latency 周期计数呈现。通过观察线程束延迟的分布情况,我们可以更深入地了解着色器计时的可变性,并提供提示,说明是否已提前退出,以及多次着色器调用的参数是否会导致不同的行为。请注意,直方图目前仅包含调用同一着色器的时间轴中不相交区域的单独延迟数据点。
有关优化 GPU 工作负载的更多详细信息,请查看以下资源:
- 用于优化任何 GPU 工作负载的峰值性能百分比分析方法 描述了 NVIDIA 内部使用的一种性能分流方法,该方法使用 NVIDIA 特定的硬件指标来确定任何给定 GPU 工作负载的主要性能限制因素。
- 强大的着色器见解:使用着色器调试信息与 NVIDIA Nsight Graphics 结合使用 ,说明在编译着色器时需要执行的步骤,以查看 GPU Trace 中的火焰图形和源关联。
- CUDA 编程指南 和 CUDA Refresher:CUDA 编程模型 介绍如何将计算和 SIMT 架构应用于图形 API 中的计算着色器。
- NVIDIA Nsight Compute 简介 – 一个 CUDA 内核分析器 以适用于图形工作负载的方式讨论 warp 调度。
D3D12 工作图
CPU 和 GPU 之间的交互通信是图形管线中的另一个常见瓶颈。即使批量数据驻留在 GPU 上,从 CPU 发出渲染指令的行为也会在 GPU 处于空闲状态时产生泡沫。工作图是 D3D12 中的一项新功能,旨在减少调度 GPU 工作对 CPU 的依赖性。GPU 驱动的调度已经出现一段时间了,但工作图形引入了比 ExecuteIndirect
等现有方法更先进的功能。有关工作图形的概述,请参阅 Direct3D 12 中使用工作图形推进 GPU 驱动渲染。
Nsight Graphics 2024.2 中引入了对 Shader Profiler 中分析 Work Graph 节点整体的初步支持。在 2024.3 中,Shader Profiler 现在支持 Work Graph 的源关联,从而在 Shader Source 视图和 Hot Spots 列表中启用完整的逐行分析功能。由于 Work Graph 是 D3D12 中的一项新功能,因此此功能应能帮助开发者探索和更好地理解 Work Graph 的性能特征。请注意,源关联需要最新的 R565 系列驱动。
同样,Nsight Aftermath SDK 2024.3 增加了对用于跟踪工作图形的着色器的支持,并提供上下文信息,以帮助缩小源自工作图形工作负载的相关 GPU 错误。
Vulkan 更新
最近发布的 Vulkan 1.4 标准将十几个先前可选扩展程序提升到所需的扩展程序集,并引入了更高的最低硬件限制。有关更多信息,请参阅 Khronos 简化使用 Vulkan 1.4 的 GPU 加速应用程序的开发和部署 。Nsight Graphics 2024.3 在 Frame Debugger 中提供 Vulkan 1.4 支持。有关支持 1.4 的测试版驱动,请访问 Vulkan 驱动支持 。
即使您未直接使用 Vulkan 1.4,Nsight Graphics 现在也支持所有新推广的扩展。此外,还添加了对许多其他扩展程序的支持,包括 VK_NV_inherited_viewport_scissor 和 VK_NV_device_generated_commands_compute。有关完整列表,请参阅 NVIDIA Nsight Graphics 用户指南 。
此版本还增加了对在 Windows 和 Linux 桌面平台上使用 Vulkan SC 的应用程序的帧调试和 GPU 追踪的支持。有关 Vulkan SC 和驱动支持的更多信息,请访问 Vulkan 驱动支持 。
结束语
在开始针对并行性进行优化之前,您可能需要对 GPU 计算模型有一个基本的了解。然而,由于数据模式、编译器和硬件优化以及许多其他二阶影响,该理论如何转化为实践可能很难预测。根据工具中的假设检验和测量记录制定策略。了解指标的含义,然后在您进行调整时追踪其变化情况。虽然同时实现 GPU 上每个硬件单元的 100%利用率并不切实际,但增量改进可以帮助您达到应用的性能需求。
Nsight Graphics 2024.3 现已推出 。使用位于 Nsight Graphics 窗口右上角的“Feedback”(反馈)按钮,向我们介绍您使用这些新功能的体验。
详细了解 Nsight 开发者工具 并探索 Nsight Tools 教程 。在 Nsight Graphics Developer 论坛 上提问、提供反馈,以及与图形开发者社区互动。
致谢
感谢 Avinash Baliga、Jeff Kiel、Axel Mamode、Aurelio Reis 和 Louis Bavoil 为本文做出的贡献。