我是SSE编程新手,所以我希望有人能帮助我。我最近使用GCC SSE内在函数实现了一个函数来计算32位整数数组的总和。下面给出了我的实现代码。大型阵列尺寸的SSE性能下降
int ssum(const int *d, unsigned int len)
{
static const unsigned int BLOCKSIZE=4;
unsigned int i,remainder;
int output;
__m128i xmm0, accumulator;
__m128i* src;
remainder = len%BLOCKSIZE;
src = (__m128i*)d;
accumulator = _mm_loadu_si128(src);
output = 0;
for(i=BLOCKSIZE;i<len-remainder;i+=BLOCKSIZE){
xmm0 = _mm_loadu_si128(++src);
accumulator = _mm_add_epi32(accumulator,xmm0);
}
accumulator = _mm_add_epi32(accumulator, _mm_srli_si128(accumulator, 8));
accumulator = _mm_add_epi32(accumulator, _mm_srli_si128(accumulator, 4));
output = _mm_cvtsi128_si32(accumulator);
for(i=len-remainder;i<len;i++){
output += d[i];
}
return output;
}
正如你可以看到,这是一个相当简单的实现方式,其中我使用扩展XMM寄存器在一个时间求和阵列4,然后通过加入余下的元件清理在末端。
然后,我将该SIMD实现的性能与普通的for循环进行了比较。这个实验的结果可以在这里找到:
正如你可以看到,相较于一个for循环,这个实现确实表现出约〜60%的加速为输入尺寸(指的长度阵列)高达约5M元素。然而,对于输入大小的较大值,与for循环有关的性能会急剧下降,并且只会产生大约20%的加速。
我无法解释这种戏剧性的下降。我或多或少地通过内存线性地步进,所以缓存未命中和页面错误的影响应该对于两种实现大致相同。我在这里错过了什么?有什么办法可以将这条曲线弄平吗?任何想法将不胜感激。
你使用的是什么CPU? –
首先,你是否检查gcc是否会自动化标量代码?其次,你可能会受限于内存带宽。 – EOF
正如@EOF所说,你在循环中几乎不做任何事(一个SIMD算术指令),所以当你有大的数组时,你很可能会限制内存带宽。 –