【问题标题】:How do I add all elements in an array using SSE2?如何使用 SSE2 添加数组中的所有元素?
【发布时间】:2012-09-22 17:43:35
【问题描述】:

假设我有一个非常简单的代码,例如:

double array[SIZE_OF_ARRAY];
double sum = 0.0;

for (int i = 0; i < SIZE_OF_ARRAY; ++i)
{
    sum += array[i];
}

我基本上想用 SSE2 做同样的操作。我该怎么做?

【问题讨论】:

  • 如果你真的必须使用双精度,那么它可能不值得打扰,因为现在大多数现代 x86 CPU 都有两个 FPU。如果您可以降低到单精度(即浮点数),那么它可能值得做。您需要提高多少性能?
  • 强烈推荐使用 Kahan 求和。此处问答中提出的解决方案容易出错。

标签: c x86 sse simd sse2


【解决方案1】:

这是一个非常简单的 SSE3 实现:

#include <emmintrin.h>

__m128d vsum = _mm_set1_pd(0.0);
for (int i = 0; i < n; i += 2)
{
    __m128d v = _mm_load_pd(&a[i]);
    vsum = _mm_add_pd(vsum, v);
}
vsum = _mm_hadd_pd(vsum, vsum);
double sum = _mm_cvtsd_f64(vsum0);

您可以展开循环以获得更好的性能,方法是使用多个累加器隐藏 FP 添加的延迟(如 @Mysticial 所建议的那样)。使用多个“和”向量展开 3 或 4 次,以达到负载和 FP-add 吞吐量(每个时钟周期一个或两个)的瓶颈,而不是 FP-add 延迟(每 3 或 4 个周期一个):

__m128d vsum0 = _mm_setzero_pd();
__m128d vsum1 = _mm_setzero_pd();
for (int i = 0; i < n; i += 4)
{
    __m128d v0 = _mm_load_pd(&a[i]);
    __m128d v1 = _mm_load_pd(&a[i + 2]);
    vsum0 = _mm_add_pd(vsum0, v0);
    vsum1 = _mm_add_pd(vsum1, v1);
}
vsum0 = _mm_add_pd(vsum0, vsum1);    // vertical ops down to one accumulator
vsum0 = _mm_hadd_pd(vsum0, vsum0);   // horizontal add of the single register
double sum = _mm_cvtsd_f64(vsum0);

请注意,数组 a 假定为 16 字节对齐,元素数量 n 假定为 2 的倍数(或 4,在展开循环的情况下)。

另请参阅Fastest way to do horizontal float vector sum on x86,了解在循环外进行水平求和的替代方法。 SSE3 支持并非完全普遍(尤其是 AMD CPU 比 Intel 更晚支持它)。

此外,_mm_hadd_pd 即使在支持它的 CPU 上通常也不是最快的方式,因此在现代 CPU 上,仅 SSE2 的版本不会更糟。不过,它在循环之外,并没有太大的区别。

【讨论】:

  • 我认为这可以从展开至少 3 次迭代中受益。 (3 个独立的vsum 变量)
  • 是的,可能。您可以让编译器展开它,或者手动完成更好的工作。性能可能会受到内存带宽的限制,除非它是一个相对较小的数据集恰好在缓存中,因此微优化可能不会产生太大的好处。
  • 我认为编译器不允许节点拆分,因为它破坏了关联性。也就是说,我还没有看到它在宽松的浮点下会做什么。但我从未见过编译器在优化 SSE 内在函数方面过于激进。
  • 是的,编译器循环展开可能只会生成多个加载和添加,而不会引入额外的临时变量,因此您可以获得一些好处(例如从双重加载问题),但不如智能手动展开那么多。我现在在答案中添加了 2x 展开版本。
  • _mm_hadd_pd 不是 SSE2 内在 btw,它是 SSE3。
猜你喜欢
  • 1970-01-01
  • 2016-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多