Skip to content

搞英语 → 看世界

翻译英文优质信息和名人推特

Menu
  • 首页
  • 作者列表
  • 独立博客
  • 专业媒体
  • 名人推特
  • 邮件列表
  • 关于本站
Menu

使用 AVX-512 快速解析整数

Posted on 2023-09-23

肖像2018facebook.jpg

如果我给程序员一个字符串,例如“9223372036854775808” ,并要求他们将其转换为整数,他们可能会在 C++ 中执行以下操作:

 std ::字符串s = . 。 。 。  
   
uint64_t 值;  
   
自动[ ptr , ec ] =  
   
std :: from_chars ( s . data ( ) , s . data ( ) + s . size ( ) , val ) ;  
   
if ( ec ! = std :: errc ( ) ) { } // 我有一个错误!  
   
// val 保存值  
   
  
   

它非常快:您可以使用大约 128 条指令以每个整数大约 40 个周期来解析随机 32 位整数序列。

你能做得更好吗?

最近的英特尔处理器有新的指令 AVX-512,它可以一次处理多个字节并进行屏蔽,以便您可以仅选择一系列数据。

我假设您知道数字序列的开头和结尾。以下带有 AVX-512 内在函数的代码执行以下操作:

  1. 计算以字节为单位的跨度 (digit_count),
  2. 如果我们有超过 20 个字节,我们就知道该整数太大,无法容纳 64 位整数,
  3. 我们计算一个“掩码”:一个 32 位值,只有最低有效的 digital_count 位设置为 1,
  4. 我们将 ASCII 或 UTF-8 字符串加载到 256 位寄存器中,
  5. 我们减去字符值“0”以获得 0 到 9 之间的值(数字值),
  6. 我们检查某个值是否超过 9,在这种情况下我们有一个非数字字符。
 size_t数字计数= size_t (结束-开始) ;  
   
// if (digit_count > 20) { 错误 ....}  
   
const simd8x32 ASCII_ZERO = _mm256_set1_epi8 ( '0' ) ;  
   
const simd8x32 九= _mm256_set1_epi8 ( 9 ) ;  
   
uint32_t 掩码= uint32_t ( 0xFFFFFFFF ) < < (开始-结束+ 32 ) ;  
   
自动输入= _mm256_maskz_loadu_epi8 (掩码,结束-32 ) ;  
   
自动base10_8bit = _mm256_maskz_sub_epi8 (掩码, in , ASCII_ZERO ) ;  
   
自动非数字= _mm256_mask_cmpgt_epu8_mask (掩码, base10_8bit ,九) ;  
   
if (非数字) {  
   
// 有一个非数字  
   
}  
   

这是使用 AVX-512 功能的关键步骤。之后,对于熟悉传统 x64 处理器上的高级 Intel 内在函数的人来说,我们可以使用“老式”处理……大多数情况下,我们只需乘以 10、乘以 100、乘以 100000 即可创建四个 32 位值:第一个对应于最低有效的 8 个 ASCII 字节,第二个到下一个最高有效的 8 个 ASCII 字节,以及最多 4 个最高有效字节。当数字为 8 位或更少时,只有其中一个单词相关;当数字为 16 位或更少时,前两个单词有意义。我们总是浪费一个由零组成的 32 位值。代码可能如下所示:

自动DIGIT_VALUE_BASE10_8BIT =  
   
_mm256_set_epi8 ( 1 , 10 , 1 , 10 , 1 , 10 , 1 , 10 ,  
   
1 , 10 , 1 , 10 , 1 , 10 , 1 , 10 ,  
   
1 , 10 , 1 , 10 , 1 , 10 , 1 , 10 ,  
   
1 , 10 , 1 , 10 , 1 , 10 , 1 , 10 ) ;  
   
自动DIGIT_VALUE_BASE10E2_8BIT = _mm_set_epi8 (  
   
1 , 100 , 1 , 100 , 1 , 100 , 1 , 100 , 1 , 100 , 1 , 100 , 1 , 100 , 1 , 100 ) ;  
   
