2017-02-19 5 views
2

나는 스칼라 행렬 덧셈 커널을 구현했다.스칼라 매트릭스 추가에 addss 대신 vaddss를 사용하면 어떤 이점이 있습니까?

gcc -O2 msse4.2 : 다음

이때
#include <stdio.h> 
#include <time.h> 
//#include <x86intrin.h> 

//loops and iterations: 
#define N 128 
#define M N 
#define NUM_LOOP 1000000 


float __attribute__((aligned(32))) A[N][M], 
     __attribute__((aligned(32))) B[N][M], 
     __attribute__((aligned(32))) C[N][M]; 

int main() 
{ 
int w=0, i, j; 
struct timespec tStart, tEnd;//used to record the processiing time 
double tTotal , tBest=10000;//minimum of toltal time will asign to the best time 
do{ 
    clock_gettime(CLOCK_MONOTONIC,&tStart); 

    for(i=0;i<N;i++){ 
     for(j=0;j<M;j++){ 
      C[i][j]= A[i][j] + B[i][j]; 
     } 
    } 

    clock_gettime(CLOCK_MONOTONIC,&tEnd); 
    tTotal = (tEnd.tv_sec - tStart.tv_sec); 
    tTotal += (tEnd.tv_nsec - tStart.tv_nsec)/1000000000.0; 
    if(tTotal<tBest) 
     tBest=tTotal; 
    } while(w++ < NUM_LOOP); 

printf(" The best time: %lf sec in %d repetition for %dX%d matrix\n",tBest,w, N, M); 
return 0; 
} 

, I는 다른 컴파일러 플래그와 내부 루프의 조립 출력 프로그램을 컴파일 한이며, 가장 시간 : 128X128위한 0.000024 초에서 406,490 반복 매트릭스

movss xmm1, DWORD PTR A[rcx+rax] 
addss xmm1, DWORD PTR B[rcx+rax] 
movss DWORD PTR C[rcx+rax], xmm1 

gcc -O2 -mavx : 최고의 시간 : 0.000009 초에서 1,000,001 반복

매트릭스 용 128X

AVX 버전 gcc -O2 -mavx :

__m256 vec256; 
for(i=0;i<N;i++){ 
    for(j=0;j<M;j+=8){ 
     vec256 = _mm256_add_ps(_mm256_load_ps(&A[i+1][j]) , _mm256_load_ps(&B[i+1][j])); 
     _mm256_store_ps(&C[i+1][j], vec256); 
      } 
     } 

SSE 버전 gcc -O2 -sse4.2 ::

__m128 vec128; 
for(i=0;i<N;i++){ 
    for(j=0;j<M;j+=4){ 
    vec128= _mm_add_ps(_mm_load_ps(&A[i][j]) , _mm_load_ps(&B[i][j])); 
    _mm_store_ps(&C[i][j], vec128); 
      } 
     } 

스칼라 프로그램에서이 msse4.2 이상 -mavx의 속도 향상은 2.7 배이다. 나는 ISA를 효율적으로 개선 한 avx을 알고 있으며 이러한 개선으로 인해있을 수 있습니다. 그러나 AVXSSE 모두에 대해 내장 프로그램에서 프로그램을 구현하면 속도가 3 배 빨라졌습니다. 문제는 AVX 스칼라가 SSE보다 2.7 배 빨라서 벡터화 할 때 속도가 3 배 (매트릭스 크기는 128x128)입니다. 스칼라 모드에서 AVX 및 SSE를 사용하면 2.7 배의 속도 향상이 가능합니다. SSE의 네 요소에 비해 AVX에서 여덟 요소를 처리하기 때문에 벡터화 된 방법이 더 좋아야합니다. perf stat이보고 된대로 모든 프로그램의 캐시 누락이 4.5 % 미만입니다. 사용

gcc -O2, linux mint, skylake

UPDATE : 간단하게는, 스칼라 AVX는이 벡터화하는 동안에 스칼라 SSE하지만 AVX-256은 SSE-128에 비해 단지 3 배 더 빠른 것보다 2.7 배 빠릅니다. 파이프 라이닝 때문일 수도 있습니다. 스칼라에는 벡터화 된 모드에서 사용할 수없는 3 vec-ALU이 있습니다. 나는 사과 대신에 사과와 사과를 사과와 비교해 볼 수도 있는데, 그 이유를 이해하지 못할 수도 있습니다.

