如何使用SSE2对距离计算进行矢量化

时间:2013-06-08 14:25:28

标签: c++ visual-c++ optimization vectorization sse2

A和B是向量或长度N,其中N可以在20到200的范围内。 我想计算这些向量之间距离的平方, 即d ^ 2 = || A-B || ^ 2。

到目前为止,我有:

float* a = ...;
float* b = ...;
float d2 = 0;

for(int k = 0; k < N; ++k)
{
    float d = a[k] - b[k];
    d2 += d * d;
}

这似乎工作得很好,除了我已经分析了我的代码,这是瓶颈(超过50%的时间花在这上面)。 我在Win 7上使用Visual Studio 2012,使用这些优化选项:/O2 /Oi /Ot /Oy-。 我的理解是VS2012应该自动矢量化该循环(使用SSE2)。 但是,如果我在代码中插入#pragma loop(no_vector)我没有明显减慢速度,所以我猜这个循环没有被矢量化。编译器通过以下消息确认:

  info C5002: loop not vectorized due to reason '1105'

我的问题是:

  1. 是否可以修复此代码,以便VS2012可以对其进行矢量化?
  2. 如果没有,尝试自己对代码进行矢量化是否有意义?
  3. 您能否推荐一个网站供我学习SSE2编码?
  4. 是否有一些N的值低于哪个矢量化会适得其反?
  5. 什么是reason '1105'

2 个答案:

答案 0 :(得分:6)

使用SSE内在函数实现这一点非常简单:

#include "pmmintrin.h"

__m128 vd2 = _mm_set1_ps(0.0f);
float d2 = 0.0f;
int k;

// process 4 elements per iteration
for (k = 0; k < N - 3; k += 4)
{
    __m128 va = _mm_loadu_ps(&a[k]);
    __m128 vb = _mm_loadu_ps(&b[k]);
    __m128 vd = _mm_sub_ps(va, vb);
    vd = _mm_mul_ps(vd, vd);
    vd2 = _mm_add_ps(vd2, vd);
}

// horizontal sum of 4 partial dot products
vd2 = _mm_hadd_ps(vd2, vd2);
vd2 = _mm_hadd_ps(vd2, vd2);
_mm_store_ss(&d2, vd2);

// clean up any remaining elements
for ( ; k < N; ++k)
{
    float d = a[k] - b[k];
    d2 += d * d;
}

请注意,如果您可以保证ab对齐16字节,那么您可以使用_mm_load_ps而不是_mm_loadu_ps这可能有助于提升效果,尤其是在较旧的情况下( pre Nehalem)CPU。

另请注意,对于诸如此类的循环,其中相对于负载数量的算术指令非常少,那么性能可能会受到内存带宽的限制,并且实际上可能无法实现矢量化的预期加速。

答案 1 :(得分:4)

MSDN documentation开始,1105错误代码意味着编译器无法弄清楚如何将代码减少为矢量化指令。对于浮点运算,表示需要指定/ fp:fast选项以启用任何浮点减少。