我已经实现了以下卷积矩阵程序。
#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);
}
}
}
问题在于当我使用-O3
进行自动向量化时,它仅适用于3x3卷积矩阵。我已经查看了汇编输出,并且自动向量化只对3x3内核进行了一些更改,并合理地提高了性能(20倍的速度,注意:异常函数的标量版本比朴素函数慢),但是对于5x5卷积矩阵没有任何改进。
conv
的每个元素使用一个向量,因此向量大小不是问题。寄存器的数量仍然可能是问题,但我真的不确定。当然,在5x5情况下,它不能使用25个向量来保存条目,但可以即时广播一些。尽管如此,GCC仍然不合作,我花了很多时间试图说服它为5x5制作好代码,但它根本不行,即使使用内部函数也不行。嗯,也许如果我变得非常明确并且不留任何东西给优化器,但那样我必须手动展开并失去通用性。 - haroldCdiv
不再为1,除了某些特定情况和稍微舍入一下,它肯定必须是2的幂,因为没有整数向量除法)。 因此,short temp
会产生更好的代码。但对于5x5来说仍然有点太困难了,显然。 GCC还非常小心地不覆盖填充,因此每行都以15个标量卷积开始和结束,使用Intrinsics很容易避免这种情况(顶部和底部仍然应该具有这种情况,否则读取将超出输入)。 - harold