一、实验内容
1、通过改写rotate和smooth函数,对程序进行优化,最后通过查看加速比和cep
得出最终的结果,cep越小越好,加速比越大越好
二、实验步骤
1、rotate优化
优化1 牺牲读命中来减少写不命中惩罚
原来的rotate函数是一行行读,然后一列列写来达到旋转的目的
其中RIDX(i,j,n)= ((i)*(n)+(j)),考虑dim等于2的最简单情况,按照循环次序
此时dst[2]=src[0],dst[0]=src[1],dst[3]=src[2],dst[1]=src[3],如下图所示实现了“旋转”
也就是横着读src,竖着写入dst,显然写不命中率更高,所以对
赋值语句进行改写dst[RIDX(i, j, dim)] = src[RIDX(j, dim-i-1, dim)];
下图是不做任何优化的分数
修改过后,运行分数如下
可以看到rotate的分数明显增加了,说明写不命中惩罚更高
优化2:分块执行(在优化1的基础上)
首先在fcyc.c代码中得到#define CACHE_BLOCK 32 ,说明块的大小为32
所以在优化1的基础上对循环进行分块,在循环中增加两层循环来分解i,j;
通过循环分块可以减少步长,提高cache的命中率,修改代码如下图所示
运行分数如下,可以看到rotate的分数明显增加,说明分块可行
在实验的时候尝试用其他大小的块,发现从2到64的大部分分块结果都是13.5左右
只有32的大小才能达到16.5以上的分数,都是设计好的数据
- smooth优化
优化一 avg,accumulate_sum、assign_sum_to_pixel在smooth内实现
优化后的分数如下,优化不是很明显。
优化二 循环展开,消去两层for循环
考虑到在算sum的时候使用了两层循环来计算一个九宫格的数据,而这个是可以通过使用循环展开来直接计算的,于是代码如下所示
对于边界情况依然使用原来的循环进行求平均值,分数如下
可以看到,分数有显著的提升,从15到了20.2
优化三 边界循环展开
在优化二中,只对九宫格形式的循环进行展开,现在对边界循环进行展开
分为对角,边两种情况进行展开,代码如下图所示
运行分数如下所示,比起优化2没有多大变化,说明边界不是很耗时
附录:关于分块能够降低步长的理解
假设缓冲区大小4*4,待置换块为A,结果为B
其中0表示不命中,1表示命中,如果不分块,结果如下图所示
b块的后四行一直替换缓冲区里的前四行,所以全部不命中