2011-05-26 67 views
6

我需要比较两个缓冲区chunk-wise为相等。我不需要关于两个缓冲区的关系的信息,就好像每两个区块相等或不相等。我的英特尔机最多支持SSE4.2比较缓冲区尽可能快

天真的做法是:

const size_t CHUNK_SIZE = 16; //128bit for SSE2 integer registers 
const int ARRAY_SIZE = 200000000; 

char* array_1 = (char*)_aligned_malloc(ARRAY_SIZE, 16); 
char* array_2 = (char*)_aligned_malloc(ARRAY_SIZE, 16); 

for (size_t i = 0; i < ARRAY_SIZE;) 
{ 
    volatile bool result = memcmp(array_1+i, array_2+i, CHUNK_SIZE); 
    i += CHUNK_SIZE; 
} 

与使用SSE有史以来我第一次尝试:

union U 
{ 
    __m128i m; 
    volatile int i[4]; 
} res; 

for (size_t i = 0; i < ARRAY_SIZE;) 
{ 
    __m128i* pa1 = (__m128i*)(array_1+i); 
    __m128i* pa2 = (__m128i*)(array_2+i); 
    res.m = _mm_cmpeq_epi32(*pa1, *pa2); 
    volatile bool result = ((res.i[0]==0) || (res.i[1]==0) || (res.i[2]==0) || (res.i[3]==0)); 
    i += CHUNK_SIZE; 
} 

速度的增益约为33%。我能做得更好吗?

+0

你在这个特定的代码中有瓶颈吗? – 2011-05-26 09:54:26

+0

是的,这是我程序中的主要热点。 – beutelfuchs 2011-05-26 10:05:21

+0

除非你的'memcmpy'实现被破坏,否则你将很难击败它 - 它应该已经被SIMD优化了。 – 2011-05-26 10:16:37

回答

4

你真的不应该使用标码和工会测试所有的个体向量元素是 - 做这样的事情,而不是:

for (size_t i = 0; i < ARRAY_SIZE; i += CHUNK_SIZE) 
{ 
    const __m128i a1 = _mm_load_si128(array_1 + i); 
    const __m128i a2 = _mm_load_si128(array_2 + i); 
    const __m128i vcmp = _mm_cmpeq_epi32(a1, a2); 
    const int vmask = _mm_movemask_epi8(vcmp); 
    const bool result = (vmask == 0xffff); 
    // you probably want to break here if you get a mismatch ??? 
} 
+0

谢谢,如果我正在寻找的信息,这正是那种 – beutelfuchs 2011-05-26 10:32:50

+0

但不幸的是,增益与使用工会为这个特殊情况。 – beutelfuchs 2011-05-26 10:40:35

+0

这可能是因为你的瓶颈是内存带宽,所以加快比较操作可能是徒劳的。 – 2011-05-26 13:25:07

2

既然你可以使用SSE 4.1,还有另外一种选择,可能是速度快:

for (size_t i = 0; i < ARRAY_SIZE; i += CHUNK_SIZE;) 
{ 
    __m128i* pa1 = (__m128i*)(array_1+i); 
    __m128i* pa2 = (__m128i*)(array_2+i); 
    __m128i temp = _mm_xor_si128(*pa1, *pa2); 
    bool result = (bool)_mm_testz_si128(temp, temp); 
} 

_mm_testz_si128(a, b)回报0如果a & b != 0和返回1如果a & b == 0。优点是您可以在新的AVX指令中使用此版本,其中块大小为32字节。

+0

谢谢。不幸的是VS2005不支持V2版本以上的SSE,就像我在那一刻学到的那样。也许我可以找出操作码并使用内联asm代替。 – beutelfuchs 2011-05-27 07:44:25

+0

我尝试使用支持这个instrincts的英特尔编译器。性能可与此处介绍的其他两种方法相媲美。 – beutelfuchs 2011-05-27 08:32:24

+0

感谢您尝试编码。正如Paul R.所指出的那样,内存带宽很可能是瓶颈,这个代码可能会快1到2个周期。 – 2011-05-27 21:49:47