AMD Ryzen™ 处理器软件优化指南
目录
- Zen 2 和 Zen 3 处理器概述
- Zen 2 架构处理器
- 2.1 Zen 2 基本产品形态
- 2.2 Xbox 系列 X 和 S 的 Zen 2 处理器
- 2.3 同时多线程技术
- Zen 3 架构处理器
- 3.1 Zen 3 的改进与性能提升
- 3.2 Zen 3 处理器架构图
- 3.3 高级同步 API 的使用建议
- 最佳实践
- 4.1 审查内容和优化建议
- 4.2 使用现代同步 API
- 4.3 解决虚假共享问题
- 4.4 数据访问模式和硬件预取
- 4.5 使用软件预取指令
- 4.6 应用程序的可伸缩性测试和优化
- 4.7 锁和互斥量的选择
- 4.8 虚假共享和性能优化
- 附录
- 5.1 Windows 性能分析工具的使用
- 5.2 AMD uProf 性能分析工具
- 5.3 SMT 的使用和优化建议
- 了解更多
Zen 2 和 Zen 3 处理器概述
Zen 2 和 Zen 3 是由 AMD 推出的一系列处理器架构,用于提供卓越的游戏和计算性能。这些处理器采用了先进的技术和架构设计,旨在优化游戏主机和个人电脑的性能。
Zen 2 架构处理器
2.1 Zen 2 基本产品形态
Zen 2 架构处理器以多种形态存在。移动处理器系列 Ryzen 4000 以代号“Renoir”命名,采用了先进的 Zen 2 架构,在超薄笔记本电脑中提供了高达 8 个强大的核心。这些笔记本电脑非常适合那些携带需求有限的用户,只需 15 瓦功率即可运行。
另一方面,主流台式机处理器系列 Ryzen 3000 以代号“Matisse”命名,提供了高达 16 核心的处理能力,适用于游戏和其他工作负载。而高端台式机处理器系列 Ryzen 3000 以代号“Castle Peak”命名,提供了高达 64 核心的处理能力,旨在满足数字内容创作者和软件开发人员的需求。
2.2 Xbox 系列 X 和 S 的 Zen 2 处理器
Xbox Series X 和 Series S 的定制设计处理器采用了 Zen 2 CPU 和 RDNA 2 图形架构。Zen 2 架构的 CPU 性能大大提升,比 Xbox One X 的性能提高了四倍以上。尽管 Ryzen 移动处理器的 CPU 架构、核心数量和缓存大小与 Xbox 系列处理器相似,但内存和图形设计却有很大的差异。
2.3 同时多线程技术
同时多线程(Simultaneous Multi-Threading, SMT)是高性能处理器的一项重要技术,它允许利用空闲的处理器资源执行额外的硬件线程。两个硬件线程共享核心资源,但也会带来一些带宽和延迟方面的折衷。开发人员可以根据这些折衷点对性能进行优化。
Zen 2 支持2路 SMT,可以以单线程或双线程模式运行。程序线程的选择是在分支预测期间进行的,通常使用循环调度的方式进行。在双线程模式下,核心处于双线程模式,同时执行两个逻辑处理器的程序线程。如果其中一个逻辑处理器执行操作系统的空闲线程,则该核心将返回单线程模式。通过禁用 SMT 和偏置菜单选项,可以减少系统中的逻辑处理器数量,限制核心仅在单线程模式下运行。
共享资源的定义如下:竞争共享的资源条目是按需分配的,一个线程可以使用所有资源条目;带有水印的资源条目是按需分配的,当处于双线程模式时,线程不能使用超过水印阈值指定的资源条目;静态划分的资源条目在进入双线程模式时进行划分,线程不能使用超过分区中可用资源条目的数量;而退出双线程模式时,资源条目是未分区的。大多数资源是竞争共享的,但是浮点调度器和存储队列等资源是带有水印的静态划分的。对于轻负载的应用程序,在核心处于单线程模式时,运行效果最好,以减少资源共享。不论在单线程模式还是双线程模式下使用的指令集是相同的。Zen 2 添加了缓存行写回和写回无效的指令,矢量化指令使用浮点调度器和执行单元。AMD 和 Intel 处理结果的二进制格式可能在求倒数和求平方根指令方面不一致,尽管两者都符合ISA兼容性,但我们希望 AMD Jaguar 和 Zen 在浮点指令方面是等效的。需要注意的是,Zen 2 不支持 AVX-512 或 AMX 指令。软件预取指令是用于将指定内存地址的缓存行加载到与局部性参考提示(T0、T1、T2 或 NTA)指定的数据缓存级别中的指令。这个指令在实现上是不同的,Prefetch 的填充和清除策略在其他处理器上可能不同。Zen 1、Zen 2 和 Zen 3 的缓存详细信息,包括路数、关联度、包含策略和权重策略,在 AMD 的软件优化指南中有详细介绍。系统的高级数据流视图可以帮助说明可能的瓶颈情况。该视图显示了 AMD Ryzen 4000 系列移动处理器的抽象图,称为“Renoir”。想象远右边的 DRAM 中的数据通过数据传输缓存和核心向左移动。每个统一内存控制器管理 64 位的 DRAM,例如一个 64 位 DDR4 或者两个 32 位 LPDDR4。需要注意的是,这是一个单片 SoC 设计,具有橙色核心复合 L3 缓存,以 32 字节每周期读取和 32 字节每周期写入的速度与蓝色的数据传输缓存相连。与 AMD Zen 2 桌面产品不同,这个产品只有 4MB 的 L3 缓存。后面我们将会介绍的 Ryzen 7 4700G 处理器基于 Renoir 架构。接下来,这个幻灯片展示了一个抽象的 AMD Ryzen 3000 系列主流台式机处理器“Matisse”的架构图。这是一个 Chiplet 设计,具有两个核心复合芯片,也称为 CCD。每个 CCD 都有两个 16MB 的 L3 缓存。然而,CCD 内部的 L3 缓存复合体共享一个与数据传输缓存的链接,读取速度为每周期 32 字节,写入速度为每周期 16 字节。最后,这个幻灯片展示了一个抽象的 AMD Ryzen 3000 系列高端台式机处理器,代号“Castle Peak”。这种拓扑结构具有高达 8 个 CCD,示意图中将其分成了四个象限以简化显示。需要注意的是,每个象限的结构与 Matisse 相似,但是 Castle Peak 有一个更大的 IO 芯片,具有额外的统一内存控制器和 PCI 线路。用户可以根据需求添加多个 GPU 和 NVMe 驱动器。
Zen 3 架构处理器
3.1 Zen 3 的改进与性能提升
Zen 3 架构在性能方面取得了令人瞩目的进步,与之前的 Zen 2 架构相比,提升了19%的桌面 IPC。它采用了统一的 8 核心集群,以促进更快的缓存传输,并且 L3 缓存容量翻倍,改进了加载存储单元、增加浮点和整数引擎的宽度,提高了 SMT 的公平性,并增加了新的密码学指令。
从 Zen 2 到 Zen 3 的资源共享方面发生了一些改变。整数调度器、整数寄存器文件和加载队列将竞争共享改为了带有水印。这些更改改善了 SMT 的公平性,除此之外,资源共享的方式与 Zen 2 相似。指令集方面也有一些改动,Zen 3 添加了矢量化 AES 和矢量化乘法运算指令,通常用于密码学。此外,平行位提取和平行位插入指令的延迟仅为三个周期。需要注意的是,Zen 3 不支持 AVX-512 或者 AMX 指令。
3.2 Zen 3 处理器架构图
这里展示了 AMD Ryzen 5000 系列主流台式机处理器“Vermeer”的抽象架构图。它采用了 Chiplet 设计,每个核心复合芯片具有统一的 8 核心集群和巨大的 32MB L3 缓存。这种改进大大提高了缓存命中率,减少了某些应用程序的数据传输争用。
3.3 高级同步 API 的使用建议
在使用 Zen 3 架构处理器时,推荐使用现代的同步 API。一些现代的同步 API 可以有效地利用 AMD 的 MWAIT X 指令在等待地址或超时上。传统的同步 API 可能具有不必要的系统调用开销,用户自旋锁可能会不必要地消耗操作系统线程调度资源,因为操作系统调度程序可能无法确定是否应该暂停自旋而不是继续运行。通过使用标准互斥量,性能可以提升超过 10%。这里展示了一个使用互斥锁的微基准测试的源代码,它会统计所有线程执行回调函数所需的时间。不好的用户自旋锁可能会浪费电力并耗尽电池。更糟糕的是,操作系统调度程序可能无法确定是否应该在进行非有效负载工作时暂停执行,而不是自旋。我们可以看到,不加 pause 指令的 while 循环可能过于主动地占据核心资源,而不进行有效负载工作,并对具有较少 SMT 公平性的旧处理器造成很大的痛苦。另外,在这个例子中,使用 WaitForSingleObject 和 CreateMutex 可以解决问题。这两个 API 已经存在很长时间了,WaitForSingleObject 函数检查指定对象的当前状态,如果对象的状态不是已标记,则调用线程进入等待状态,直到对象被标记或者超时时间到期。因此,WaitForSingleObject 可能不会受到某些不好的用户自旋锁引起的操作系统线程调度和核心资源共享问题的影响。需要注意的是,这个示例在主函数中需要一些初始化工作,而标准互斥量甚至比 WaitForSingleObject 更快。这个现代同步 API 是基于 Slim Reader/Writer Lock 和 Microsoft 的实现,可以使用 Windows 性能分析器进行验证。在我的测试中,标准的共享互斥量和进入临界区也优于 WaitForSingleObject。查找和修复虚假共享问题可能会有很大的性能好处。这个微基准测试展示了超过 500% 的性能提升。在这个示例中,我们使用 alignas 接口对每个线程的数据进行了填充,以避免在回调函数使用线程数据时发生不必要的缓存行争用。优化之前,在最内层循环中的许多数据访问操作都无法命中 AMD Ryzen 7 4700G 的 4MB 最后一级缓存。由于复合类的成员数据不是公共的,因此无法使用偏移关键字,因此我们显示了字面上的偏移量。在这个示例中没有展示,但通过重新排列热成员数据,使其只占用一个缓存行而不是四个,可能还可以获得更高的性能。有些应用程序在使用许多逻辑处理器时具有很好的可伸缩性。例如,Cinebench R23 在具有 8 个核心和 16 个逻辑处理器的系统配置上性能提高了 28%,得益于 SMT 的支持。g_threadCount 命令行选项可以非常接近地确定实际使用的逻辑处理器数量。游戏的线程可伸缩性在很大程度上取决于游戏引擎和系统的 GPU、CPU、内存等。我们经常看到游戏性能在受制于 GPU 的情况下水平偏低。降低分辨率可能有助于预测未来更快 GPU 的性能。在 UE4.26 中,Core Limit 命令行选项将影响测试图形需要生成的工作线程数量,也可以创建其他线程。对于渗透者演示游戏,Windows 性能分析器显示最热的线程是渲染线程一、RHI 线程和主线程,其次是任务图线程。在我们的可伸缩性测试中,平均性能在核心限制为 4 时达到峰值,并在较高的核心限制值下保持相对稳定。通过查看帧时间的百分位数,我们可能会发现平均值未能发现的性能问题。在进行比较时,确保有足够的样本,特别是 3 倍标准差及以上的样本。在这个例子中,我们可以看到在高核心限制值下性能下降了,而默认值实际上是逻辑处理器数量减去 2。将默认核心限制值与最佳核心限制值相比较,平均值较慢 3%,68%百分位数较慢 5%,95%百分位数较慢 5%,99.7%百分位数较慢 3%。当以管理员身份运行并使用高级设置时,可使用 AMD uProf 工具显示进程的实际线程并发直方图。在左边,使用默认的 core limit 值时,SMT 线程使用了 13% 的时间。在右边,使用 core limit 值为 4 时,SMT 线程仅使用了 2% 的时间,但性能稍有提高。在互联网上搜索最近的技术媒体游戏评测和使用生物设置的 SMT 开启和关闭的结果可能是不一致的,这再次证明了在游戏开发期间进行应用可伸缩性测试的必要性。根据我们的经验,某些游戏的性能在减少工作线程数量后提高了5%或更多。请务必对应用程序进行性能分析,特别是对于最低、推荐和超高 PC 规格,以确定最佳的工作线程数量。这些建议是针对 AMD 处理器的一般性建议,并不适用于所有处理器厂商。一般来说,应用程序会从 SMT 中受益,推荐使用所有逻辑处理器。然而,在游戏进行中,可能会发生 SMT 冲突,占用主线程或渲染线程的资源。减少这种冲突的一种策略是根据物理核心数量而不是逻辑处理器数量创建线程。通过对应用程序或游戏进行性能分析,可以确定理想的线程数量。游戏初始化阶段,包括解压资产、编译和预热着色器等,可能会受益于使用 SMT 双线程模式的逻辑处理器。然而,游戏进行阶段可能更适合使用物理核心数量,仅使用 SMT 单线程模式。我建议为游戏增加选项,如设置最大线程池大小、强制线程池大小、强制 SMT 和强制单一 NUMA 节点,这将隐式地限制到单一处理器组。最后,避免将线程池大小设置为固定值,建议作为一个可调整的参数。可以在 gpuopen.com 上找到 AMD 处理器的核心数量检测代码示例,我们计划更新这个示例,增加一个低核心阈值,并更清楚地阐述关于游戏进行和游戏初始化建议的指南。这些建议仅适用于 AMD 处理器,并且基于我们的经验,可能随着技术的进展而发生变化。请根据您的应用程序进行性能分析,以获得最佳性能。
最佳实践
为了充分发挥 Zen 2 和 Zen 3 处理器的优势,以下是一些最佳实践的建议:
4.1 审查内容和优化建议
- 审查内容:向艺术家询问他们推荐的有趣场景,以进行分析。例如,有大量遮挡的室内地牢、室外城市、带有透明度的室外森林、大型人群或特定时间的场景。
- 优化建议:在进行 CPU 分析之前,检查统计信息。如果场景超出绘制预算或存在许多重复的对象(特别是物理对象),请考虑将此问题反馈给艺术家并对不同的场景进行分析。否则,可能会针对不再热门的热点进行分析。
4.2 使用现代同步 API
- 推荐使用现代同步 API,这些 API 可以充分利用 AMD 的 MWAIT X 指令,以高效地等待地址或超时。
- 避免使用过时的同步 API,因为它们可能会引入不必要的系统调用开销。
- 用户自旋锁可能会消耗操作系统线程调度资源,因为操作系统调度程序可能无法确定是否应该将其暂停,以便执行其他有负载工作的线程而不是自旋。
- 使用标准互斥量可以提高性能。
4.3 解决虚假共享问题
- 虚假共享问题指的是多个线程同时修改同一缓存行的情况,而这些线程在使用相应的内存时可能会相互干扰。
- 通过修改数据填充和对齐以避免虚假共享,可以获得显著的性能改进。
4.4 数据访问模式和硬件预取
- 了解并匹配硬件预取器的数据访问模式,特别是流式和步幅数据访问模式。
- 合理使用软件预取指令,以优化访问链表等数据结构的性能。
4.5 使用软件预取指令
- 根据缓存大小和内存延迟等因素,使用软件预取指令可以获得超过60%的性能提升。
- 需要根据不同的缓存大小和内存延迟进行测试,以确定最佳的软件预取策略。
4.6 应用程序的可伸缩性测试和优化
- 对于多线程应用程序,测试和优化其可伸缩性是非常重要的。
- 通过增加或减少线程数量,并测试应用程序的可伸缩性,可以找到最佳的线程数。
4.7 锁和互斥量的选择
- 根据应用程序的特性,选择适合的锁和互斥量。
- 标准互斥量通常比自旋锁更快,并且可以避免一些资源共享问题。
4.8 虚假共享和性能优化
- 通过分配线程到不同的最后一级缓存连接的核心,可以减少虚假共享问题,提高性能。
附录
5.1 Windows 性能分析工具的使用
- 使用 Windows 性能分析工具,可以显示进程的线程并发直方图,用于分析线程使用情况和优化性能。
5.2 AMD uProf 性能分析工具
- 使用 AMD uProf 工具可以显示实际线程并发直方图,用于性能分析和优化。
5.3 SMT 的使用和优化建议
- 推荐根据应用程序的特性和需求,优化 SMT 的使用,避免 SMT 引起的性能下降。
- 可以根据应用程序的性能进行测试和优化,确定理想的线程数和 SMT 设置。
了解更多
- developer.amd.com上提供了 Zen 2 和 Zen 3 的软件优化指南,以供进一步了解和参考。
- 在gpuopen.com上可以找到用于优化图形性能的开源效果、SDK、工具和教程。加速设计、渲染和迭代过程。
- 感谢您选择花时间阅读本文,期待看到您的作品。
Highlights:
- Zen 2 和 Zen 3 是由 AMD 推出的一系列处理器架构,提供卓越性能和计算能力。
- Zen 2 架构处理器适用于移动和台式机,而 Zen 3 架构提供了更大的性能改进。
- 使用现代同步 API 可以提高性能,并优化数据访问模式以匹配硬件预取器。
- 虚假共享问题可能会影响性能,可以通过修改数据填充和引入锁来解决。
- 应根据应用程序的特性和要求进行可伸缩性测试和优化。
FAQs:
Q: Zen 3 处理器是否支持 AVX-512 指令?
- A: 不支持。Zen 3 处理器不支持 AVX-512 指令集。
Q: 如何选择合适的锁和互斥量?
- A: 根据应用程序的特性选择合适的锁和互斥量。标准互斥量通常比自旋锁更快,并且可以避免资源共享问题。
Q: Zen 2 和 Zen 3 处理器之间有什么不同?
- A: Zen 2 架构处理器是 Zen 3 架构的前一代,Zen 3 架构提供了更高的性能和改进的特性。
Q: 怎样可以优化应用程序的可伸缩性?
- A: 可以增加或减少线程数量,并测试应用程序的可伸缩性,以确定最佳的线程数。
Q: 什么是虚假共享问题?如何解决?
- A: 虚假共享指的是多个线程同时修改同一缓存行的情况,通过修改数据填充和引入锁,可以解决虚假共享问题。