我需要比较两个缓冲块大小平等。 我不需要关于两个缓冲区的关系的信息,就是如果每两个区块相等或不相等。 我的英特尔机器支持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%。 我可以做得更好吗?
你真的不应该使用标量代码和联合来测试所有的单独的向量元素 – 做这样的事情,而不是:
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 ??? }
既然你可以使用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); }
如果a & b != 0
, _mm_testz_si128(a, b)
返回0
,如果a & b == 0
则返回1
。 优点是你可以在新的AVX指令中使用这个版本,其中块大小是32字节。