Doom GPU Flame Graphs
标题: Doom 游戏的 GPU Flame Graphs 分析
AI Flame Graphs 现在已经开源,并且包含了 Intel Battlemage GPU 的支持。这意味着它可以生成全栈的 GPU flame graph,从而为游戏性能提供新的见解,特别是与 FlameScope(我之前开源的一个项目)结合使用时。这里有一个 GZDoom 的例子,我将从 CPU 和 GPU 利用率的 flame scope 开始,并附上详细的注释:
(这里是原始的 CPU 和 GPU 版本。) FlameScope 显示了 profile 样本的亚秒级偏移热图,其中每一列代表一秒(在本例中,由 50 个 20 毫秒的块组成),颜色深度代表样本的数量,揭示了方差和扰动,您可以选择这些方差和扰动来生成仅针对该时间范围的 flame graph。
将这些 CPU 和 GPU 的 flame scope 并排放置,可以让您通过肉眼进行模式匹配,从而解决原本需要花费大量时间进行性能关联的任务。右侧 GPU flame scope 中的空白(GPU 没有进行太多工作)与左侧 CPU 工作较重的时段相匹配。
CPU 分析
FlameScope 允许我们点击感兴趣的时段。通过选择其中一个 CPU shader 编译条带,我们可以获得仅针对该范围的 flame graph:
这非常棒,我们可以清楚地看到 CPU 为何忙碌了大约 180 毫秒(红色条纹的垂直长度):它正在编译 GPU shader 并进行一些 NIR 预处理(对 Mesa 内部使用的 NIR intermediate representation 进行优化)。如果您不熟悉 flame graph,可以先查找最宽的塔,并首先优化它们。这是 interactive SVG。
CPU flame graph 和 CPU flame scope 并不是什么新鲜事物(分别来自 2011 和 2018,都是开源的)。 新的是全栈 GPU flame graph 和 GPU flame scope。
GPU 分析
还可以在 GPU FlameScope 中选择感兴趣的细节来生成 GPU flame graph。此示例选择“room 3”范围,该范围是 Doom 地图中的一个房间,包含数百个敌人。绿色框是 GPU 上运行的实际指令,aqua 显示了这些函数的源代码,红色 (C) 和黄色 (C++) 显示了启动 GPU 程序的 CPU 代码路径。灰色“-”框仅有助于突出显示 CPU 和 GPU 代码之间的边界。(这与我在 AI flame graph 文章中描述的类似,其中包括用于内核代码的额外帧。)x 轴与成本成正比,因此您可以查找最宽的事物并找到减少它们的方法。
我已包含此 flame graph 的 interactive SVG 版本,因此您可以将鼠标悬停在元素上并单击以进行缩放。(PNG 版本。)
GPU flame graph 分为来自渲染墙壁(41.4%)、后处理效果(35.7%)、模板(17.2%)和精灵(4.95%)的停顿。CPU 堆栈通过导致停顿的各个 shader 以及这些停顿的原因进一步区分。
GZDoom
我们选择了 GZDoom 来尝试,因为它是一个在 Linux 上运行的著名游戏的开源版本(我们的 profiler 尚不支持 Windows)。Intel Battlemage 可以轻松运行 GZDoom,但是,由于 GPU profile 是基于停顿的,因此我们没有获得很多样本。我们可以切换到更现代和对 GPU 要求更高的游戏,但没有好的开源想法,因此我认为我们将使 GZDoom 提出更高的要求。我们为 GZDoom 构建了 GPU 需求大的地图(我不敢相信我找到了使用 Slade 的与工作相关的原因),并且还设置了一些 Battlemage 可调参数来限制资源,从而扩大了剩余资源的使用率。
我们的 GZDoom 测试地图有三个房间:房间 1 是空的,房间 2 充满了火炬,房间 3 是开放的,有一个很大的天空盒,并且充满了敌人,包括士官的产卵点。这为我们提供了几个不同的工作负载,可以通过在房间之间行走来检查。
使用 iaprof:Intel 的开源加速器 profiler
AI Flame Graph 项目是一项开创性的工作,需要对图形编译器、库和内核驱动程序进行各种更改,不仅是代码,还包括它们的构建方式。由于 Intel 拥有自己的公共云(Intel® Tiber™ AI Cloud),我们可以提前修复软件堆栈,以便客户“正常工作”。检查 available releases。它目前支持 Intel Max Series GPU。
如果您不在 Intel 云上,或者您希望在 Intel Battlemage 上尝试此操作,那么让系统准备好进行 profile 可能需要大量工作。要求包括:
- 具有超级用户(root)访问权限的 Linux 系统,以便可以使用 eBPF 和 Intel eustalls。
- 具有最新 Intel GPU 驱动程序的较新 Linux 内核。对于 Intel Battlemage,这意味着 Linux 6.15+ 与 Xe 驱动程序;对于 Intel Max Series GPU,它是 Linux 5.15 与 i915 驱动程序。
- 使用 Intel 驱动程序特定的 eustall 和 eudebug 接口构建的 Linux 内核(有关详细信息,请参见 github docs)。其中一些修改已在上游中最新版本的 Linux 中进行了修改,而另一些修改目前正在进行中。(默认情况下,这些接口在 Intel® Tiber™ AI Cloud 上可用。)
- 所有正在进行 profile 的系统库或程序都需要包含 frame pointers,以便可以看到完整的堆栈,包括 Intel 的 oneAPI 和图形库。对于此示例,需要使用 frame pointers 编译 GZDoom 本身以及 GZDoom 使用的所有库(glibc 等)。在最新版本的 Fedora 和 Ubuntu 中,这变得越来越容易(例如,Ubuntu 24.04 LTS),这些版本默认情况下都附带带有 frame pointers 的系统库。但是我希望会有一些应用程序和依赖项还没有 frame pointers,并且需要重新编译。如果您的 flame graph 有一些区域非常短,只有一两个帧深,这就是原因。
如果您不熟悉自定义内核构建和库修改,那么让所有这些工作正常进行可能会感觉像 Nightmare! 难度。随着时间的推移,情况将会改善并逐渐变得更容易:检查 github docs。Intel 还可以开发此工具的更简单版本,作为更广泛的产品的一部分,并使其不仅可以在 Linux 和 Battlemage 上运行(请注意此空间,或者,如果您有 Intel 代表,请要求他们将其作为优先事项)。
一旦一切正常运行,您就可以运行 iaprof
命令来 profile GPU。例如:
git clone --recursive https://github.com/intel/iaprof
cd iaprof
make deps
make
sudo **iaprof record** > profile.txt
cat profile.txt | iaprof flame > flame.svg
iaprof
是以 Linux perf
命令为模型的。(也许有一天它会直接包含在 perf
中。)感谢 Gabriel Muñoz 完成了使这项工作开源的工作。
FAQ 和未来工作
从去年推出 AI flame graph 以来,我可以猜测 FAQ #1 将是:“NVIDIA 呢?”。他们确实在 Nsight Graphics 中有用于 GPU 工作负载的 flame graph,尽管他们的 flame graph 目前很浅,因为它仅是 GPU 代码,并且使用起来很麻烦,因为我相信它需要一个中间人;从好的方面来说,他们可以点击以查看源代码。我们一直在开发的新的 GPU profiling 方法允许像您期望从 CPU profiler 那样,轻松地进行随时随地的全方位 profiling。
未来的工作将包括 github 版本、更多硬件支持和开销减少。我们是第一个以这种方式使用 eustalls 的人,我们需要添加更多优化以达到 <5% 开销的目标,尤其是在使用 i915 驱动程序时。
结论
我们已经开源了 AI flame graph 并在新硬件 Intel Battlemage 和非 AI 工作负载 GZDoom(游戏)上对其进行了测试。很高兴看到 CPU 和 GPU 资源的视图下降到毫秒级分辨率,我们可以在 flame scope 热图中看到视觉模式,可以选择这些视觉模式来生成 flame graph 以显示代码。我们将这些新工具应用于 GZDoom,并通过选择相应的 CPU 突发并读取 flame graph 以及 GPU 代码在任意时间窗口内的使用情况来解释 GPU 暂停。
虽然我们已经 开源 了此工具,但要使其全部运行需要 Intel 硬件以及 Linux 内核和库的修改,这可能需要大量工作。(实际上,以 Nightmare! 难度玩 Doom 可能会更容易。)随着时间的推移,情况会好转。我们期待看到是否有人可以度过这段时间并解决他们可以解决的新性能问题。
作者:Brendan Gregg, Ben Olson, Brandon Kammerdiener, Gabriel Muñoz.