Radeon™ 内存可视化工具 (RMV) 是一款工具,可让您深入了解您的应用程序如何使用图形资源的内存。

Radeon™ 内存可视化工具 (RMV) 是 AMD 为游戏引擎开发者提供的一款工具。它允许工程师检查、诊断和理解其项目中的 GPU 内存管理。
随着 DirectX®12 和 Vulkan® 的引入,内存成为了需要游戏引擎显式管理的资源。多年来,图形开发者一直缺乏辅助工具。RMV 旨在满足工程师在任何给定时间点了解游戏如何使用内存以解决问题的需求。
要使用 RMV,您需要使用具有相应支持的驱动程序。请参阅RMV 页面以获取最新的支持驱动程序和 RMV 软件包。
随着 RMV 的推出,我们还引入了新的 Radeon™ Developer Panel (RDP),它对您之前可能使用过的 RDP 进行 Radeon™ GPU Profiler 跟踪的工作流程进行了微小改动。它非常相似,但有一个重要的变化,我们将在下面进行概述。如果您已经熟悉设置 RDP 2.0,您可以跳到“运行您的应用程序”。

运行 Developer Panel,并在出现提示时允许它通过 Windows® 防火墙。数据通过网络回送接口传输,这就是为什么您可能会看到防火墙提示。使用新的 Panel,您需要通过 System 选项卡添加要跟踪的可执行文件。查找您的应用程序名称,然后单击“Add”(添加),使其列在下面的“My Applications”(我的应用程序)列表中。它应该将“API”设置为“Auto”(自动),将“Workflow”(工作流程)设置为“Memory Trace”(内存跟踪)。

我们运行的图形应用程序是 Vulkan® Radeon™ Cauldron 示例。我们选择几个不同的场景,然后退出。您可以通过渲染窗口上方的 Radeon™ Developer Panel HUD 来知道内存跟踪是否处于活动状态。它应该显示“RMV Tracing: Active”(RMV 跟踪:活动)。如果您没有看到此消息,请确保 Radeon™ Developer Panel 的 Application 选项卡中列出了正确的应用程序路径,并且您使用的是支持 RMV 的 Radeon™ 图形驱动程序包。

退出应用程序时,将自动转储内存跟踪,并将其列在“Recently collected traces”(最近收集的跟踪)区域。双击应会打开跟踪 – 如果不打开,请确保 Radeon™ Memory Visualizer 的路径正确,该路径在同一面板下的“Trace settings”(跟踪设置)中列出。

使用 RMV 打开跟踪后,它将带您进入“TIMELINE”(时间线)概览。它显示资源大小随时间的变化,块的颜色表示资源类型。使用下拉组合框,您可以选择显示资源计数而不是大小 – 如果您更感兴趣的话。目前,我们将其保留为“Resource usage size”(资源使用大小)。鉴于这是一个时间线,很容易就能了解正在发生什么。

为了进一步检查内存,我们需要创建一个快照。快照是记录到目前为止内存跟踪所记录内容的一个时间点。它允许对我们的资源、内存使用情况进行深入分析,尤其重要的是 – 这些资源是如何映射到物理内存的。
右键单击时间线,选择“Add snapshot at”(在此处添加快照)。这将创建快照并将其添加到时间线下的快照列表中。双击快照即可打开它。

您首先会看到“Heap Overview”(堆概览)。它提供了此时间点内存构成基本信息。它显示了 Local(本地)、Invisible(不可见)和 Host(主机)内存堆,以及有关这些堆的一些规格,例如 CPU 和 GPU 缓存是如何在它们之间处理的。还列出了最小和最大分配数据,以及堆内分配的资源类型的饼图。从这里您可以立即看到大部分资源类型的位置。

此窗口还可以显示有关堆过度订阅问题的警告。这些应认真对待,并采取措施减轻高内存利用率,以防止因过度订阅而导致的卡顿和其他问题。

下一个区域是“Resource Overview”(资源概览)子窗口。它尝试显示可按各种状态着色或过滤的资源图。这是一个可以立即查看占用内存最多的资源的视图,但也可以用于查找潜在的驻留问题。

