在软件中,我们使用 Unicode 转换格式 (UTF) 之一(最流行的是 UTF-8 和 UTF-16)将文本字符串作为字节数组存储在内存中。 Windows、Java、C# 和其他系统常见语言和系统默认使用 UTF-16,而其他系统和大多数 Web 则依赖于 UTF-8。两种格式各有利弊,我们不会很快就采用其中一种格式。这意味着我们必须不断地将字符串从 UTF-8 转换为 UTF-16,然后再转换回来。
非常重要的是,基于 z/Architecture 的 IBM 大型机提供了名为“CONVERT UTF-8 TO UTF-16”和“CONVERT UTF-16 TO UTF-8”的专用指令,用于两种编码之间的转换。由于采用硬件实现,典型输入的处理速度超过 10 GiB。我们其他人无法使用功能强大的大型机,但我们的处理器具有单指令多数据 (SIMD) 指令。这些 SIMD 指令在表示数字向量的较大寄存器(128 位、256 位)上运行。从 AMD Zen 4 系列处理器开始,到最新的服务器 Intel 处理器(即 Ice Lake 或更好),我们拥有强大的 SIMD 指令,可以操作超过 512 位数据 (AVX-512)。宽度(512 位)并不是这些指令最有趣的事情:它们也明显比以前的 SIMD 指令集更强大。
我们有一个用于此目的的软件库,称为 simdutf 。该库会自动检测您的处理器并选择最合适的函数“内核”。它支持多种指令集(ARM NEON、SSE2、AVX2),但直到去年,它还不支持 AVX-512。
那么,使用 AVX-512 转换(或“转码”)字符串的速度有多快?这是一篇新论文的主题:使用 AVX-512 指令转码 unicode 字符(软件:实践和体验,即将出现)。一个参考点是流行的 ICU 库,几乎普遍用于此任务。它已经成熟并且优化得很好。
对于简单情况(例如英语),优化转码性能相当容易,但对于阿拉伯语等语言则更具挑战性……最困难的情况可能是表情符号流。下图显示了我们的性能(以每秒 GB 的输入量为单位),与我们的快速 AVX2 内核和困难情况下的 ICU 进行比较:图 A 用于 UTF-8 到 UTF-16 转码,图 B 用于 UTF-16 到 UTF-8 转码。在这些实验中,我们使用 Ice Lake 处理器和 LLVM 的 Clang 14 C++ 编译器。
在最新的 Intel 和 AMD 处理器上使用 AVX-512,从 UTF-8 转码时,我们在中文和表情符号输入上的速度超过 4 GB/s,在阿拉伯文本上几乎达到 8 GB/s。从 UTF-16 转码时,中文和表情符号文本的速度超过了 5 GB/s,阿拉伯语文本的速度突破了 20 GB/s 的障碍。
我还喜欢以“每秒十亿字符”为单位报告速度:每秒处理数十亿个字符。每秒千兆字节不太令人印象深刻,因为字符可以跨越多个字符,但是每秒千兆字符,我们可以直接将 UTF-8 到 UTF-16 转码与 UTF-16 到 UTF-8 转码进行比较。我们发现从 UTF-16 转码比从 UTF-8 转码要容易得多,因为它是一种更简单的格式。与 ICU 相比的优势取决于数据源,但我们的 simdutf 库可以快几倍,如下表所示。
UTF-8 到 UTF-16:
重症监护室 | AVX-512 | |
---|---|---|
阿拉伯 | 0.80 | 4.3 |
中国人 | 0.50 | 1.8 |
表情符号 | 0.22 | 1.0 |
希伯来语 | 0.80 | 4.3 |
印地语 | 0.43 | 1.7 |
日本人 | 0.51 | 1.7 |
韩国人 | 0.62 | 1.8 |
拉丁 | 1.5 | 20. |
俄语 | 0.46 | 4.2 |
UTF-16 到 UTF-8:
重症监护室 | AVX-512 | |
---|---|---|
阿拉伯 | 0.67 | 11. |
中国人 | 0.36 | 3.9 |
表情符号 | 0.27 | 1.6 |
希伯来语 | 0.68 | 11. |
印地语 | 0.21 | 3.8 |
日本人 | 0.37 | 3.8 |
韩国人 | 0.37 | 3.8 |
拉丁 | 0.91 | 20. |
俄语 | 0.23 | 11. |
支持 AVX-512 的旧版英特尔处理器由于各种形式的“频率限制”而引发了严重的担忧:每当您使用这些指令时,它们都会触发频率降低。因此,我们不在这些较旧的处理器上使用 AVX-512 指令,而是转而使用 AVX 指令。由于 AVX-512 指令,AMD Zen 4 或最新的英特尔处理器上没有频率限制。
我们的函数作为simdutf 库的一部分已在生产系统中使用了近一年。该库包含大量测试和基准测试。它是 Node.js、Bun、Oracle graaljs 等多个重要项目的一部分,并被 Couchbase 和其他项目使用。 simdutf 库是社区共同努力的成果,有多个重要贡献者(例如,Wojciech Muła、Yagiz Nizipli 等)。
我们目前正在向库添加 Latin 1 支持。未来,我希望我们可以为新一代 ARM 处理器添加 SVE/SVE2 支持。
致谢:新 AVX-512 功能的算法设计应归功于始终才华横溢的 Robert Clausecker。
原文: https://lemire.me/blog/2023/09/13/transcoding-unicode-strings-at-crazy-speeds-with-avx-512/