AMD Radeon™ GPU Detective
AMD Radeon™ GPU Detective (RGD) 是一款用于 GPU 崩溃事后分析的工具。RGD 可以捕获 DirectX® 12 应用的 AMD GPU 崩溃转储。
AMD Radeon™ GPU Detective (RGD) v1.4 版本(AMD 用于 GPU 崩溃事后分析的工具)带来了一项强大的新功能:硬件崩溃分析。启用后,RGD 会收集 GPU 崩溃时的低级硬件状态信息,并丰富崩溃分析 (.rgd) 输出文件中的信息,提供有意义的见解。
在 RGD v1.3 及之前版本中,执行标记树中的每个执行标记只能有 3 种状态之一
[X] finished[>] in progress[ ] not started通过硬件崩溃分析,添加了第四种执行标记状态。RGD 会将飞行中的波前 (wavefronts) 与执行标记关联起来,并用 [#] 符号标记在崩溃期间有正在运行波前的节点。
[#] shader in flight考虑以下 Direct3D® 12 应用程序的示例执行标记树
Legend======[X] finished[>] in progress[ ] not started
Command Buffer ID: 0xb14 (Queue type: Direct)=============================================[>] "Frame 694 CL0" ├─[>] "DownSamplePS" │ ├─[X] ----------Barrier---------- │ ├─[X] Draw(VertexCount=3, InstanceCount=1) │ ├─[X] Draw(VertexCount=3, InstanceCount=1) │ ├─[X] Draw(VertexCount=3, InstanceCount=1) │ ├─[>] Draw(VertexCount=3, InstanceCount=1) │ ├─[>] Draw(VertexCount=3, InstanceCount=1) │ └─[>] ----------Barrier---------- ├─[>] "Bloom" │ ├─[>] "BlurPS" │ │ ├─[>] ----------Barrier---------- │ │ ├─[>] Draw(VertexCount=3, InstanceCount=1) │ │ ├─[>] ----------Barrier---------- │ │ ├─[>] Draw(VertexCount=3, InstanceCount=1) │ │ └─[>] ----------Barrier---------- │ ├─[>] ----------Barrier---------- │ ├─[>] Draw(VertexCount=3, InstanceCount=1) │ ├─[>] ----------Barrier---------- │ ├─[>] "BlurPS" │ │ ├─[>] ----------Barrier---------- │ │ ├─[>] Draw(VertexCount=3, InstanceCount=1) │ │ ├─[>] ----------Barrier---------- │ │ ├─[>] Draw(VertexCount=3, InstanceCount=1) │ │ └─[ ] ----------Barrier---------- │ ├─[ ] ----------Barrier----------上面的执行标记树已经为我们识别出可疑的绘制调用指明了方向。它可以是“进行中”([>]) 的标记中的任何一个。有很多正在进行的绘制调用,但考虑到崩溃期间可能有大量的绘制调用在飞行中,仅缩小到几个潜在可疑的绘制调用本身就是一项巨大的时间节省。
然而,正如您在下面看到的,硬件崩溃分析功能将我们带得更远,它识别出在崩溃期间由正在飞行的着色器执行的“进行中”标记。当启用硬件崩溃分析捕获 AMD GPU 崩溃转储 (.rgd 文件) 时,相同的执行标记树将显示如下:
Legend======[X] finished[>] in progress[#] shader in flight[ ] not started
Command Buffer ID: 0xb14 (Queue type: Direct)=============================================[>] "Frame 694 CL0" ├─[>] "DownSamplePS" │ ├─[X] ----------Barrier---------- │ ├─[X] Draw(VertexCount=3, InstanceCount=1) │ ├─[X] Draw(VertexCount=3, InstanceCount=1) │ ├─[X] Draw(VertexCount=3, InstanceCount=1) │ ├─[#] Draw(VertexCount=3, InstanceCount=1) <-- has a correlated running wave <SHADER INFO section IDs: {ShaderInfoID1}, API PSO hash = 0x3f0dcc77cb4a94c6, API stages: {Pixel}> │ ├─[#] Draw(VertexCount=3, InstanceCount=1) <-- has a correlated running wave <SHADER INFO section IDs: {ShaderInfoID1}, API PSO hash = 0x3f0dcc77cb4a94c6, API stages: {Pixel}> │ └─[>] ----------Barrier---------- ├─[>] "Bloom" │ ├─[>] "BlurPS" │ │ ├─[>] ----------Barrier---------- │ │ ├─[>] Draw(VertexCount=3, InstanceCount=1) │ │ ├─[>] ----------Barrier---------- │ │ ├─[>] Draw(VertexCount=3, InstanceCount=1) │ │ └─[>] ----------Barrier---------- │ ├─[>] ----------Barrier---------- │ ├─[>] Draw(VertexCount=3, InstanceCount=1) │ ├─[>] ----------Barrier---------- │ ├─[>] "BlurPS" │ │ ├─[>] ----------Barrier---------- │ │ ├─[>] Draw(VertexCount=3, InstanceCount=1) │ │ ├─[>] ----------Barrier---------- │ │ ├─[>] Draw(VertexCount=3, InstanceCount=1) │ │ └─[ ] ----------Barrier---------- │ ├─[ ] ----------Barrier----------注意 RGD 如何将潜在的罪魁祸首列表缩小到“DownSamplePS”子树中的仅两个特定的绘制调用。此外,RGD 现在识别出崩溃着色器的 API 阶段(本例中为像素着色器)、着色器正在执行的 API 管道(通过哈希字符串)以及着色器本身(稍后将在下一节中详细介绍)。
正如您所见,飞行中执行标记的注释包含对 ShaderInfoID1 的引用。这是一个句柄,您可以使用它跳转到我们添加到 RGD 输出文件中的一个新部分:SHADER INFO 部分。名称 ShaderInfoID1 是任意的。它的目的是作为 RGD 输出文本文件范围内的唯一字符串标识符,允许您在搜索该字符串时快速跳转到文本文件的相关部分。
让我们看一下同一个崩溃的 Direct3D® 12 应用程序的新 SHADER INFO 部分,它通常出现在 RGD 输出文本文件的末尾
===========SHADER INFO===========
Shader info ID : ShaderInfoID1API PSO hash : 0x3f0dcc77cb4a94c6API shader hash: 0x9e7e544426c404defd8c0ea8a6f65c3bAPI stage : Pixel
Disassembly=========== . . . v_interp_p2_f32 v2, v3, v1, v0 wait_exp:7 // 000000000360: CD010702 04020303 s_mov_b32 s4, s5 // 000000000368: BE840005 s_mov_b32 s5, s9 // 00000000036C: BE850009 s_load_b256 s[4:11], s[4:5], null // 000000000370: F40C0102 F8000000 s_waitcnt lgkmcnt(0) // 000000000378: BF89FC07 v_mul_f32_e64 v3, 2.0, s0 // 00000000037C: D5080003 000000F4 v_mul_f32_e64 v0, 2.0, s1 // 000000000384: D5080000 000002F4 s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)// 00000000038C: BF870112 v_sub_f32_e32 v1, v4, v3 // 000000000390: 08020704 v_sub_f32_e32 v3, v2, v0 // 000000000394: 08060102 v_fma_f32 v0, s0, 2.0, v4 // 000000000398: D6130000 0411E800 v_fma_f32 v6, s1, 2.0, v2 // 0000000003A0: D6130006 0409E801 s_mov_b32 s12, 0x8007092 // 0000000003A8: BE8C00FF 08007092 s_mov_b32 s13, 0xfff000 // 0000000003B0: BE8D00FF 00FFF000 s_mov_b32 s14, 0x64500000 // 0000000003B8: BE8E00FF 64500000 s_mov_b32 s15, 0x80000000 // 0000000003C0: BE8F00FF 80000000 s_clause 0x8 // 0000000003C8: BF850008> image_sample v[8:11], [v0, v6], s[4:11], s[12:15] dmask:0xf dim:SQ_RSRC_IMG_2D// 0000000003CC: F06C0F05 0C010800 00000006 <-- ***PAGE FAULT SUSPECT (128 waves)*** image_sample v[12:15], [v4, v6], s[4:11], s[12:15] dmask:0xf dim:SQ_RSRC_IMG_2D// 0000000003D8: F06C0F05 0C010C04 00000006 image_sample v[18:21], [v1, v6], s[4:11], s[12:15] dmask:0xf dim:SQ_RSRC_IMG_2D// 0000000003E4: F06C0F05 0C011201 00000006 image_sample v[22:25], [v0, v2], s[4:11], s[12:15] dmask:0xf dim:SQ_RSRC_IMG_2D// 0000000003F0: F06C0F05 0C011600 00000002 image_sample v[26:29], [v4, v2], s[4:11], s[12:15] dmask:0xf dim:SQ_RSRC_IMG_2D// 0000000003FC: F06C0F05 0C011A04 00000002 image_sample v[30:33], v[1:2], s[4:11], s[12:15] dmask:0xf dim:SQ_RSRC_IMG_2D// 000000000408: F06C0F04 0C011E01 image_sample v[34:37], [v0, v3], s[4:11], s[12:15] dmask:0xf dim:SQ_RSRC_IMG_2D// 000000000410: F06C0F05 0C012200 00000003 image_sample v[4:7], [v4, v3], s[4:11], s[12:15] dmask:0xf dim:SQ_RSRC_IMG_2D// 00000000041C: F06C0F05 0C010404 00000003 image_sample v[0:3], [v1, v3], s[4:11], s[12:15] dmask:0xf dim:SQ_RSRC_IMG_2D// 000000000428: F06C0F05 0C010001 00000003 s_cmp_eq_i32 s2, 0 // 000000000434: BF008002 s_cbranch_scc1 _L5 // 000000000438: BFA20041 s_waitcnt vmcnt(7) // 00000000043C: BF891FF7 v_add_f32_e32 v8, v8, v12 // 000000000440: 06101908 v_add_f32_e32 v9, v9, v13 // 000000000444: 06121B09 v_add_f32_e32 v10, v10, v14 // 000000000448: 06141D0A v_add_f32_e32 v11, v11, v15 // 00000000044C: 06161F0B s_waitcnt vmcnt(6) // 000000000450: BF891BF7 s_delay_alu instid0(VALU_DEP_4) | instskip(NEXT) | instid1(VALU_DEP_4)// 000000000454: BF870214 v_add_f32_e32 v8, v18, v8 // 000000000458: 06101112 . . .您可以看到 SHADER INFO 部分仅包含一个着色器 (ShaderInfoID1),这与执行标记树匹配。除了着色器元数据之外,您还可以看到崩溃着色器反汇编的相关子集。如果崩溃是由着色器触发的页面错误引起的,RGD 将在相关反汇编行中用 [>] 前缀标记有问题的指令,并带有标记页面错误罪魁祸首嫌疑以及崩溃时执行该指令的波前数量的注释。默认情况下,该工具仅在输出文件中包含着色器反汇编的相关子集,以尽量减少噪音。在页面错误嫌疑指令周围,您会找到少量指令,以提供该指令执行的上下文。垂直的 . . . 线表示已过滤的指令。如果您确实需要查看完整的着色器反汇编,可以通过手动运行 rgd 命令行工具并将 AMD GPU 崩溃转储 (.rgd) 文件作为输入,并使用 --all-disassembly 命令行选项来实现(有关更多信息,请运行 rgd -h 查看 rgd 命令行工具帮助手册)。
为了使该工具能够检索您 GPU 崩溃案例的其他低级信息,需要完成一些工作。首先,您必须确保在 Radeon Developer Panel (RDP) 的崩溃分析选项卡中选中了硬件崩溃分析复选框(默认情况下已选中)。此外,由于此版本工具侧重于有问题的着色器,因此 GPU 崩溃显然需要由着色器执行的硬件块触发。如果 GPU 崩溃发生在其他地方,则执行树标记将不关联任何着色器,您将无法获得新硬件崩溃分析模式的优势。但是,如果您的崩溃案例得到 RGD 的支持,您可以依靠“标准”(RGD v1.3)信息,无论硬件崩溃分析功能是否适用于您的崩溃案例。
另外,请注意 RGD 目前在此新模式下仅提供低级信息。诸如崩溃着色器的高级或中间源代码之类的信息不包含在内。我们希望在未来的版本公告中与您分享有关这些令人兴奋的功能的更新——敬请关注!