+0

제목 질문에 답변하려면 (본문의 마지막 부분을 완전히 파싱 할 수 없음) : [GCC는 -O1에서 컴파일 할 때만 말한 내용을 수행합니다] (https://godbolt.org/g/T4xnCU). AVX가있는 시스템을 대상으로 할 때 [기존 SSE 지침의 VEX 버전을 사용하는 것이 좋습니다] (https://software.intel.com/sites/default/files/m/d/4/1/d/8) /11MC12_Avoiding_2BAVX-SSE_2BTransition_2BPenalties_2Brh_2Bfinal.pdf). –

+0

@MargaretBloom, no gcc -O2' 나는 질문에 덧붙였다. 타겟팅은 정상이지만 AVX-128이 아닌 순수한'AVX'와'SSE'를 AVX-256이 아닌 AVX-128과 비교하고 있습니다. – Martin

+0

@MargaretBloom, 벡터화는'-O3'에 의해 가능하지만'-O2'가 아닌'-ftree-loop-vectorize'에 의해 가능합니다. –

답변

3

관찰중인 문제는 here으로 설명되어 있습니다. Skylake 시스템에서 AVX 레지스터의 상반부가 더러 우면 AVX 레지스터의 상반부에서 인코딩되지 않은 SSE 작업에 대해 잘못된 종속성이 있습니다. 귀하의 경우 glibc 2.23 버전에 버그가있는 것 같습니다. 우분투 16.10과 glibc 2.24 Skylake 시스템에서 나는 문제가 없다.

__asm__ __volatile__ ("vzeroupper" : : :); 

을 사용하면 AVX 레지스터의 위쪽 절반을 청소할 수 있습니다. 나는 GCC가 SSE 코드라고 말할 것이고 intrinsic을 인식하지 못하기 때문에 당신이 _mm256_zeroupper과 같은 intrinsic을 사용할 수 있다고 생각하지 않는다. -mvzeroupper 옵션은 GCC가 다시 SSE 코드라고 생각하고 vzeroupper 명령어를 방출하지 않기 때문에 작동하지 않습니다.

BTW, it's Microsoft's fault that the hardware has this problem.


업데이트 :

Other people are apparently encountering this problem on Skylake. printf, memsetclock_gettime 이후에 관찰되었습니다.

128 비트 연산을 256 비트 연산과 비교하는 것이 목표라면 -mprefer-avx128 -mavx (AMD에서 특히 유용함)을 사용하는 것이 좋습니다. 그렇다면 AVX256과 AVX128을 비교하고 AVX256과 SSE는 비교하지 않을 것입니다. AVX128과 SSE는 모두 128 비트 연산을 사용하지만 그 구현은 다릅니다. 벤치마킹하는 경우 어떤 것을 사용했는지 언급해야합니다.

+0

ABI에 따르면, AVX를 사용하는 모든 함수는 완료 될 때'vzeroupper'를 실행해야한다. 벌레가 어딘가에있는 것 같습니다. – fuz

+0

@fuz, 내가 지적한 첫 번째 링크를 읽었습니까? 문제는 AVX 레지스터의 상단 부분을 지울 때 사라집니다. 시스템에서 문제를 재현 할 수 없으므로 테스트 할 수 없습니다. OP는 문제가'main_'의 직후에'__asm__ __volatile__ ("vzeroupper": : :);와 같이 없어지지 않았다고 말했고, 그것은'clock_gettime' 후에 사용되었을 때 사라졌습니다. 내 대답은 내가 언급하지 않았다. 왜냐하면 내가 확실히 알고있는 유일한 문제는 상반부가 더럽다는 것이다. 우리가 그것에 동의 할 수 있습니까? –

+0

링크 된 게시물의 마지막 몇 줄을 읽으십시오. 기본적으로 말한 것과 똑같습니다. 누군가가 나중에 vzeroupper를 실행하지 않고 AVX 명령어를 사용 했어야합니다. – fuz