물론 코드를 개선 할 수 있습니다. 이 SSE2를 사용하여 기능의 최적화의 예 :
const __m128i Z = _mm_setzero_si128();
const size_t A = sizeof(__m128i);
inline __m128i SquaredDifference(__m128i a, __m128i b)
{
const __m128i aLo = _mm_unpacklo_epi8(a, Z);
const __m128i bLo = _mm_unpacklo_epi8(b, Z);
const __m128i dLo = _mm_sub_epi16(aLo, bLo);
const __m128i aHi = _mm_unpackhi_epi8(a, Z);
const __m128i bHi = _mm_unpackhi_epi8(b, Z);
const __m128i dHi = _mm_sub_epi16(aHi, bHi);
return _mm_add_epi32(_mm_madd_epi16(dLo, dLo), _mm_madd_epi16(dHi, dHi));
}
inline __m128i HorizontalSum32(__m128i a)
{
return _mm_add_epi64(_mm_unpacklo_epi32(a, Z), _mm_unpackhi_epi32(a, Z));
}
inline uint64_t ExtractSum64(__m128i a)
{
uint64_t _a[2];
_mm_storeu_si128((__m128i*)_a, a);
return _a[0] + _a[1];
}
void SumOfSquaredDifference(
const uint8_t *a, size_t aStride, const uint8_t *b, size_t bStride,
size_t width, size_t height, uint64_t * sum)
{
assert(width%A == 0 && width < 0x10000);
__m128i fullSum = Z;
for(size_t row = 0; row < height; ++row)
{
__m128i rowSum = Z;
for(size_t col = 0; col < width; col += A)
{
const __m128i a_ = _mm_loadu_si128((__m128i*)(a + col));
const __m128i b_ = _mm_loadu_si128((__m128i*)(b + col));
rowSum = _mm_add_epi32(rowSum, SquaredDifference(a_, b_));
}
fullSum = _mm_add_epi64(fullSum, HorizontalSum32(rowSum));
a += aStride;
b += bStride;
}
*sum = ExtractSum64(fullSum);
}
이 예에서는 단순화 몇 가지 (이미지 너비가 16의 배수가 아닌 경우 작동하지 않습니다)입니다. 알고리즘의 전체 버전은 here입니다.
그리고
SSSE3 버전에서 몇 가지 마법 :
const __m128i K_1FF = _mm_set1_epi16(0x1FF);
inline __m128i SquaredDifference(__m128i a, __m128i b)
{
const __m128i lo = _mm_maddubs_epi16(_mm_unpacklo_epi8(a, b), K_1FF);
const __m128i hi = _mm_maddubs_epi16(_mm_unpackhi_epi8(a, b), K_1FF);
return _mm_add_epi32(_mm_madd_epi16(lo, lo), _mm_madd_epi16(hi, hi));
}
마법 설명 (_mm_maddubs_epi16 참조) GCC 코드를 벡터화를 장려 스위치가
K_1FF -> {-1, 1, -1, 1, ...};
_mm_unpacklo_epi8(a, b) -> {a0, b0, a1, b1, ...};
_mm_maddubs_epi16(_mm_unpacklo_epi8(a, b), K_1FF) -> {b0 - a0, b1 - a1, ...};
수동으로 최적화를 시작하기 전에 컴파일러가 아직 벡터화 된 코드를 생성하고 있지 않은지 확인해야합니다. 최적화 및 SIMD가 활성화되어 있는지 확인하고 생성 된 코드에서 SSE 지침을 확인하십시오. 그렇지 않으면 바보 같은 일에 시간을 낭비 할 수 있습니다. (BTW, 사용중인 CPU 하드웨어, OS 및 컴파일러를 지정하십시오.) –
외부 루프가 쓸모없는 것처럼 보입니다. 그게 실수 야? –
@ A.S.H : 이상하게 보입니다. 그러나 그는 각 행 반복에서'a','b' 포인터를 부딪 히고 있습니다. –