Я реализовал следующую программу для матрицы свертки
#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 улучшений нет.
ОБНОВЛЕНИЕ: я добавил наивную реализацию к вопросу и изменил размер изображения на NxM, матрицу conv на ядро, Cdim1xCdim2 на PxQ и функцию seqConv на необычную для пояснения. Вопрос не в том, чтобы улучшить реализацию необычной функции. Вопрос в том, что если все элементы находятся в одних и тех же местах памяти, gcc использует эвристику и т. д., то почему gcc не может улучшить эту необычную реализацию? ПРИМЕЧАНИЕ: проблема не в наивной реализации. gcc -O3
улучшить наивную реализацию для ядер 3x3, 5x5 на ~7 ускорение. и это также для 7x7 и 9x9 с ускорением ~ 1,5. Чтобы улучшить свертку, я использовал встроенные функции, и ускорение более чем в 40 раз по сравнению с простой реализацией, что примерно в 2 раза быстрее, чем у обычной свертки. Так что моя векторизация примерно в 80 раз быстрее, чем моя необычная. Оптимизация ручной настройки не является проблемой. Оптимизация автоматического векторизатора является проблемой и причиной сбоев.
Команда GCC: gcc -Wall -march=native -O3 -o "%e" "%f"
Платформа: Linux mint, Skylake, gcc 6.2.
заранее спасибо
__attribute__(( aligned(32)))
- person Martin   schedule 07.12.2016#define Cdim1 3
вclang
иMVC++
, а ускорение по сравнению сgcc -O2
составляет0.97
и4.34
соответственноclang -O3
иMVC++ O2
. Я также включил/arch:AVX2
иEnhancement extension
Ot
, но разницы нет. - person Martin   schedule 07.12.2016gcc
есть библиотека свертки 3x3? а для 5х5 нет? - person Martin   schedule 13.12.20163x3xsizeof(short int) <256 (the vector size)
whenever 5x5x16>256
- person Martin   schedule 13.12.2016conv
, поэтому размер вектора не имеет значения. Количество регистров еще может быть, но я действительно не уверен. Конечно, он не может использовать 25 векторов для хранения записей в случае 5x5, но он может транслировать некоторые из них на лету. Однако GCC продолжает отказываться от сотрудничества, я потратил много времени, пытаясь убедить его сделать хороший код для 5x5, но это просто не так, даже со встроенными функциями. Ну, может быть, если я буду очень явным и ничего не оставлю оптимизатору, но тогда мне придется разворачивать вручную и терять общность. - person harold   schedule 13.12.2016Cdiv
перестало быть 1, за исключением некоторых конкретных случаев и округления немного, оно определенно должно быть степенью двойки, по крайней мере, поскольку нет целочисленное векторное деление). Таким образом,short temp
приводит к более красивому коду. Однако не для 5x5, это все еще слишком много, чтобы просить, по-видимому. GCC также очень осторожен, не перезаписывая отступы, поэтому каждая строка начинается и заканчивается 15 скалярными свертками, этого легко избежать с помощью встроенных функций (верхний и нижний все еще должны иметь это, иначе чтение выйдет за пределы ввода). - person harold   schedule 13.12.2016