AMD 与 Intel:一场 Unicode 基准测试
简而言之,我们的处理器主要分为两种类型:手机中的 ARM 处理器,以及由 Intel 和 AMD 制造的 x64 处理器。过去,最好的服务器处理器由 Intel 制造。但如今,Intel 越来越难以保持领先地位。
最近,亚马逊提供了最新的 AMD 微架构(Zen 5)。具体来说,如果你启动一个 r8a 实例,你会得到一个 AMD EPYC 9R45 处理器。其 Intel 对应产品(r8i 实例)则搭载 Intel Xeon 6975P-C 处理器。这款 Intel 处理器属于 Granite Rapids 家族(2024年发布)。
Phoronix 网站的 Michael Larabel 有几篇关于新款 AMD 处理器的文章。其中一篇题为《AMD EPYC 9005 带来惊人性能》。这篇文章非常值得一读。他发现,与上一代 AMD 处理器(采用 Zen 4 微架构)相比,AMD EPYC 9R4 的速度快了 1.6 倍。在另一篇文章中,Michael 将 AMD 处理器与对应的 Intel 处理器进行了比较。他发现 AMD 处理器比 Intel 处理器快 1.6 倍。
我决定亲自上手测试一番。当时我正好在准备 simdutf 库的新版本发布。simdutf 库能够快速在 UTF-8、UTF-16 和 UTF-32 编码之间进行转换,并具有其他功能。它被主流浏览器和 JavaScript 运行时(如 Node.js 或 Bun)所使用。一个常见且重要的操作是从 UTF-16 转换为 UTF-8。JavaScript 内部使用 UTF-16,因此大多数字符使用 2 字节,而互联网默认使用 UTF-8,字符可以使用 1 到 4 字节。
UTF-16 是一种变长 Unicode 编码,它使用单个 16 位码元(值从 0x0000 到 0xd7ff 以及 0xe000 到 0xffff)表示最常见的字符,但通过使用代理对来扩展到 U+FFFF 之外的完整 Unicode 范围:一个高代理项(0xd800 到 0xdbff)后跟一个低代理项(0xdc00 到 0xdfff),两者共同编码一个补充字符,该字符映射为四个 UTF-8 字节。因此,我们可以认为代理对中的每个元素在 UTF-8 中占用两个字节。范围在 0x0000 到 0x007f(ASCII)的非代理项码元变为一个字节,0x0080 到 0x07ff 变为两个字节,0x0800 到 0xffff(不包括代理项)变为三个字节。
我的基准测试代码首先确定需要多少输出内存,然后进行转码。
|
|
在现代处理器上的转码代码并不简单(Clausecker 和 Lemire, 2023)。然而,从 UTF-16 数据计算 UTF-8 长度的过程相对简单一些。
这些 Intel 和 AMD 处理器支持 AVX-512 指令:这些指令可以操作最多 64 字节的寄存器,而我们通常使用 64 位寄存器。这是 SIMD 的一个实例:单指令多数据。使用 AVX-512,你可以一次加载和处理 32 个 UTF-16 单元。我们的主例程如下所示。
|
|
该代码使用 _mm512_loadu_si512 加载来自内存的 512 位 UTF-16 码元向量。然后,它首先通过应用按位与(_mm512_and_si512)来屏蔽每个码元的前五位(与 0xf800 进行与操作),并将结果与 0xd800 进行比较(_mm512_cmpeq_epi16_mask),从而识别代理项码元;这会产生一个 32 位掩码,其中处于代理范围(0xd800 到 0xdfff)内的任何码元对应的位被置位,表明是潜在的 UTF-16 代理对,它们在 UTF-8 中不应贡献额外的长度。接下来,我们使用位测试(_mm512_test_epi16_mask)将每个码元与 0xff80 的掩码进行比较,为任何非 ASCII 码元在 c0 中设置位。类似地,另一个针对 0xf800 的 _mm512_test_epi16_mask 操作为需要 3 个 UTF-8 字节的码元(代理对除外)在 c1 中设置位。最后,代码将 c0 和 c1 中的置位位数累加到计数器中,然后减去代理掩码的 popcount。总的来说,我们可以用大约十几条指令处理约 32 个 UTF-16 单元。(设计思路归功于 Wojciech Muła,相关优化也感谢 Yagiz Nizipli 的帮助。)
搭载 AMD 处理器的大型 Amazon 实例价格为 0.13892 美元/小时,而 Intel 处理器实例为 0.15976 美元/小时。我使用 Amazon Linux 启动了这两个实例。然后我在 shell 中运行了以下命令。
|
|
我得到了以下结果。
| 处理器 | GB/s | GHz | Ins/Byte | Ins/Cycle |
|---|---|---|---|---|
| AMD | 11 | 4.5 | 1.7 | 4.0 |
| Intel | 6 | 3.9 | 1.7 | 2.6 |
基准测试结果表明,在 UTF-16 到 UTF-8 的转码中,AMD 处理器的吞吐量几乎是 Intel 处理器的两倍(10.53 GB/s 对比 5.96 GB/s),部分得益于其更高的工作频率。两个系统都需要相同的 1.71 条指令/字节,但 AMD 实现了显著更高的每周期指令数(3.98 i/c 对比 2.64 i/c),这表明其在 AVX-512 流水线内的执行效率更优。其中一个原因与执行单元的数量有关。AMD 处理器有四个能够处理 512 位寄存器的计算单元,而 Intel 通常仅限于两个这样的执行单元。
我的基准测试比 Larabel 的更具体,它们有助于表明 AMD 在使用 AVX-512 指令时相比 Intel 具有巨大优势。考虑到 AVX-512 是 Intel 发明的而 AMD 较晚才支持,这一点尤其引人注目。可以说 AMD 在其对手的游戏中击败了它。
我的基准测试代码可供获取。 进一步阅读:Robert Clausecker, Daniel Lemire, Transcoding Unicode Characters with AVX-512 Instructions, Software: Practice and Experience 53 (12), 2023. Daniel Lemire, “AMD vs. Intel: a Unicode benchmark,” in Daniel Lemire’s blog, November 16, 2025, https://lemire.me/blog/2025/11/16/amd-vs-intel-a-unicode-benchmark/.