나는 문제는 내가 자동 벡터화에 대한 -O3
를 사용하는 경우, 그것은 단지 3 × 3 회선 매트릭스 작동이다 회선 매트릭스gcc autovectorization이 3x3보다 큰 convolution 행렬에서 작동하지 않는 이유는 무엇입니까?
#include <stdio.h>
#include <time.h>
#define NUM_LOOP 1000
#define N 128 //input or output dimention 1
#define M N //input or output dimention 2
#define P 5 //convolution matrix dimention 1 if you want a 3x3 convolution matrix it must be 3
#define Q P //convolution matrix dimention 2
#define Csize P*Q
#define Cdiv 1 //div for filter
#define Coffset 0 //offset
//functions
void unusual(); //unusual implementation of convolution
void naive();
//data
unsigned short int input[N][M] __attribute__((aligned(32))); // input data
unsigned short int output[N][M] __attribute__((aligned(32))); // out put data
unsigned short int kernel[P][Q] __attribute__((aligned(32)));//convolution coefficients
int main(){
struct timespec tStart, tEnd;//used to record the processiing time
double tTotal , tBest=10000;//minimum of toltal time will asign to the best time
int w=0;
do{// this loop repeat the body to record the best time
clock_gettime(CLOCK_MONOTONIC,&tStart);
//function to be executed here :
unusual();
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, MAX1, MAX2);
return 0;
}
//unusual sequential convolution
void unusual(){
int i, j,k,temp;
for (i=P/2; i< N-P/2; i++){
for(j=Q/2; j< M-Q/2; j++){
temp=0;
for(k=0; k< Csize; k++){
temp += (kernel[k/P][k%Q]) * (input[i - (P/2) + (k/Q)][j - (Q/2) + (k%Q)]);
}
output[i][j]=((temp/(Cdiv))+Coffset);
}
}
}
//The naive implementation
inline void naive(){
int i, j,k,l,temp;
for (i=P/2; i< N-P/2; i++){
for(j=Q/2; j< M-Q/2; j++){
temp=0;
for(k = 0; k < P; k++){
for(l = 0; l < Q; l++){
temp += (kernel[k][l]) * (input[i - (P/2)+k][j - (Q/2)+l]);
}
}
output[i][j]=((temp/(Cdiv))+Coffset);
}
}
}
에 대해 다음 프로그램을 구현했습니다. 어셈블리 출력과 자동 벡터화가 3x3 커널을 약간 변경하고 성능을 합리적으로 향상시키는 것을 보았습니다 (20 시간 빨라짐 : 특이한 func의 스칼라 버전은 단순한 재미보다 느립니다). 그러나 5x5 회선 매트릭스에 대한 개선은 없습니다
업데이트 : 질문에 순진한 구현을 추가하고 그림 크기를 NxM, 커널에 conv 행렬, Cdim1xCdim2에서 PxQ로 변경하고 seqConv 기능을 명확히하기 위해 비정상적으로 변경했습니다. 문제는 비정상적인 기능의 구현을 향상시키는 것이 아닙니다. 문제는 모든 요소가 메모리의 동일한 위치에있는 반면 gcc는 경험적 방법을 사용하는 것입니다. gcc가이 비정상적인 구현을 향상시키지 못하는 이유는 무엇입니까? 참고 : 문제는 순진 구현에 관한 것이 아닙니다. gcc -O3
은 3 배속, 5 배속 커널에 대한 순진한 구현을 ~ 7 배 향상시킵니다. 또한 1.5 배속으로 7x7 및 9x9를 처리합니다. 회선을 개선하기 위해 필자는 intrinsics를 사용했으며 속도가 비정상적인 회 돌이보다 ~ 2 배 빠른 순진 구현보다 40 배 이상 빠릅니다. 그래서 내 벡터화는 나의 특이한 것보다 80 배 빠릅니다. 손 조정 최적화는 문제가되지 않습니다. 자동 벡터화 최적화가 문제이며 실패의 원인입니다.
GCC 명령 : gcc -Wall -march=native -O3 -o "%e" "%f"
플랫폼 : 리눅스 민트, 스카이 레이크, 사전에 6.2
감사
컴파일하여 충분히 컴파일 할 수 있습니까? – harold
물론, 나는 놓친 부분을 추가했습니다. 구멍 프로그램에는 AVX2 내장 함수로 구현 된 다른 많은 기능이 포함되어 있습니다. 이 프로그램에서는'__attribute __ ((aligned (32)))' – Martin
을 사용하여 모든 행렬을 정렬했다.'clang'과'MVC++'에서'#define Cdim1 3'으로 컴파일했고'gcc -O2'보다 속도가'0.97'이고 ''4.34' 각각 'clang -O3'과'MVC++ O2' 나는'/ arch : AVX2'와'Enhancement extension'과'Ot'을 활성화 시켰습니다. 그러나 차이점은 없습니다. – Martin