AMD 长期以来一直在争夺 GPU 计算市场份额。自从 Nvidia 凭借其 Tesla 架构抢占先机以来,AMD 就一直在追赶。Terascale 3 从 VLIW5 迁移到 VLIW4,以提高计算工作负载中执行单元的利用率。GCN 取代了 Terascale,并强调 GPGPU 和图形应用程序的一致性能。然后,AMD 将其 GPU 架构开发分为单独的 CDNA 和 RDNA 线路,分别专门用于计算和图形。
CDNA 2 最终为 AMD 带来了显著的成功。MI250X 和 MI210 GPU 赢得了多个超级计算机合同,其中包括 ORNL 的 Frontier,该计算机在 2023 年 11 月的 TOP500 排行榜上排名第一。但是,虽然 CDNA2 提供了稳定且经济高效的 FP64 计算,但 H100 拥有更好的 AI 性能并提供了更大的统一 GPU。
CDNA 3 希望通过提供 AMD 提供的所有功能来缩小这些差距。MI300X 配备了先进的小芯片设置,充分展示了该公司在先进封装技术方面的经验。与 Infinity Fabric 组件一起,先进的封装使 MI300X 能够进行扩展,以与 Nvidia 最大的 GPU 竞争。在内存方面,RDNA 系列的 Infinity Cache 被引入 CDNA 领域,以缓解带宽问题。但这并不意味着 MI300X 的内存带宽很轻。它仍然拥有庞大的 HBM 设置,使其两全其美。最后,CDNA 3 的计算架构获得了显著的世代改进,以提高吞吐量和利用率。
01. GPU布局
AMD 一直有使用小芯片来廉价扩展 Ryzen 和 Epyc CPU 核心数量的传统。MI300X 在高级别上使用类似的策略,将计算拆分到加速器复合芯片 (XCD) 上。XCD 类似于 CDNA 2 或 RDNA 3 的图形计算芯片 (GCD) 或 Ryzen 的核心复合芯片 (CCD)。AMD 可能会更改命名,因为 CDNA 产品缺乏 RDNA 系列中的专用图形硬件。
每个 XCD 包含一组核心和一个共享缓存。具体来说,每个 XCD 物理上都有 40 个 CDNA 3 计算单元,其中 38 个在 MI300X 上的每个 XCD 上启用。XCD 上也有一个 4 MB 二级缓存,为芯片的所有 CU 提供服务。MI300X 有 8 个 XCD,总共有 304 个计算单元。
这比 MI250X 的 220 个 CU 有了很大的增加。更好的是,MI300X 可以将所有这些 CU 作为单个 GPU 公开。在 MI250X 上,程序员必须手动在两个 GPU 之间分配工作,因为每个 GPU 都有单独的内存池。
Nvidia 的 H100 由 132 个流式多处理器 (SM) 组成,并将它们作为一个大型统一 GPU 呈现给程序员。H100 采用传统方法,在大型单片芯片上实现所有计算。即使所有东西都在同一个芯片上,H100 也太大了,无法让所有 SM 平等地访问缓存。因此,H100 将 L2 拆分为两个实例。单个 SM 可以使用全部 50 MB 的 L2,但访问超过 25 MB 会导致性能损失。
尽管如此,Nvidia 的策略比 MI300X 的策略更有效地利用了缓存容量。MI300X XCD 不会使用其他 XCD 上的 L2 容量进行缓存,就像 Epyc/Ryzen 上的 CCD 不会分配到彼此的 L3 缓存中一样。
英特尔的 Ponte Vecchio (PVC) 计算 GPU 进行了非常有趣的比较。PVC 将其基本计算构建块放置在称为“Compute Tiles”的芯片中,这大致类似于 CDNA 3 的 XCD。同样,PVC 的 Base Tile 具有与 CDNA 3 的 IO 芯片类似的功能。两者都包含大型末级缓存和 HBM 内存控制器。与 MI300X 一样,Ponte Vecchio 卡可以作为具有统一内存池的单个 GPU 公开。
然而,也存在重要的差异。与 CDNA 3 XCD 上的 38 个计算单元相比,Ponte Vecchio 的计算块更小,只有 8 个 Xe 核心。英特尔没有使用计算块宽缓存,而是使用更大的 L1 缓存来减少跨芯片流量需求。使用两层 Ponte Vecchio 部件作为统一 GPU 也带来了挑战。两个堆栈之间的 EMIB 桥仅提供 230 GB/s 的带宽,如果访问跨所有内存控制器进行条带化,则不足以充分利用 HBM 带宽。为了解决这个问题,英特尔提供了 API,可以让程序在 NUMA 配置中与 GPU 配合使用。
在物理构造方面,PVC和CDNA 3的设计面临着不同的挑战。CDNA 3 提供具有 HBM 的统一内存池的能力需要 IO 芯片之间的高带宽。PVC 使用带宽相对较低的 EMIB 链路。但 PVC 的设计变得复杂,因为它使用四种具有不同工艺节点和铸造厂的模具类型。AMD 在 MI300X 中仅使用两种芯片类型,并且两个节点(6 纳米和 5 纳米)均来自台积电。
02. 解决带宽问题
几十年来,计算速度一直超过内存。与 CPU 一样,GPU 也通过日益复杂的缓存策略来应对这一问题。CDNA 2 使用具有 8 MB L2 的传统两级缓存层次结构,依靠 HBM2e 来保持执行单元的运行。但即使使用 HBM2e,MI250X 的带宽需求也比 Nvidia 的 H100 更严重。如果 AMD 只是增加更多的计算能力,带宽匮乏可能会成为一个严重的问题。因此,AMD 借鉴了 RDNA(2) 的经验,添加了“无限缓存”。
与消费级 RDNA GPU 非常相似,MI300 的无限缓存就是技术文档中所称的“附加最后一级内存”(MALL),这是一种奇特的说法,表示最后一级缓存级别是内存端缓存。与更靠近计算单元的 L1 和 L2 缓存相比,Infinity Cache 连接到内存控制器。所有内存流量都会通过无限缓存,无论它来自哪个块。其中包括 IO 流量,因此对等 GPU 之间的通信可以受益于无限缓存带宽。由于无限高速缓存始终具有 DRAM 内容的最新视图,因此它不必处理窥探或其他高速缓存维护操作。
但由于内存端缓存距离计算较远,因此通常会出现较高的延迟。因此,AMD 在 CDNA 3 和 RDNA 2 上都配备了数兆字节的 L2 缓存,以将计算与内存端缓存的较低性能隔离开来。
与 RDNA 2 一样,CDNA 3 的无限缓存是 16 路组相联的。然而,CDNA 3 的实现针对带宽比针对容量进行了更优化。它由 128 个片组成,每个片容量为 2 MB,每个周期读取带宽为 64 字节。所有切片每个周期总共可以传输 8192 字节,这对于 2.1 GHz 下的 17.2 TB/s 来说是不错的。
相比之下,RDNA 2 的 128 MB 无限缓存可以在所有片上每个周期提供 1024 字节,从而在 2.5 GHz 下提供 2.5 TB/s 的理论带宽。芯片截图显示每个 Infinity Cache 片有 4 MB 的容量,并提供 32B/周期。因此,RDNA 2 使用更大的slice、更少的slice,并且每个slice的带宽也更少。
MI300X 对带宽的关注意味着计算密度较低的工作负载如果能够获得足够的无限缓存命中,仍然可以享受不错的性能。这应该会让 CDNA 3 的执行单元更容易运行,尽管主内存带宽与计算的比率没有太大变化并且仍然落后于 Nvidia。
如果我们使用 Infinity Cache 的理论带宽构建 MI300X 的屋顶线模型,我们可以实现完整的 FP64 吞吐量,每字节加载 4.75 FLOP。与 DRAM 相比,这是一个巨大的改进,DRAM 每加载一个字节需要 14.6FLOP 到 15 次 FLOP。
03. 跨芯片带宽可能面对的挑战
MI300X 的 Infinity Fabric 跨越四个 IO 芯片,每个芯片连接到两个 HBM 堆栈和关联的缓存分区。然而,当 MI300X 作为具有统一内存池的单个逻辑 GPU 运行时,芯片到芯片连接的带宽可能会限制实现完整的无限缓存带宽。如果内存访问在内存控制器(以及缓存分区)上均匀分布,就像大多数 GPU 设计的典型情况一样,可用的芯片到芯片带宽可能会阻止应用程序达到理论上的无限缓存带宽。
首先,让我们关注单个 IO die 分区。它沿着与其他 IO 芯片相邻的两个边缘具有 2.7 TB/s 的入口带宽。它的两个 XCD 可以获得 4.2 TB/s 的 Infinity 缓存带宽。如果 L2 未命中请求在芯片上均匀分布,则该带宽的 3/4 或 3.15 TB/s 必须来自对等芯片。由于 3.15 TB/s 大于 2.7 TB/s,跨芯片带宽将限制可实现的缓存带宽。
我们可以在对角添加芯片而不会产生任何差异,因为其所需的所有芯片间带宽都在相反的方向上。MI300X 具有双向芯片到芯片链接。
如果所有芯片都需要统一配置中的最大无限缓存带宽,事情就会变得更加复杂。消耗额外的跨芯片带宽,因为对角芯片之间的传输需要两跳,这会减少每个芯片可用的入口带宽。
虽然 MI300X 的设计就像一个大型 GPU,但将 MI300X 拆分为多个 NUMA 域可以提供更高的组合无限缓存带宽。AMD 可能会有一个 API,可以在不同的 IO 芯片之间透明地分割程序。此外,高 L2 命中率(hit rates)将最大限度地减少带宽问题的可能性,这将有助于避免这些瓶颈。在 Infinity Cache 命中率较低的情况下,MI300X 的芯片间链接足够稳健,并提供充足的带宽来顺利处理 HBM 流量。
04. 跨XCD一致性
尽管无限缓存不必担心一致性,但二级缓存却需要担心。普通 GPU 内存访问遵循宽松的一致性模型,但程序员可以使用atomics来强制线程之间的排序。AMD GPU 上的内存访问也可以用 GLC 位(全局级一致:Global Level Coherent)进行标记。如果 AMD 希望将 MI300X 作为单个大 GPU 而不是像 MI250X 那样的多 GPU 配置,那么这些机制仍然必须发挥作用。
在之前的 AMD GPU 上,atomics和coherent 访问是在 L2 处理的。设置 GLC 位的加载将绕过 L1 缓存,从而从 L2 获取最新的数据副本。这不适用于 MI300X,因为缓存行的最新副本可能位于另一个 XCD 的 L2 缓存上。AMD 可以使相干访问绕过 L2,但这会降低性能。这可能适用于游戏 GPU,因为游戏 GPU 的一致性访问并不是太重要。但 AMD 希望 MI300X 在计算工作负载方面表现良好,并需要 MI300A(APU 变体)在 CPU 和 GPU 之间高效共享数据。这就是 Infinity Fabric 的用武之地。
与 Ryzen 上的 Infinity Fabric 一样,CDNA 3 具有 XCD 连接到 IO 芯片的 Coherent Master(CM)。相干从属设备 (CS:Coherent Slaves) 与无限高速缓存 (IC:Infinity Cache) 片一起位于每个内存控制器中。我们可以通过 Ryzen 文档推断它们是如何工作的,该文档显示 Coherent Slaves 有一个探针过滤器和用于处理原子事务的硬件。MI300X 可能有类似的 CS 实现。
如果 CS 上出现一致写入,则必须确保任何执行一致读取的线程都会观察到该写入,无论该线程在 GPU 上的何处运行。这意味着任何缓存了该行的 XCD 都必须从 Infinity Cache 重新加载它才能获取最新数据。这一般会让我们认为,CS 必须跨所有 XCD 探测 L2 缓存,因为其中任何一个都可以缓存相应的数据。探测过滤器通过跟踪哪些 XCD 实际缓存了该行来帮助避免这种情况,从而避免不必要的探测流量。CDNA 3 的白皮书称窥探过滤器(探针过滤器的另一个名称)足够大,可以覆盖多个 XCD L2 缓存。我当然相信他们,因为 MI300X 在所有 8 个 XCD 上都有 32 MB 的 L2。即使是消费级 Ryzen 部件也可以拥有更多 CCD 专用缓存,供探针过滤器覆盖。
得益于 CS 和 CM 等类似 CPU 的 Infinity Fabric 组件,XCD 可以拥有私有回写式 L2 缓存,能够处理芯片内一致访问,而无需跨越 IO 芯片结构。AMD 本来可以采用一种简单的解决方案,即连贯操作和atomics绕过 L2 直接进入无限缓存。这样的解决方案将节省工程工作并创建更简单的设计,但代价是降低一致性操作的性能。显然,AMD 认为优化原子和相干访问非常重要,因此需要付出更多努力。
然而,XCD 中的 CDNA 3 的工作方式仍然与之前的 GPU 非常相似。显然,正常的内存写入不会像 CPU 那样自动使来自对等缓存的写入行无效。相反,代码必须显式告诉 L2 write back dirty lines,并使对等 L2 缓存使非本地 L2 行无效。
05. 二级缓存
靠近计算单元,每个 MI300X XCD 都包含一个 4 MB 二级缓存。L2 是更传统的 GPU 缓存,由 16 个slice构建。每个 256 KB slice可以提供每个周期 128 字节的带宽。在 2.1 GHz 下,这对于 4.3 TB/s 来说是不错的。作为与计算单元位于同一芯片上的最后一级缓存,L2 在充当 L1 未命中(misses)的后备装置方面发挥着重要作用。
与H100和MI250X相比,MI300X具有更高的L2带宽计算比。由于每个 XCD 都配有 L2,因此随着 CDNA 3 产品配备更多 XCD,L2 带宽自然会扩展。换句话说,MI300X 的 L2 布局避免了将单个缓存连接到大量计算单元并维持大量带宽的问题。
PVC的L2则形成鲜明对比。随着英特尔添加更多计算块,基础块的共享 L2 的带宽需求也不断增加。从缓存设计的角度来看,PVC 的配置更简单,因为 L2 充当单点一致性和 L1 未命中的后备。但它无法提供与 MI300X 的 L2 一样多的带宽。MI300X 还可能享有更好的 L2 延迟,使应用程序更容易利用缓存带宽。
06. 一级缓存
CDNA 3 对高缓存带宽的关注延续到了 L1。在与 RDNA 相匹配的举措中,CDNA 3 的 L1 吞吐量从每周期 64 字节增加到 128 字节。与 GCN 中的 2048 位相比,CDNA 2 将每 CU 向量吞吐量提高到每周期 4096 位,因此 CDNA 3 翻倍的 L1 吞吐量有助于保持与 GCN 相同的计算与 L1 带宽比率。
除了更高的带宽外,CDNA 3 还将 L1 容量从 16 KB 增加到 32 KB。这一举措再次反映了 RDNA 系列的发展,其中 RDNA 3 的一级缓存也获得了类似的大小提升。较大缓存的较高命中率将降低平均内存访问延迟,从而提高执行单元利用率。从 L2 及更高层传输数据会消耗电力,因此更高的命中率也有助于提高电力效率。
虽然 CDNA 3 改进了一级缓存,但 Ponte Vecchio 仍然是该类别的冠军。PVC 中的每个 Xe 核心每个周期可传输 512 字节,为英特尔提供非常高的 L1 带宽计算比。L1 也很大,为 512 KB。适合 L1 的内存绑定内核将在英特尔架构上表现良好。然而,Ponte Vecchio 缺乏计算块级别的中级缓存,并且当数据溢出 L1 时可能会面临严酷的性能悬崖。
07. 调度和执行单元
复杂的小芯片设置和修改后的缓存层次结构让 AMD 将 MI300X 作为单个 GPU 呈现,从而解决了 MI250X 的最大弱点之一。但 AMD 并没有就此解决。他们还对核心计算单元架构进行了迭代改进,解决了 CDNA 2 使用 FP32 单元的困难。
当 CDNA 2 转向原生处理 FP64 时,AMD 通过打包执行提供了双倍速率 FP32。编译器必须将两个 FP32 值打包到相邻的寄存器中,并对这两个值执行相同的指令。通常,除非程序员明确使用向量,否则编译器很难实现这一点。
CDNA 3 通过更灵活的双发行机制解决了这个问题。最有可能的是,这是 GCN 多问题功能的扩展,而不是 RDNA 3 的 VOPD/wave64 方法。每个周期,CU 调度程序都会选择四个 SIMD 之一,并检查其线程是否已准备好执行。如果多个线程准备就绪,GCN 可以选择最多五个线程发送到执行单元。当然,GCN SIMD 只有一个 16 宽向量 ALU,因此 GCN 必须选择具有不同指令类型的线程,准备好进行多发出。例如,标量 ALU 指令可以与矢量 ALU 指令一起发出。
另一种方法是利用 wave64 更宽的宽度,让线程在四个周期内完成两条向量指令。然而,这样做会破坏 GCN 在 4 个时钟周期的倍数内处理 VALU 指令的模型。CDNA 3 与 GCN 的关系仍然比 RDNA 更为密切,重用 GCN 的多发行策略是明智之举。AMD 还可以使用 RDNA 3 的 VOPD 机制,其中特殊的指令格式可以包含两个操作。虽然该方法可以提高每个线程的性能,但依靠编译器来查找双问题对可能会成功或失败。
CDNA 3 的双问题方法可能会将责任推给程序员,以通过更大的调度大小来公开更多线程级并行性,而不是依赖编译器。如果 SIMD 有更多正在运行的线程,它将有更好的机会找到两个带有 FP32 指令准备执行的线程。至少,SIMD 需要两个活动线程才能实现完整的 FP32 吞吐量。实际上,CDNA 3 需要更高的占用率才能实现良好的 FP32 利用率。GPU 使用按顺序执行,因此各个线程通常会因内存或执行延迟而被阻塞。即使在满员的情况下,保持一组执行单元的供电也可能很困难。
因此,AMD 将每个 CDNA 3 SIMD 可以跟踪的线程数量从 8 个大幅增加到24 个。如果程序员可以利用这一点,CDNA 3 将更好地定位于多问题。但这可能很困难。AMD 没有提到矢量寄存器文件容量的增加,这通常会限制 SIMD 可以运行的线程数量。如果每个线程使用较少的寄存器,向量寄存器文件可以保存更多线程的状态,因此 CDNA 3 的多发出功能可能最适合具有很少活动变量的简单内核。
寄存器文件带宽对双重发行提出了另一个挑战。CDNA 2 的打包 FP32 执行不需要从向量寄存器文件中进行额外的读取,因为它利用了传递 64 位值所需的更宽的寄存器文件端口。但单独的指令可以引用不同的寄存器,并且需要从寄存器文件中进行更多读取。添加更多寄存器文件端口的成本高昂,因此 CDNA 3“逐代改进了源缓存,以提供更好的重用和带宽放大,以便每个向量寄存器读取可以支持更多下游向量或矩阵操作” 。最有可能的是,AMD 正在使用更大的寄存器缓存来缓解端口冲突并保持执行单元的运行。
08. 矩阵运算
随着机器学习的兴起,矩阵乘法变得越来越重要。Nvidia 在这一领域投入了大量资金,多年前就在其 Volta 和 Turing 架构中添加了矩阵乘法单元(张量核心)。AMD 的 CDNA 架构增加了矩阵乘法支持,但当代 Nvidia 架构在矩阵乘法吞吐量方面投入了更多资金。这尤其适用于 AI 中常用的低精度数据类型,例如 FP16。
与前几代 CDNA 相比,MI300X 通过将每 CU 矩阵吞吐量提高了一倍来迎头赶上。最重要的是,MI300X 的小芯片设计允许大量的 CU。但 Nvidia 更高的每 SM 矩阵性能仍然使其成为一支不可忽视的力量。因此,CDNA 3延续了AMD从矢量FP64性能方面重击Nvidia的趋势,同时保持了孤立的强大AI性能。
09. 指令缓存
除了处理指令请求的内存访问之外,计算单元还必须从内存中获取指令本身。传统上,GPU 的指令传递比较容易,因为 GPU 代码往往很简单并且不会占用大量内存。在DirectX 9时代,Shader Model 3.0甚至对代码大小进行了限制。随着 GPU 不断发展以承担计算任务,AMD 推出了具有 32 KB 指令缓存的 GCN 架构。如今,CDNA 2 和 RDNA GPU 继续使用 32 KB 指令缓存。
CDNA 3 将指令缓存容量增加至 64 KB。关联性也加倍,从 4 路变为 8 路。这意味着具有更大、更复杂内核的 CDNA 3 的指令缓存命中率更高。我怀疑 AMD 的目标是将 CPU 代码天真地移植到 GPU。复杂的 CPU 代码可能会对GPU 造成影响,因为它们无法通过长距离指令预取和准确的分支预测来隐藏指令缓存未命中延迟。更高的指令缓存容量有助于容纳更大的内核,而增加的关联性有助于避免冲突未命中。
与 CDNA 2 一样,每个 CDNA 3 指令缓存实例为两个计算单元提供服务。GPU 内核通常以足够大的工作大小启动,以填充许多计算单元,因此共享指令缓存是有效使用 SRAM 存储的好方法。我怀疑 AMD 没有在更多计算单元之间共享缓存,因为单个缓存实例可能难以满足指令带宽需求。
10. 写在最后的话
CDNA 3 的白皮书称“AMD CDNA 3 架构中最大的代际变化在于内存层次结构”,我不得不同意。与 CDNA 2 相比,虽然 AMD 改进了计算单元的低精度数学功能,但真正的改进是添加了无限缓存。
MI250X 的主要问题是它并不是真正的 GPU。它是两个 GPU 共享同一个包,GCD 之间每个方向每秒只有 200 GB。根据 AMD 的评估,每个方向每秒 200 GB 不足以让 MI250X 显示为一个 GPU,这就是 AMD 显着增加芯片到芯片带宽的原因。
AMD 将东西向总带宽提高到每个方向 2.4TB/秒,比 MI250X 增加了 12 倍。南北向总带宽甚至更高,每个方向为 3.0TB/秒。随着带宽的大幅增加,AMD 能够使 MI300 看起来像一个大型的统一加速器,而不是像 MI250X 那样是 2 个独立的加速器。
如果两个 XCD 都需要所有可用内存带宽,则一个芯片的 4.0 TB/s 总入口带宽可能看起来不够。然而,两个 XCD 组合起来只能从 IO 芯片访问高达 4.2TB/s 的带宽,因此实际上 4.0TB/s 的入口带宽不是问题。最大 4.0TB/s 的入口带宽意味着单个 IO 芯片无法利用所有 5.3TB/s 的内存带宽。
这与桌面 Ryzen 7000 部件类似,由于 Infinity Fabric 的限制,一个 CCD 无法充分利用 DDR5 带宽。然而,这在 MI300X 上可能不是问题,因为所有芯片都在运行时,带宽需求将最高。在这种情况下,每个芯片将消耗约 1.3 TB/s 的带宽,通过跨芯片链路获取其中的 3/4 不会有问题。
但MI300不只是GPGPU部分,它还有APU部分,在我看来这是这两款MI300产品中更有趣的一个。AMD 首款 APU Llano 于 2011 年发布,它基于 AMD 的 K10.5 CPU 搭配 Terascale 3 GPU。快进到 2023 年,AMD 在其首款“big iron”APU MI300A 中将 6 个 CDNA3 XCD 与 24 个 Zen 4 核心配对,同时重复使用相同的基础芯片。这允许 CPU 和 GPU 共享相同的内存地址空间,从而无需通过外部总线复制数据以保持 CPU 和 GPU 彼此一致。
审核编辑:黄飞
评论
查看更多