2010-12-09 71 views
-1

以下循环执行数百次。
elma and elmc are both unsigned long (64-bit) arrays, so is res1 and res2.SIMD代码和标量代码

unsigned long simdstore[2]; 
__m128i *p, simda, simdb, simdc; 
p = (__m128i *) simdstore; 

for (i = 0; i < _polylen; i++) 
{ 

    u1 = (elma[i] >> l) & 15; 
    u2 = (elmc[i] >> l) & 15; 
    for (k = 0; k < 20; k++) 
    {  

    1. //res1[i + k] ^= _mulpre1[u1][k]; 
    2. //res2[i + k] ^= _mulpre2[u2][k];    
    3.  _mm_prefetch ((const void *) &_mulpre2[u2][k], _MM_HINT_T0); 
    4.  _mm_prefetch ((const void *) &_mulpre1[u1][k], _MM_HINT_T0); 
    5.  simda = _mm_set_epi64x (_mulpre2[u2][k], _mulpre1[u1][k]); 
    6.  _mm_prefetch ((const void *) &res2[i + k], _MM_HINT_T0); 
    7.  _mm_prefetch ((const void *) &res1[i + k], _MM_HINT_T0); 
    8.  simdb = _mm_set_epi64x (res2[i + k], res1[i + k]); 
    9.  simdc = _mm_xor_si128 (simda, simdb); 
    10.  _mm_store_si128 (p, simdc); 
    11.  res1[i + k] = simdstore[0]; 
    12.  res2[i + k] = simdstore[1];      
    }  
} 

在for循环中,标量版本的代码(注释)运行速度比simd代码快两倍。以上提到的cachegrind输出(指令读取)如下。

第1行:668460000 2 2
第2行:668460000 1 1
第3行:89985000 1 1
第4行:89985000 1 1
第5行:617040000 2 2
第6行:44992500 0 0
第7行:44992500 0 0
第8行:539910000 1 1
第9行:128550000 0 0
第10行:。 。 。
第11行:205680000 0 0
第12行:205680000 0 0

从上面的图,它显示了注释(标量的代码)需要更少显著比SIMD代码指令数目。

这段代码如何能更快?

+0

这是你自己问题的重复。回到那里,理解为什么这个答案(而不是你标记为正确的答案)解决了这个问题:http://stackoverflow.com/questions/4394930/simd-code-runs-slower-than-scalar-code/4395337# 4395337 – 2010-12-09 12:27:29

回答

3

取出_mm_prefetch内在因素 - 他们在这种情况下什么都没有实现,甚至可能会伤害到表现。如果(a)您有空闲带宽,并且(b)您可以在数据实际需要时提前数百个时钟周期发出预取提示,则预取仅有益处。我认为你的情况既不是(a)也不是(b)。

1

你peformance问题是这样的:

_mm_set_epi64x(_mulpre2 [U2] [k]的,_mulpre1 [U1] [K]);

mm_set(a,b,c,d)类内在函数非常缓慢。 只有单参数集内在函数(aka广播)速度很快。

我看着他们在汇编代码中做了什么。

他们基本上在堆栈上创建一个数组,使用正常的内存移动(mov DWORD),将您的两个整数从它们当前驻留的多维数组移动到堆栈数组。然后从堆栈数组中使用XMM内存移动(mov XMWORD)。

标量版本直接从内存到寄存器。更快!

您看到开销来自于XMM寄存器一次只能与128位通信这一事实,因此您的程序在加载它们之前先在另一个内存区域中排序128位。

如果有办法将64位值直接移入或移出正常寄存器到XMM寄存器,我仍在寻找它。

为了从使用SSE/XMM寄存器获得速度提升,您的数据可能需要在内存中保持有序。如果您可以在无序加载的情况下执行多个XMM操作,则将无序数据装载到XMM寄存器中是非常值得的。在这里你做一个单独的XOR操作。