2013-02-25 2 views
4

가능한 한 빨리 메모리 블록 두 개를 XOR하고 싶습니다. 어떻게 SIMD를 사용하여 가속시킬 수 있습니까?SIMD를 사용하여 두 개의 메모리 블록 XOR을 가속화하려면 어떻게해야합니까?

내 원래의 코드는 다음과 같습니다 :

void region_xor_w64( unsigned char *r1,   /* Region 1 */ 
         unsigned char *r2,   /* Region 2 */ 
         int nbytes)  /* Number of bytes in region */ 
{ 
    uint64_t *l1; 
    uint64_t *l2; 
    uint64_t *ltop; 
    unsigned char *ctop; 

    ctop = r1 + nbytes; 
    ltop = (uint64_t *) ctop; 
    l1 = (uint64_t *) r1; 
    l2 = (uint64_t *) r2; 

    while (l1 < ltop) { 
     *l2 = ((*l1)^(*l2)); 
     l1++; 
     l2++; 
    } 
} 

은 나 자신을 하나 썼다, 그러나 약간의 속도가 증가.

void region_xor_sse( unsigned char* dst, 
         unsigned char* src, 
         int block_size){ 
    const __m128i* wrd_ptr = (__m128i*)src; 
    const __m128i* wrd_end = (__m128i*)(src+block_size); 
    __m128i* dst_ptr = (__m128i*)dst; 

    do{ 
    __m128i xmm1 = _mm_load_si128(wrd_ptr); 
    __m128i xmm2 = _mm_load_si128(dst_ptr); 

    xmm2 = _mm_xor_si128(xmm1, xmm2); 
    _mm_store_si128(dst_ptr, xmm2); 
    ++dst_ptr; 
    ++wrd_ptr; 
    }while(wrd_ptr < wrd_end); 
} 
+1

실행중인 플랫폼은 무엇입니까? 사용 가능한 SIMD 기능은 매우 플랫폼에 따라 다릅니다. –

+0

@JasonR SSE4.2를 지원하는 64 비트 Linux – foool

+1

루프를 풀어 볼 수 있습니다. 출력 값마다 많은 크 런치를 수행하지 않을 때 큰 성능 향상을 얻는 것은 어렵습니다. 또한 정렬 된로드/저장 명령어를 사용하려는 경우 버퍼 정렬에주의해야합니다. –

답변

7

더 중요한 질문은 수동으로 수행해야하는 이유입니다. 현명 할 수 있다고 생각하는 고대 컴파일러가 있습니까? SIMD 명령어를 수동으로 작성해야했던 좋은 옛날은 끝났습니다. 오늘날, 99 %의 경우 컴파일러가 당신을 위해 일을 할 것이며, 더 나은 일을 할 가능성이 있습니다. 또한 점점 더 확장 된 명령어 세트를 통해 새로운 아키텍처가 매번 나오고 있음을 잊지 마십시오. 자신에게 질문하십시오 - 각 플랫폼에 대한 구현의 N 개의 복사본을 유지 하시겠습니까? 유지 관리 가치가 있는지 지속적으로 구현을 테스트하고 싶습니까? 대부분의 대답은 아니오 일 것입니다.

가장 간단한 코드를 작성하면됩니다. 컴파일러가 나머지를 처리합니다. 예를 들어 다음과 같이 함수를 작성하는 방법을 알려 드리겠습니다.

void region_xor_w64(unsigned char *r1, unsigned char *r2, unsigned int len) 
{ 
    unsigned int i; 
    for (i = 0; i < len; ++i) 
     r2[i] = r1[i]^r2[i]; 
} 

조금 더 간단하지 않습니까? 정렬되지 않은 액세스를 지원

@Mysticial가 지적했듯이
4008a0:  f3 0f 6f 04 06   movdqu xmm0,XMMWORD PTR [rsi+rax*1] 
4008a5:  41 83 c0 01    add r8d,0x1 
4008a9:  f3 0f 6f 0c 07   movdqu xmm1,XMMWORD PTR [rdi+rax*1] 
4008ae:  66 0f ef c1    pxor xmm0,xmm1 
4008b2:  f3 0f 7f 04 06   movdqu XMMWORD PTR [rsi+rax*1],xmm0 
4008b7:  48 83 c0 10    add rax,0x10 
4008bb:  45 39 c1    cmp r9d,r8d 
4008be:  77 e0     ja  4008a0 <region_xor_w64+0x40> 

