-1

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

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:668,460,000 2 2
行2:668,460,000 1 1 1
行3:89,985,000 1 1 1 1
行4:89,985,000 1 1 1 1
行5:617,040,000 2 2行2
行6:44,992,500 0 0 0 0 LINE 0
LINE 7:44,992,500 0 0
LINE LINE LINE 8:44,992,500 0
LINE : : 128,550,000 0 0
第 10 行: . . .
第 11 行:205,680,000 0 0
第 12 行:205,680,000 0 0

从上图中可以看出,注释(标量代码)所需的指令数量明显少于 simd 代码。

如何使这段代码更快?

4

2 回答 2

3

去掉_mm_prefetch内在函数——在这种情况下,它们一无所获,甚至可能会损害性能。只有在以下情况下,预取才有用:(a) 您有空闲带宽,并且 (b) 您可以在实际需要数据之前几百个时钟周期发出预取提示。我认为在您的情况下,(a)和(b)都不正确。

于 2010-12-15T14:37:18.387 回答
1

您的性能问题是这样的:

_mm_set_epi64x (_mulpre2[u2][k], _mulpre1[u1][k]);

mm_set(a,b,c,d) 类的内在函数非常慢。只有单个参数集内在函数(又名广播)是快速的。

我查看了它们在汇编代码中的作用。

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

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

您会看到开销来自这样一个事实,即 XMM 寄存器一次只能与 128 位通信,因此您的程序首先在另一个内存区域中对 128 位进行排序,然后再加载它们。

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

要通过使用 SSE/XMM 寄存器来提高速度,您的数据可能需要在内存中已经有序。只有在每次乱序加载都可以执行多个 XMM 操作时,才值得将乱序数据加载到 XMM 寄存器中。在这里你做一个 XOR 操作。

于 2011-02-04T14:00:36.913 回答