CSAPP:代码优化【矩阵运算】
编程除了使程序在所有可能的情况下都正确工作,还需要考虑程序的运行效率,上一节主要介绍了关于读写的优化,本节将对运算的优化进行分析。
1、2、3处分别代表角点、边缘点以及内部点的相邻像素
我们用以下结构体表示一张图像的像素点:
typedef struct { unsigned short red; /* R value */ unsigned short green; /* G value */ unsigned short blue; /* B value */ } pixel;
red、green、blue分别表示一张彩色图像的红绿蓝三个通道。
原平滑函数如下:
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_sum sum) { 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; } 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; } 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); }
图像是标准的正方形,用一维数组表示,第(i,j)个像素表示为I[RIDX(i,j,n)],n为图像边长。
参数:
- dim:图像的边长
- src: 指向原始图像数组首地址
- dst: 指向目标图像数组首地址
优化目标:使平滑运算处理的更快
当前我们拥有一个driver.c文件,可以对原函数和我们优化的函数进行测试,得到表示程序运行性能的CPE(每元素周期数)参数。
我们的任务就是实现优化代码,与原有代码同时运行进行参数的对比,查看代码优化情况。
优化的主要方法
- 循环展开
- 并行计算
- 提前计算
- 分块运算
- 避免复杂运算
- 减少函数调用
- 提高Cache命中率
循环主体只存在一条语句,该语句主要是进行大量的均值运算,而且调用了多层的函数,这样运行时会出现多个函数栈的调用。
通过分析,本节的优化手段比
计算红色区域平均值与黄色区域平均值时,有两行是重复运算的。相应的优化策略是以1*3小矩阵为组计算和,这样每次计算均值只需要3个已知的和相加除以9,减少了一定的运算量。
相应的优化代码如下:
int rsum[4096][4096]; int gsum[4096][4096]; int bsum[4096][4096]; void smooth(int dim, pixel *src, pixel *dst) { int dim2 = dim * dim;