例如,我们可能想看看是否有任何正在使用的资源没有完全映射到 VRAM。为此,命令缓冲区是一个简单的例子。我们从“Resource usage”(资源使用)下拉菜单中仅选择“Command buffer”(命令缓冲区),并“Color by not all in preferred heap”(按非全部在首选堆着色)。
要理解内存的一个重要方面是,资源的部分内容可以位于我们想要的位置,而其他部分则被分页出,或者根本没有映射。当我们设置这些资源选项时,我们会看到列出了三个命令缓冲区,但其中两个是红色的,表示它们没有完全位于首选堆位置。双击第一个会带我们到“Resource details”(资源详细信息)窗格,并立即显示一个警告,告知我们并非所有资源都位于创建时请求的首选堆中。只有 53% 的此资源映射到了首选 HOST 堆,其余部分未映射。

在这种情况下,我们的命令缓冲区仅在映射区域内使用。但如果这是一个很少使用的效果的渲染目标,当该效果被使用时,我们可能会遇到性能方面的问题,例如卡顿。
另一个有用的视觉辅助是显示为虚线/网点效果的资源。这意味着该资源是别名化的,并与其他资源共享内存。

最后一个视图用于探索分配和其中存在的资源。在这里,您可以查看有关您的分配策略工作方式的信息 – 其中包括分配内资源内存的碎片级别。

RMV 最有趣的功能之一是快照比较。它允许您在时间线视图中选择两个快照,并比较它们之间的内存状态。这对于在加载资产或更改游戏状态之前和之后调试问题非常有用。
一个基本的测试是运行您的游戏并长时间运行。在下面的示例中,我们运行了 Vulkan® 测试近 20 分钟 – 但如果您需要,可以运行更长时间。
RMV 捕获的一个重要方面是它是一个低开销的过程。您可以运行您的游戏数小时,跟踪文件输出也只会占用几百兆字节。内存问题可能需要很长时间才能出现,因此在设计中,能够捕获和分析非常长的运行时间是一个重要的考虑因素。

在此跟踪中,我们看到时间线看起来是静态的,除了前几秒钟快速的加载峰值。鉴于我们的跟踪是用 Cauldron GLTV 示例拍摄的,刚刚加载到一个场景中,没有其他更改,这正是我们所期望的。此测试中内存需求的任何增加都可能是潜在的错误。为了确认这一点,我们可以拍摄两个快照 – 一个在加载后不久,另一个在测试快结束时 – 并进行比较。

选择两个快照,右键单击可以进入“COMPARE”(比较)窗口。此视图最初显示 delta 比较,包括资源类型和内存的基本更改。在我们的示例中,虚拟内存或资源计数没有变化。这证实了我们的游戏在 20 分钟的捕获期间没有增加其内存占用。
我们可以进行的另一个测试是加载到场景 A,退回到场景 B,然后第二次重新加载场景 A。在我们的示例游戏中执行此操作并打开 RMV 跟踪文件后,我们可以从时间线视图中看到场景加载和卸载的典型迹象。在加载峰值之后,当我们在应用程序中渲染静态场景几秒钟时,资源大小保持稳定。我们可以使用比较窗口来确保第二次加载场景 A 时创建的资源数量与第一次加载时相同 – 并且没有从之前的场景遗留下来任何悬挂资源,这可能导致内存泄漏和错误。

我们在相关点创建快照并再次进行比较。在此示例中,我们不会深入研究实际的内存大小 delta,但资源类型 delta 很重要。在我们的例子中,我们可以看到有两个额外的渲染目标 – 为什么?让我们找出原因!

RMV 中的“COMPARE”(比较)模式中还有一个视图 – “Memory leak finder”(内存泄漏查找器)。它允许您轻松识别快照之间的常见资源,以及仅出现在其中一个快照中的资源。我们还可以将资源使用范围缩小到仅列出“Render targets”(渲染目标),因为我们知道它们的 delta 为 +2。

