是否有 SIMD 指令来加快校验和计算?

Posted

技术标签:

【中文标题】是否有 SIMD 指令来加快校验和计算?【英文标题】:Are there SIMD instructions to speed up checksum calculations? 【发布时间】:2011-07-12 22:22:02 【问题描述】:

我将不得不编写一个非常基本的校验和函数,例如:

char sum(const char * data, const int len)

    char sum(0);
    for (const char * end=data+len ; data<end ; ++data)
        sum += *data;
    return sum;

这很简单。现在,我应该如何优化它? 首先,我可能应该使用一些带有 lambda 或类似的 std::for_each :

char sum2(const char * data, const int len)

    char sum(0);
    std::for_each(data, data+len, [&sum](char b)sum+=b;);
    return sum;

接下来,我可以使用多个线程/内核来汇总块,然后将结果相加。我不会把它写下来,而且我担心创建线程(或者无论如何从池中获取它们),然后切割数组,然后调度所有东西等的成本不会很好,因为我主要会计算小数组的校验和,大部分是 10-100 字节,很少达到 1000。

但我真正想要的是更低级别的东西,一些 SIMD 东西,它们可以对 128b 寄存器上的字节求和,或者可能在两个寄存器之间独立地求和字节而不携带进位,或两者兼而有之。

那里有这样的东西吗?

注意:这是实际的过早优化,但它很有趣,那么到底是什么?

编辑:我仍然需要一种方法来总结 SSE 寄存器中的所有字节,这比

char ptr[16];
_mm_storeu_si128((__m128i*)ptr, sum);
checksum += ptr[0] + ptr[1] + ptr[2]  + ptr[3]  + ptr[4]  + ptr[5]  + ptr[6]  + ptr[7]
          + ptr[8] + ptr[9] + ptr[10] + ptr[11] + ptr[12] + ptr[13] + ptr[14] + ptr[15];

【问题讨论】:

我没有实际证据证明这一点,但我怀疑std::for_each 版本会比手动方法慢... 我假设您希望英特尔 opps 在这里? @Mike 视情况而定,小数据包实际上速度较慢,但​​大数据包速度更快。我用 100b 和 900b 测试过,我不知道我的设置的限制在哪里。我想创建对象的成本与此有关。不出所料,SSE 在这两种规模上都击败了两者。 @Gabriel:这不是过早的优化。例如,在我的项目中,这是一个最慢的地方。起初我将它展开 4,这给了很多提升,但它仍然是最慢的。所以我不得不使用 SSE 内在函数重写它。这很有趣! :) 【参考方案1】:

是的,MMX指令集中有这样的指令,叫做“Packed ADD”:

_mm_add_pi8 在 Visual C++ 中 __builtin_ia32_paddb 在 gcc 中

在SSE2指令集中:

_mm_add_epi8 在 Visual C++ 中 __builtin_ia32_paddb128 在 gcc 中

编辑:添加部分和的更快方法:

__m128i sums;

sums = _mm_add_epi8(sums, _mm_srli_si128(sums, 1));
sums = _mm_add_epi8(sums, _mm_srli_si128(sums, 2));
sums = _mm_add_epi8(sums, _mm_srli_si128(sums, 4));
sums = _mm_add_epi8(sums, _mm_srli_si128(sums, 8));
checksum += _mm_cvtsi128_si32(sums);

【讨论】:

现在,在给定上述循环的情况下,任何编译器都足以生成正确的代码吗? 我无法想象大多数编译器会费心为第一个循环发出 SSE。尝试从任意指针加载很烦人——编译器不知道目标是否对齐,是否可以加载 SSE 大小的块,等等。 这里不需要使用编译器名称。 GCC 以及 Visual C++ 支持标准的 MMX/SSE 扩展头和函数。我不是 MMX/SSE 用户,但请检查例如 &lt;mmintrin.h&gt; 的原型。【参考方案2】:

看看 _mm_add_ps。同时添加 128 位连续块。您需要对数组进行零填充或处理最后几个非 SIMD 样式。

【讨论】:

以上是关于是否有 SIMD 指令来加快校验和计算?的主要内容,如果未能解决你的问题,请参考以下文章

Neon 在 Intrinsics 中的校验和代码实现

确定 MIPS 中数字的位表示的奇偶校验

向量与 SIMD 的点积

是否有 SIMD 指令来实现批量数组内存索引映射?

Hive表数据质量校验的设计与开发

是否可以使用 SIMD 指令进行 3x3 矩阵求逆?