, 위의 코드에서 사용하는 명령 : 그리고, 컴파일러는 MOVDQUPXOR를 사용하여 128 비트 XOR을 수행하는 코드를 생성하는 것 같아요 중요한 경로는 다음과 같습니다 . 그것들은 더 느립니다. 그러나 프로그래머가 정렬 된 액세스를 올바르게 가정 할 수 있다면 컴파일러가이를 알 수있게 할 수 있습니다. 예를 들어 :

void region_xor_w64(unsigned char * restrict r1, 
        unsigned char * restrict r2, 
        unsigned int len) 
{ 
    unsigned char * restrict p1 = __builtin_assume_aligned(r1, 16); 
    unsigned char * restrict p2 = __builtin_assume_aligned(r2, 16); 

    unsigned int i; 
    for (i = 0; i < len; ++i) 
     p2[i] = p1[i]^p2[i]; 
} 

이 컴파일러는 (통지 movdqa) 위의 C 코드에 대해 다음 생성 : 나 자신에게 하 스웰 CPU를 노트북을 구매할 때

400880:  66 0f 6f 04 06   movdqa xmm0,XMMWORD PTR [rsi+rax*1] 
400885:  41 83 c0 01    add r8d,0x1 
400889:  66 0f ef 04 07   pxor xmm0,XMMWORD PTR [rdi+rax*1] 
40088e:  66 0f 7f 04 06   movdqa XMMWORD PTR [rsi+rax*1],xmm0 
400893:  48 83 c0 10    add rax,0x10 
400897:  45 39 c1    cmp r9d,r8d 
40089a:  77 e4     ja  400880 <region_xor_w64+0x20> 

내일, 컴파일러는 저를 생성합니다 동일한 코드에서 128 비트 대신 256 비트 명령어를 사용하는 코드는 벡터 성능을 두 배 향상시킵니다. Haswell이 그것을 할 수 있다는 것을 몰랐다해도 그것을 할 수 있습니다. 이 기능에 대해 알고있을뿐만 아니라 다른 버전의 코드를 작성하고 테스트하는 데 시간을 할애해야합니다.

그런데 코드에서 데이터 벡터의 나머지 3 바이트까지 스킵 할 수있는 버그가있는 것처럼 보입니다.

어쨌든 컴파일러를 신뢰하고 무엇이 생성되는지 확인하는 방법을 익히고 (즉, objdump에 익숙해지기를 권장합니다.) 다음 선택은 컴파일러를 변경하는 것입니다. 그래야만 벡터 처리 명령을 수동으로 작성하는 것에 대해 생각하기 시작하십시오. 아니면 나쁠거야!

희망이 있습니다. 행운을 빕니다!

+0

내 의견을 잊어 버리십시오. 나는 당신이 마지막에 정렬 물건을 언급하는 것을 알아 차리기에는 너무 정신이 없었다. – Mysticial

+1

그 동안 데이터 타입 크기를 늘리는 것은'__m128i'까지만 풀지 않으면 도움이되지 않습니다. 64 비트 정수 정렬조차도 'movdqu'에 대한 필요성을 제거하기에 충분하지 않기 때문입니다. – Mysticial

+0

MSVC에서 대부분의 작업을 수행 한 이후로 나는 그것을 사용한 적이 한번도 없습니다. 대부분의 경우 간단한 루프가 성능에 중요한 영향을 주면 단순한 벡터화보다 더 많은 개선을 이루기 위해 수행 할 수있는 더 높은 수준의 변환이 일반적으로 있다는 것을 알았습니다. 하지만 이러한 변환은 애플리케이션에 따라 다르며 때로는 그렇게하기 쉽지 않습니다. 따라서 컴파일러 확장을 해킹하는 것은 아마도 대부분의 사람들에게 더 쉬운 방법 일 것입니다. – Mysticial