【问题标题】:why is strchr twice as fast as my simd code为什么 strchr 比我的 simd 代码快两倍
【发布时间】:2023-03-20 04:44:01
【问题描述】:

我正在学习 SIMD,我很想知道是否有可能在寻找角色方面击败 strchr。似乎 strchr 使用相同的内在函数,但我假设它检查空值,而我知道字符在数组中并计划避免空值检查。

我的代码是:

size_t N = 1e9;
bool found = false; //Not really used ...
size_t char_index1 = 0;
size_t char_index2 = 0;
char * str = malloc(N);
memset(str,'a',N);

__m256i char_match;
__m256i str_simd;
__m256i result;
__m256i* pSrc1;

int simd_mask;

str[(size_t)5e8] = 'b';


    char_match = _mm256_set1_epi8('b');
    result = _mm256_set1_epi32(0);

    simd_mask = 0;

    pSrc1 = (__m256i *)str;

    while (1){
        str_simd  = _mm256_lddqu_si256(pSrc1);
        result = _mm256_cmpeq_epi8(str_simd, char_match);
        simd_mask = _mm256_movemask_epi8(result);   
        if (simd_mask != 0){
            break;
        }
        pSrc1++;
    }

完整(尚未完成的代码)位于: https://gist.github.com/JimHokanson/433e185ba53b41e49ce3ac804568ac1e

strchr 是这段代码的两倍(使用 gcc 和 xcode)。我希望了解原因。

更新:编译使用:gcc -std=c11 -mavx2 -mlzcnt

【问题讨论】:

  • 你编译优化了吗,比如-O3?
  • 在大多数系统上,可以获得标准函数的源代码,例如strchr,或者至少您可以随时检查生成的机器代码。我建议您研究源代码(或机器代码)以了解它的作用。我的猜测是,在 40 年左右的时间里,该功能已经存在,并且已经进行了相当多的调整和优化。
  • @Someprogrammerdude 我不确定如何研究机器代码。重要的是,如果您做出参考代码没有做出的简化假设,通常可以击败经过高度优化的代码。
  • This is glibc's strchr-avx2.S。是的,它必须做大约 2 倍的检查 nul 和字符的工作。但请注意它们是如何展开 4 个向量和 OR 比较结果的,以节省 vpmovmskb / 分支吞吐量。这是memchr-avx2.S,他们不检查nul。相当不错的 asm,未对齐的启动和对齐的内循环。

标签: c simd


【解决方案1】:

我没有在编译器中设置优化标志。设置 -O3 导致 SIMD 代码只占用 strchr 时间的 75%。

更新:我还应该澄清这不是代码的最终工作版本。仍然需要进行额外的检查以及优化调用的可能方法(我认为)。至少在这一点上,虽然代码在 strchr 的范围内。正如问题 cmets 所指出的那样,这个版本可以读取过去的页面和错误。最后,这主要是一个 SIMD 学习机会(对我自己而言),memchr 可能是你最好的选择(尽管我怀疑如果你有一个哨兵缓冲区,你可能会稍微击败 memchr)。

【讨论】:

    猜你喜欢
    • 2011-08-22
    • 2018-08-12
    • 2015-11-02
    • 2011-05-28
    • 2017-02-03
    • 2017-05-12
    • 2014-05-29
    • 2017-08-15
    • 1970-01-01
    相关资源
    最近更新 更多