SSE를 사용하여 4 개의 플로트에 4 개의 플로트를 곱하는 가장 효율적인 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1227249

  •  22-07-2019
  •  | 
  •  

문제

현재 다음 코드가 있습니다.

float a[4] = { 10, 20, 30, 40 };
float b[4] = { 0.1, 0.1, 0.1, 0.1 };
asm volatile("movups (%0), %%xmm0\n\t"
             "mulps (%1), %%xmm0\n\t"             
             "movups %%xmm0, (%1)"             
             :: "r" (a), "r" (b));

먼저 몇 가지 질문이 있습니다.

(1) 16 바이트 경계에 배열을 정렬한다면 작동합니까? 배열이 스택에 할당되었으므로 정렬하는 것이 거의 불가능하다는 것이 사실입니까?

이 게시물의 선택한 답변을 참조하십시오. 스택 변수는 gcc __attribute __ ((aligned (x))에 의해 정렬됩니까?

(2) 코드를보다 효율적으로 만들기 위해 코드를 전혀 리팩토링 할 수 있습니까? 두 플로트 배열을 하나가 아닌 레지스터에 넣으면 어떻게해야합니까?

감사

도움이 되었습니까?

해결책

16 바이트 경계에서 배열을 정렬한다면 작동합니까? 배열이 스택에 할당되었으므로 정렬하는 것이 거의 불가능하다는 것이 사실입니까?

스택의 정렬이 작동해야합니다. 그렇지 않으면 고유는 작동하지 않습니다. 나는 당신이 인용 한 게시물이 정렬 값에 대해 선택한 엄청난 가치와 관련이 있다고 생각합니다.

2 ~ 2 :

아니요, 성능에 차이가 없어야합니다. 이것 좀 봐 대지 여러 프로세서의 지침 타이밍.


스택 변수의 정렬이 작동하는 방법 :

push    ebp
mov ebp, esp
and esp, -16                ; fffffff0H
sub esp, 200                ; 000000c8H

그만큼 그리고 스택의 시작을 16 바이트로 정렬합니다.

다른 팁

C로 쓰고 사용하십시오

gcc -S -mssse3

최신 버전의 GCC가있는 경우.

(1) 16 바이트 경계에 배열을 정렬하려면 작동할까요? 배열이 스택에 할당되었으므로 정렬하는 것이 거의 불가능하다는 것이 사실입니까?

아니요, 스택 포인터를 사용하여 정렬하는 것은 매우 간단합니다. and:

and esp, 0xFFFFFFF0 ; aligned on a 16-byte boundary

그러나 16 바이트 유형과 같이 GCC가 제공하는 것을 사용해야합니다. __attribute__ 정렬을 사용자 정의합니다.

GCC가 지원을 제공합니까? __m128 데이터 형식? 그렇다면 16 바이트 정렬 된 데이터 유형을 보장하기위한 최선의 계획입니다. 그럼에도 불구하고 있습니다 __attribute__((aligned(16))) 일을 정렬합니다. 배열을 다음과 같이 정의하십시오

float a[4] __attribute__((aligned(16))) = { 10, 20, 30, 40 };
float b[4] __attribute__((aligned(16))) = { 0.1, 0.1, 0.1, 0.1 };

그리고 대신 Movaps를 사용하십시오 :)

특히 최적화를 통해 고유 사용이 훨씬 빠릅니다. 간단한 테스트를 작성하고 두 버전을 모두 비교합니다 (ASM 및 Intrinsic)

unsigned long long time1;
__m128 a1,b1;


a1=_mm_set_ps(10, 20,30,40);
b1=_mm_set_ps(0.1, 0.1, 0.1, 0.1);
float a[4] = { 10, 20, 30, 40 };
float b[4] = { 0.1, 0.1, 0.1, 0.1 };

time1=__rdtsc();
a1=_mm_mul_ps(a1,b1);
time1=__rdtsc() - time1 ;
printf("Time: %llu\n",time1);


time1=__rdtsc();
asm volatile("movups (%0), %%xmm0\n\t"
                 "mulps (%1), %%xmm0\n\t"
                 "movups %%xmm0, (%1)"
                 :: "r" (a), "r" (b));
time1=__rdtsc() - time1 ;
printf("Time: %llu\n",time1);

고유 버전 50-60 프로세서 타임 스탬프 ASM 버전 ~ 1000 Proc Timestamps

컴퓨터에서 테스트 할 수 있습니다

리팩토링에 대해. 고유를 사용할 수 있습니다. 예시:

#include <emmintrin.h>

int main(void)
{
    __m128 a1,b1;

    a1=_mm_set_ps(10, 20,30,40);
    b1=_mm_set_ps(0.1, 0.1, 0.1, 0.1);

    a1=_mm_mul_ps(a1,b1);

    return 0;
}

최적화 GCC (-O2 , -O3) ASM보다 빠르게 작동 할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top