执行此操作后,我们会得到一个资源列表。此时,我们应该提到 RMV 支持 Vulkan® VK_EXT_debug_util 扩展。如果您的应用程序使用此扩展来命名 Image,则名称将出现在资源列表中,而不是数字 ID – 这极大地帮助了工程师跟踪这些问题。
在“compare ID”下有两个复选标记的表示它们存在于两个捕获中,因此我们不关心它们。但是,当我们还包括“Resources unique to Snapshot 1”(快照 1 独有的资源)时,我们可以看到“BlurHorizontal”的两个额外条目,它们仅存在于第二个快照中。这些就是我们额外的渲染目标!

查看我们示例中的代码,我们会发现 BlurHorizontal 渲染目标是如何创建的。它是我们模糊效果的临时渲染目标。从我们的快照比较中得知此资源未按要求销毁,从我们的析构函数代码中可以看到,该资源的 OnDestroy() 调用丢失了。我们将其添加回来,在第二次内存跟踪中,我们将看到泄漏的渲染目标资源不再被列出。
在真正的游戏引擎中,跟踪泄漏的这部分可能会更困难,但 RMV 提供了之前图形工程师无法获得的大量帮助。您可能还注意到创建了其他描述符资源 – 我们可以以相同的方式缩小范围。
RMV 可以看到游戏中存在的许多常见问题。
过度分配是大多数引擎开发者已经知道的一个术语;鉴于使用新的图形 API 手动管理游戏内存的需要,工程师们熟悉您不应尝试分配超过可能 VRAM 的想法。但是,总会有发生错误的状况导致过度分配,而 RMV 可以帮助您识别和调试这些情况。

在“Heap Overview”(堆概览)窗格中,即时发生的过度分配问题将导致相关堆(无论是 Local、Invisible 还是 Host)中出现警告。当您看到此警告时,首先要确保您正在以适合给定 GPU 和可用 VRAM 的质量级别运行您的游戏。有时会错过一些配置,尤其是在硬件规格存在极端情况时。
在怀疑存在 bug 的情况下,我们可以进入资源概览页面和分配页面。您可能会发现一些利用率严重不足的分配,这些分配会导致堆过度分配,或者创建了过多的临时 RT。RMV 允许您进行调查。时间线在此处也很有用,当内存正在快速增加(例如在关卡加载期间)时很明显,但可能在游戏过程中显示缓慢的增加,从而导致问题。
您可以在资源概览窗口中检查未绑定资源,并限制为特定堆。在这里,我们可以看到至少有 50MB 的未绑定本地资源,调查这些资源将有助于控制这种过度分配。

在某些情况下,我们看到游戏进行了数万次分配,主要是针对其中的单个资源。Vulkan® 比 DirectX®12 更容易出现此问题,因为分配数量有限,迫使开发者进行子分配。我们的Vulkan® 内存分配器库可以帮助管理这一点。
但是,DirectX®12 仍然可能出现问题。创建许多已提交资源,这些资源在创建时被标记为驻留,仅在销毁时才被逐出,这可能会占用内存预算。查看“Allocation Overview”(分配概览)并看到成千上万的单个分配-资源关系,可能表明使用子分配和放置资源可能是有益的。我们的D3D12 内存分配器可以在这些情况下提供帮助。
这可能发生在堆过度分配,而我们希望资源位于这些堆中,因此它们被放置在另一个堆中。在此示例中,我们看到一个 Local 资源被推送到 Host,并在我们的时间线中被映射进出。这可能导致卡顿,因此请确保调查此行为。

事实证明,RMV 允许开发者看到并最终修复各种与内存资源相关的问题。自从引入需要手动控制内存的显式图形 API 以来,这是一款被追捧多年的工具,我们很高兴看到许多游戏开发工作室在他们的开发过程中使用它。
我们希望 RMV 的使用能帮助游戏开发者创造出未来丰富多样的虚拟世界 – 为我们在所有可用的图形处理器上提供流畅无卡顿的玩家体验。
感谢您的阅读。有关我们为图形开发者提供的工具的更多信息,请访问我们的GPUOpen 工具页面。
脚注
DirectX® 是 Microsoft Corporation 在美国和其他司法管辖区的注册商标。Vulkan® 和 Vulkan® 徽标是 Khronos Group Inc. 的注册商标。Windows 是 Microsoft Corporation 在美国和其他司法管辖区的注册商标。
© 2020 Advanced Micro Devices, Inc. 保留所有权利。