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'
我的问题是:
reason '1105'
?答案 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;
}
请注意,如果您可以保证a
和b
对齐16字节,那么您可以使用_mm_load_ps
而不是_mm_loadu_ps
这可能有助于提升效果,尤其是在较旧的情况下( pre Nehalem)CPU。
另请注意,对于诸如此类的循环,其中相对于负载数量的算术指令非常少,那么性能可能会受到内存带宽的限制,并且实际上可能无法实现矢量化的预期加速。
答案 1 :(得分:4)
从MSDN documentation开始,1105错误代码意味着编译器无法弄清楚如何将代码减少为矢量化指令。对于浮点运算,表示需要指定/ fp:fast选项以启用任何浮点减少。