自动DIGIT_VALUE_BASE10E4_16BIT =  
   
_mm_set_epi16 ( 1 , 10000 , 1 , 10000 , 1 , 10000 , 1 , 10000 ) ;  
   
自动基10e2_16位=  
   
_mm256_maddubs_epi16 ( base10_8bit , DIGIT_VALUE_BASE10_8BIT ) ;  
   
自动base10e2_8bit = _mm256_cvtepi16_epi8 ( base10e2_16bit ) ;  
   
自动基10e4_16位=  
   
_mm_maddubs_epi16 ( base10e2_8bit , DIGIT_VALUE_BASE10E2_8BIT ) ;  
   
自动基10e8_32位=  
   
_mm_madd_epi16 ( base10e4_16bit , DIGIT_VALUE_BASE10E4_16BIT ) ;  
   
  
   

我用C++实现了这个函数,并使用GCC12编译它。我在 Ice Lake 服务器上运行基准测试。我使用随机 32 位整数进行测试。 AVX-512 的速度是标准方法的两倍多。

AVX-512 1.8GB/秒 57 指令/数量 17 周期/次数
std::from_chars 0.8GB/秒 128条指令/数量 39 周期/次数

目前的比较并不完全公平,因为 AVX-512 函数假设它知道数字序列的开头和结尾。

您可以通过使用内联函数来提高性能,使其达到 2.3 GB/s,性能提升 30%。但是,假设您正在循环内按顺序解析数字。

我的原始代码将返回奇特的 std::Optional 值,但 GCC 受到负面影响,因此我将函数签名更改为更常规。甚至,在我的测试中,与 GCC 相比,LLVM/clang 稍微快一些。

信用:原始代码和问题是 John Keiser 向我建议的。我的代码很大程度上是他的代码的衍生。

原文: https://lemire.me/blog/2023/09/22/parsing-integers-quickly-with-avx-512/

本站文章系自动翻译,站长会周期检查,如果有不当内容,请点此留言,非常感谢。
  • Abhinav
  • Abigail Pain
  • Adam Fortuna
  • Alberto Gallego
  • Alex Wlchan
  • Answer.AI
  • Arne Bahlo
  • Ben Carlson
  • Ben Kuhn
  • Bert Hubert
  • Bits about Money
  • Brian Krebs
  • ByteByteGo
  • Chip Huyen
  • Chips and Cheese
  • Christopher Butler
  • Colin Percival
  • Cool Infographics
  • Dan Sinker
  • David Walsh
  • Dmitry Dolzhenko
  • Dustin Curtis
  • Elad Gil
  • Ellie Huxtable
  • Ethan Marcotte
  • Exponential View
  • FAIL Blog
  • Founder Weekly
  • Geoffrey Huntley
  • Geoffrey Litt
  • Greg Mankiw
  • Henrique Dias
  • Hypercritical
  • IEEE Spectrum
  • Investment Talk
  • Jaz
  • Jeff Geerling
  • Jonas Hietala
  • Josh Comeau
  • Lenny Rachitsky
  • Liz Danzico
  • Lou Plummer
  • Luke Wroblewski
  • Matt Baer
  • Matt Stoller
  • Matthias Endler
  • Mert Bulan
  • Mostly metrics
  • News Letter
  • NextDraft
  • Non_Interactive
  • Not Boring
  • One Useful Thing
  • Phil Eaton
  • Product Market Fit
  • Readwise
  • ReedyBear
  • Robert Heaton
  • Ruben Schade
  • Sage Economics
  • Sam Altman
  • Sam Rose
  • selfh.st
  • Shtetl-Optimized
  • Simon schreibt
  • Slashdot
  • Small Good Things
  • Taylor Troesh
  • Telegram Blog
  • The Macro Compass
  • The Pomp Letter
  • thesephist
  • Thinking Deep & Wide
  • Tim Kellogg
  • Understanding AI
  • 英文媒体
  • 英文推特
  • 英文独立博客
©2025 搞英语 → 看世界 | Design: Newspaperly WordPress Theme