SSE比FPU慢?

时间:2012-01-13 07:51:17

标签: c++ optimization sse vectorization simd

我有一大段代码,其中一部分包含这段代码:

result = (nx * m_Lx + ny * m_Ly + m_Lz) / sqrt(nx * nx + ny * ny + 1);

我已按照以下方式进行了矢量化(一切都已经是float):

__m128 r = _mm_mul_ps(_mm_set_ps(ny, nx, ny, nx),
                      _mm_set_ps(ny, nx, m_Ly, m_Lx));
__declspec(align(16)) int asInt[4] = {
    _mm_extract_ps(r,0), _mm_extract_ps(r,1),
    _mm_extract_ps(r,2), _mm_extract_ps(r,3)
};
float (&res)[4] = reinterpret_cast<float (&)[4]>(asInt);
result = (res[0] + res[1] + m_Lz) / sqrt(res[2] + res[3] + 1);

结果是正确的;但是,我的基准测试显示矢量化版本较慢

  • 非矢量化版本需要3750毫秒
  • 矢量化版本需要4050毫秒
  • 直接将result设置为0(并完全删除此部分代码)会将整个过程缩短为2500毫秒

鉴于矢量化版本仅包含一个 SSE乘法集(而不是四个单独的FPU乘法),为什么它会变慢? FPU确实比SSE快,或者这里有混淆变量吗?

(我在移动Core i5上。)

3 个答案:

答案 0 :(得分:16)

您花费大量时间将标量值移入/移出SSE寄存器_mm_set_ps_mm_extract_ps - 这会产生大量指令,其执行时间远远超过任何益处使用_mm_mul_ps。查看生成的程序集输出,以查看除单MULPS指令之外还生成了多少代码。

要正确地向量化,您需要使用128位SSE加载和存储(_mm_load_ps / _mm_store_ps),然后使用SSE shuffle指令在需要的寄存器内移动元素。

还有一点需要注意 - 现代CPU,如Core i5,Core i7,有两个标量FPU,每个时钟可以发出2个浮点乘法。因此,SSE对单精度浮点的潜在好处最多只有2倍。如果您有过多的“内务”说明,很容易失去大部分/全部这两项福利,就像这里的情况一样。

答案 1 :(得分:3)

有几个问题:

  1. 在这样的操作中使用SSE指令不会带来太多好处,因为SSE指令应该在并行操作上更好(即,同时乘以几个值)。你所做的是滥用SSE
  2. 不设置值,使用指向数组中第1个值的指针,但是你的值不在数组中
  3. 不要将值提取并复制到数组中。这也是对SSE的滥用。结果应该是在一个数组中。

答案 2 :(得分:0)

我的考虑是处理器有时间在加载下一个值时使用FPU时计算第一个乘法。 SSE必须首先加载所有值。