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

2023-12-08

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. What is reason '1105'?

使用 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 and b是 16 字节对齐的,那么你可以使用_mm_load_ps而不是_mm_loadu_ps这可能有助于提高性能,特别是在较旧的(Nehalem 之前)CPU 上。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 SSE2 对距离计算进行矢量化 的相关文章

随机推荐