在优化代码之前,首先要知道我们有哪些方法可以优化性能?
翻书!把教材翻到目录,第五章赫然写着优化方法:
1、使用内联函数。一种替换代码方法,尽可能减少函数调用;
2、消除循环中的低效率。比如说for循环判断里面带了个函数,那么就属于低效率的循环,从时间复杂度上面也能分析;
3、减少过程调用。比如说经常需要先取数,再操作,那么优化的方法通常是把这些数安排在连续的地址里面,这样可以减少地址的计算;
4、消除不必要的存储器引用。在看书之前,我认为是减少局部变量的定义,毕竟定义一个变量就要占一个寄存器,但是书上的意思是尽量拿一个变量专门用来做某一件特定的事情,举个例子,inti就是用来for循环的,不要再拿来做计数器或者权值计算器了,如果要统计和,就应该再定义一个sum,避免汇编代码层次中,要额外使用一个寄存器临时保存变量的值。
5、循环展开。减少for循环的步长,每一次循环,尽可能的让cpu做更多的运算,提高并行性,充分发挥流水的作用。
这个实验妙处在于可以融合以上所有优化方法,容我慢慢道来~
首先看smooth函数initial版本:
char naive_smooth_descr[] = "naive_smooth: Naive baselineimplementation";
void naive_smooth(int dim, pixel *src, pixel *dst)
{
int i, j;
for (i = 0; i < dim; i++)
for(j = 0; j < dim; j++)
dst[RIDX(i, j, dim)] =avg(dim, i, j, src);
}
首先要明白RIDX(i,j, dim)是什么?
在头文件def.h中,写着#defineRIDX(i,j,n) ((i)*(n)+(j))
这是我们平时不常接触的函数型宏定义,传入i和j还有n,就计算出(i)*(n)+(j),这是dst的地址。
作为一个二维的图片,通常是用二维数组存储的,但是二维数组在内存中依然是连续的物理地址。可以把dst[RIDX(i,j, dim)] 直接理解为二维数组a[i][j]。
然后问题来了,avg(dim,i, j, src) 又是什么?直觉告诉我它是一个函数!
果然在同一个文件下面找到了这个函数:
static pixel avg(int dim, int i, int j, pixel *src) //因为缺点出于函数内部,所以这个函数无法使用
{
int ii, jj;
pixel_sum sum;
pixel current_pixel;
initialize_pixel_sum(&sum);
for(ii = max(i-1, 0); ii <= min(i+1, dim-1); ii++) //缺点,调用了函数,对边界进行了综合
for(jj= max(j-1, 0); jj <= min(j+1, dim-1); jj++)
accumulate_sum(&sum,src[RIDX(ii, jj, dim)]);
assign_sum_to_pixel(¤t_pixel, sum);
return current_pixel;
}
这个函数有个问题:
就是循环中的低效率! max(i-1, 0) 和min(i+1, dim-1)都是函数,每次for循环判断条件的时候,都要调用函数min(i+1, dim-1),所以我们首先想到的是消除循环中的低效率。
但是,这个for循环被封装在avg函数里面了,怎么办?只能放弃这个函数了,我们自己写函数。
我们首先看计算像素点平均颜色是如何计算的?
static void accumulate_sum(pixel_sum *sum, pixel p) //统计颜色数据
{
sum->red += (int) p.red;
sum->green += (int) p.green;
sum->blue += (int) p.blue;
sum->num++;
return;
}
static void assign_sum_to_pixel(pixel *current_pixel, pixel_sumsum) //计算平均值
{
current_pixel->red = (unsigned short) (sum.red/sum.num);
current_pixel->green = (unsigned short) (sum.green/sum.num);
current_pixel->blue = (unsigned short) (sum.blue/sum.num);
return;
}
通过以上两个函数,我们看到了原理,就是把相邻的像素点的RGB颜色各取平均值。
现在开始负优化啦~~~
对于32*32的图片,关键是要对四个角以及边框进行讨论。如何避免讨论呢?在迷宫问题中,解决方法就是在它的外面加一个边框。