SSE

时间:2016-02-10 05:17:06

标签: c++ sse

我有以下循环,它取数组中每个条目的平方根:

#include <mmintrin.h>

float array[SIZE];
for (int i = 0; i < SIZE; i += 4)
{
    __m128 fourFloats, fourRoots;
    fourFloats = _mm_load_ps(&array[i]);
    fourRoots = _mm_sqrt_ps(fourFloats);
    float results[4];
    _mm_store_ps(results, fourRoots);
    // This is bottleneck
    array[i]   = results[0] > 63.0F ? 63.0F : floor(results[0]);
    array[i+1] = results[1] > 63.0F ? 63.0F : floor(results[1]);
    array[i+2] = results[2] > 63.0F ? 63.0F : floor(results[2]);
    array[i+3] = results[3] > 63.0F ? 63.0F : floor(results[3]);
    // This is slower
//  array[i] = (int) std::min(floor(results[0]), 63.0F);
}

根据我的探查器(Zoom),平方根不占用大量时间,但结果的四次裁剪中的每一次都占用​​了大约20%的时间,即使-O2优化也是如此上。有没有更有效的方法来实现循环?请注意_mm_store_ps()优化了gcc

我尝试了对平方根的优化表查找,因为97%的输入array值低于512,但这没有帮助。请注意,此例程占用整个应用程序总处理器时间的不到四分之一,这是一个不断运行的图像识别应用程序。

3 个答案:

答案 0 :(得分:2)

MAXPSMINPS

  

__ m128d _mm_max_ps(__ m128d a,__ m128d b);

     

对第一个源操作数和第二个源操作数中的压缩单精度浮点值执行SIMD比较,并将每对值的最大值返回到目标操作数。

  

__ m128d _mm_min_ps(__ m128d a,__ m128d b);

     

对第一个源操作数和第二个源操作数中的压缩单精度浮点值执行SIMD比较,并将每对值的最小值返回到目标操作数。

使用带有四个63.0f值的XMM寄存器作为第二个操作数。

答案 1 :(得分:2)

鉴于您可以使用非常现代的CPU,我从这开始:

float array[SIZE];
for(int i = 0; i < SIZE; i += 8)
{
    __m256 eightFloats, eightRoots;
    eightFloats = _mm256_load_ps(&array[i]);
    eightRoots = _mm256_sqrt_ps(eightFloats);
    float results[8];
    eightRoots = _mm256_floor_ps(eightRoots);
    _mm256_store_ps(results, eightRoots);
    ...
}

如果允许使用最高级的SIMD指令,甚至可以使用512个版本。

答案 2 :(得分:1)

总结这两个答案,这是我最终决定的完整要求的代码array[i] = std::min(floor(sqrt(array[i])), (float) 0x3f);

float array[SIZE];
const float clipValue = (float) 0x3f;
const float clipArray[8] = {clipValue, clipValue, clipValue, clipValue,
                            clipValue, clipValue, clipValue, clipValue};
__m256 eightClips = _mm256_load_ps(clipArray);
for(int i = 0; i < SIZE; i += 8)
{
    __m256 eightFloats = _mm256_load_ps(&array[i]);
    __m256 eightRoots  = _mm256_sqrt_ps(eightFloats);
    __m256 eightFloors = _mm256_floor_ps(eightRoots);
    __m256 eightMins   = _mm256_min_ps(eightFloors, eightClips);
    _mm256_store_ps(&array[i], eightMins);
}

我定位垂直应用中的特定硬件,因此可以使用与AVX兼容的处理器。