有没有办法加速这个1D卷积?我试图使dy缓存高效 但用g ++和-O3编译会带来更差的表现。
我和[-1。 ,0,1,两个方向。 不是作业。
#include<iostream>
#include<cstdlib>
#include<sys/time.h>
void print_matrix( int height, int width, float *matrix){
for (int j=0; j < height; j++){
for (int i=0; i < width; i++){
std::cout << matrix[j * width + i] << ",";
}
std::cout << std::endl;
}
}
void fill_matrix( int height, int width, float *matrix){
for (int j=0; j < height; j++){
for (int i=0; i < width; i++){
matrix[j * width + i] = ((float)rand() / (float)RAND_MAX) ;
}
}
}
#define RESTRICT __restrict__
void dx_matrix( int height, int width, float * RESTRICT in_matrix, float * RESTRICT out_matrix, float *min, float *max){
//init min,max
*min = *max = -1.F * in_matrix[0] + in_matrix[1];
for (int j=0; j < height; j++){
float* row = in_matrix + j * width;
for (int i=1; i < width-1; i++){
float res = -1.F * row[i-1] + row[i+1]; /* -1.F * value + 0.F * value + 1.F * value; */
if (res > *max ) *max = res;
if (res < *min ) *min = res;
out_matrix[j * width + i] = res;
}
}
}
void dy_matrix( int height, int width, float * RESTRICT in_matrix, float * RESTRICT out_matrix, float *min, float *max){
//init min,max
*min = *max = -1.F * in_matrix[0] + in_matrix[ width + 1];
for (int j=1; j < height-1; j++){
for (int i=0; i < width; i++){
float res = -1.F * in_matrix[ (j-1) * width + i] + in_matrix[ (j+1) * width + i] ;
if (res > *max ) *max = res;
if (res < *min ) *min = res;
out_matrix[j * width + i] = res;
}
}
}
double now (void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
}
int main(int argc, char **argv){
int width, height;
float *in_matrix;
float *out_matrix;
if(argc < 3){
std::cout << argv[0] << "usage: width height " << std::endl;
return -1;
}
srand(123);
width = atoi(argv[1]);
height = atoi(argv[2]);
std::cout << "Width:"<< width << " Height:" << height << std::endl;
if (width < 3){
std::cout << "Width too short " << std::endl;
return -1;
}
if (height < 3){
std::cout << "Height too short " << std::endl;
return -1;
}
in_matrix = (float *) malloc( height * width * sizeof(float));
out_matrix = (float *) malloc( height * width * sizeof(float));
fill_matrix(height, width, in_matrix);
//print_matrix(height, width, in_matrix);
float min, max;
double a = now();
dx_matrix(height, width, in_matrix, out_matrix, &min, &max);
std::cout << "dx min:" << min << " max:" << max << std::endl;
dy_matrix(height, width, in_matrix, out_matrix, &min, &max);
double b = now();
std::cout << "dy min:" << min << " max:" << max << std::endl;
std::cout << "time: " << b-a << " sec" << std::endl;
return 0;
}
答案 0 :(得分:2)
使用局部变量计算最小值和最大值。每次这样做:
if (res > *max ) *max = res;
if (res < *min ) *min = res;
max和min必须写入内存。在指针上添加 restrict 会有所帮助(表明写入是独立的),但更好的方法是
//Setup
float tempMin = ...
float tempMax = ...
...
// Inner loop
tempMin = (res < tempMin) ? res : tempMin;
tempMax = (res > tempMax) ? res : tempMax;
...
// End
*min = tempMin;
*max = tempMax;
答案 1 :(得分:1)
好吧,编译器可能正在处理这些问题,但这里有一些小问题:
a)你为什么乘以-1.F?为什么不减去?例如:
float res = -1.F * row[i-1] + row[i+1];
可能只是:
float res = row[i+1] - row[i-1];
b)这:
if (res > *max ) *max = res;
if (res < *min ) *min = res;
可以制作成
if (res > *max ) *max = res;
else if (res < *min ) *min = res;
和其他地方。如果第一个是真的,那么第二个不能这样,让我们不检查它。
<强>增加:强>
这是另一回事。要最小化乘法,请更改
for (int j=1; j < height-1; j++){
for (int i=0; i < width; i++){
float res = -1.F * in_matrix[ (j-1) * width + i] + in_matrix[ (j+1) * width + i] ;
到
int h = 0;
int width2 = 2 * width;
for (int j=1; j < height-1; j++){
h += width;
for (int i=h; i < h + width; i++){
float res = in_matrix[i + width2] - in_matrix[i];
并在循环结束时
out_matrix[i + width] = res;
你可以在其他地方做类似的事情,但希望你能得到这个想法。此外,还有一个小错误,
*min = *max = -1.F * in_matrix[0] + in_matrix[ width + 1 ];
最后应该只是in_matrix[ width ]
。
答案 2 :(得分:1)
首先,我会重写dy循环以摆脱“[(j-1)* width + i]”和“in_matrix [(j + 1)* width + i]”,并执行类似的操作:
float* p, *q, *out;
p = &in_matrix[(j-1)*width];
q = &in_matrix[(j+1)*width];
out = &out_matrix[j*width];
for (int i=0; i < width; i++){
float res = -1.F * p[i] + q[i] ;
if (res > *max ) *max = res;
if (res < *min ) *min = res;
out[i] = res;
}
但这是编译器可能已经为您做的一个微不足道的优化。
执行“q [i] -p [i]”而不是“-1.f * p [i] + q [i]”会稍微快一点,但是,再一次,编译器可能足够聪明在你背后做到这一点。
整个过程将从SSE2和多线程中获益匪浅。我马上打赌SSE2至少加速了3倍。可以使用OpenMP添加多线程,只需几行代码即可。
答案 3 :(得分:1)
编译器可能会注意到这一点,但是当您进出作用域运算符{}时,您正在堆栈中创建/释放大量变量。而不是:
for (int j=0; j < height; j++){
float* row = in_matrix + j * width;
for (int i=1; i < width-1; i++){
float res = -1.F * row[i-1] + row[i+1];
怎么样:
int i, j;
float *row;
float res;
for (j=0; j < height; j++){
row = in_matrix + j * width;
for (i=1; i < width-1; i++){
res = -1.F * row[i-1] + row[i+1];
答案 4 :(得分:1)
使用OS X上的clang和g ++编译器的版本对-O3和-O2进行分析,我发现
30%的时间用于填充初始矩阵
matrix[j * width + i] = ((float)rand() / (float)RAND_MAX) ;
40%的时间花在dx_matrix上。
out_matrix[j * width + i] = row[i+1] -row[i-1];
大约9%的时间花在dx_matrix的条件语中。我将它们分成一个单独的循环,看看是否有帮助,但它没有任何改变。
Shark建议通过使用SSE指令来改善这一点。
有趣的是,只有大约19%的时间花在了dy_matrix例程上。
这是以10k×10k矩阵(约1.6秒)运行
请注意,如果您使用的是其他编译器,不同的操作系统等,结果可能会有所不同。