而RDNA3中,因为新加了一组FP32 SIMD32,单发射的发射端如果使用正常的指令,在Wave32模式下只能喂饱其中一组,所以AMD为RDNA3的Wave32模式添加了VOPD指令格式。该指令格式可以将两条指令打包成为一条VOPD格式指令,这样就能通过仅有的一个发射端,同时驱动两个FP32 SIMD32。VOPD在性质上来说就类似于VLIW指令,但它的编码格式没有增加最大指令长度,也没有增加指令延迟,例如VOPD的双FMA指令延迟和正常FMA指令一致为5周期。VOPD指令虽然能解决驱动两个FP32 SIMD32的问题,但它也有极多的限制,它需要编译器或者汇编程序员来处理数据依赖,两条指令的常量、立即数和标量寄存器只能使用同一个,目标寄存器需要是一个奇数号一个偶数号,源寄存器需要使用不同的Bank,甚至支持的指令也是有限的,第一个SIMD支持16条指令,第二个SIMD只支持13条。如此多的限制下,VOPD驱动的第二组FP32 SIMD32可能仅仅是一个锦上添花的东西。

实际测试中,利用我自己写的OpenCL测试程序测得Wave32模式下,VOPD的两条指令中,最多在各自使用一个源向量寄存器时,在我手上这块7900XT 超白金上可以达到61.5TFlops的浮点吞吐率,有效频率大约2.86Ghz。使用其他任意格式均会导致吞吐率下降到一半水平。
在Wave64模式下,和AMD PPT上写的不同,RDNA3采用单发射端交替发射的模式喂饱两个SIMD32。这样,对于需要吞吐率的应用,在Wave64下可以较为轻松的利用起增加的SIMD,限制上少很多,延迟上也与上代保持一致,为7个时钟周期。不过Wave64模式下,寄存器压力较大,所以前一代中AMD都只在相对可能更简单的Pixel Shader中使用Wave64模式,RDNA3中AMD将寄存器堆容量增加了50%,L0也增加了一倍,应该就是为了应对Wave64模式下,寄存器压力较大的问题。

通过PIX Profile D3D程序可以得知,Direct3D下所有Shader都已经采用Wave64模式。所以使用我自己写的D3D12程序可以测得,无论何种格式的FMA指令,在Wave64模式下都至多只能获得5/6的峰值吞吐率,而常用的格式下甚至更低。稍微评价一下RDNA3这次增加一组SIMD的做法,大概就是硬塞了一组进去的感觉,寄存器方面完全没有做任何准备,比较令人失望。
接下来说下CU新增的WMMA,也就是矩阵加速器,从LLVM的代码可以看到AMD的WMMA指令,除了名字和Nvidia Tensor Core的WMMA指令一样以外,内容也差不多。回到硬件本身,AMD的Dot2 WMMA指令支持FP16、BF16和INT8,Dot4则支持INT4,宽度都为64。用FP16来算的话,DOT2等效于两个乘法操作加上两个加法,也就是每周期256个浮点操作,从单CU的性能上来看,大约和Nvidia图灵架构的差不多,对于一般AI方面的应用而言,其实是非常足够了,而且考虑到AMD之后会引入赛灵思的AIE,这种规模完全合情合理。
光追加速器方面,AMD主要增加了对Ray Flags的硬件支持。Ray Flags是DXR的Shader中通过TraceRay内联函数传递给求交之后的处理函数的光线特性覆盖标志。通过这个标志可以实现一系列高级操作来减轻复杂光追的开销。LDS也新增了一条指令,取代了以前需要由多条ALU和LDS指令配合完成的复杂操作,让每个遍历操作中减少了50条指令,降低了4倍的L0总线开销。同时增加的1.5倍寄存器,也让光追Shader的寄存器压力降低很多,实现了更高的计算单元的利用率。这块我不熟,就不测了。
调度上,RDNA3为SALU增加了s_delay_alu指令用于提示调度器接下来的指令相关性以及延迟等信息,改善了线程切换的准确性提升了CU的性能和功耗表现。这里多讲一点,GCN的调度模式是每周期都切换线程,所以GCN没办法使用寄存器缓存,每次计算都需要重新到主寄存器堆取数据。主寄存器堆很大,工作功耗会很高。而Navi开始加入了s_clause指令用于提示调度器接下来的指令可以不切换的连续执行,这样前后指令需要的数据可以被放在一块很小的操作数缓存中,写出的结果也可以通过结果缓存让后面的指令使用,大大降低了寄存器访问功耗,这也是Navi与GCN能耗比差距巨大的根本原因。同时通过软件辅助的调度器本身功耗也可以更小一些。
