perflab实验报告.docx
《perflab实验报告.docx》由会员分享,可在线阅读,更多相关《perflab实验报告.docx(18页珍藏版)》请在冰豆网上搜索。
perflab实验报告
湖南大学课程实验报告
课程名称:
计算机组成与结构
实验项目名称:
perflab
专业班级:
姓名:
学号:
指导教师:
完成时间:
2015年05月22日
计算机科学与工程系
实验题目:
程序性能调优实验
实验目的:
kernel.c文件中主要有两个需要进行优化的函数:
rotate和smooth,并分别给出了naive_rotate和naive_smooth两个函数的基本实现作为baseline作为你改进后的程序的比较对象。
你需要读懂rotate和smooth函数,并对其进行优化。
你每写一个新版本的、优化的rotate和smooth函数,均可在成注册后使用driver进行测试,并得到对应的CPE和加速比。
本次实验,要求针对每个函数、每个人均至少写出3种优化版本、并根据driver报告的结果进行性能分析。
实验环境:
Vmware虚拟机ubuntu12.04linux终端
实验步骤和结果分析:
函数源码:
rotate函数:
voidnaive_rotate(intdim,pixel*src,pixel*dst)
{
inti,j;
for(i=0;ifor(j=0;jdst[RIDX(dim-1-j,i,dim)]=src[RIDX(i,j,dim)];
}
rotate函数的作用是通过将每个像素进行行列调位,将一副点阵图像进行90度旋转。
其中RIDX(i,j,n)即((i)*(n)+(j))。
函数缺点为程序局部性不好,循环次数过多。
可以对其进行分块来提高空间局部性,也可以进行循环展开。
smooth函数:
voidnaive_smooth(intdim,pixel*src,pixel*dst)
{
inti,j;
for(i=0;ifor(j=0;jdst[RIDX(i,j,dim)]=avg(dim,i,j,src);
}
smooth函数的作用是通过对图像每几点像素求平均值来对图像进行模糊化处理。
函数缺点是循环次数过多和频繁调用avg函数,avg函数中又包含许多函数。
应该减少avg函数的调用次数,且进行循环展开。
第一种版本:
CPE分析:
rotate函数:
voidrotate(intdim,pixel*src,pixel*dst)
{
inti,j,ii,jj;
for(ii=0;iifor(jj=0;jjfor(i=ii;ifor(j=jj;jdst[RIDX(dim-1-j,i,dim)]=src[RIDX(i,j,dim)];
}
多添加了两个for函数,将循环分成了4*4的小块,在cache存储体不足够大的情况下,对循环分块能够提升高速缓存命中率,从高提升了空间局部性。
从测试的CPE中也可以看出,在dim是64的时候,原代码和本代码CPE相差不大,而随着dim的增大,本代码CPE增加不大,而原代码CPE急剧增加,就是受到了cache存储的局限性。
smooth函数:
voidsmooth(intdim,pixel*src,pixel*dst)
{
pixel_sumrowsum[530][530];
inti,j,snum;
for(i=0;i{
rowsum[i][0].red=(src[RIDX(i,0,dim)].red+src[RIDX(i,1,dim)].red);
rowsum[i][0].blue=(src[RIDX(i,0,dim)].blue+src[RIDX(i,1,dim)].blue);
rowsum[i][0].green=(src[RIDX(i,0,dim)].green+src[RIDX(i,1,dim)].green);
rowsum[i][0].num=2;
for(j=1;j{
rowsum[i][j].red=(src[RIDX(i,j-1,dim)].red+src[RIDX(i,j,dim)].red+src[RIDX(i,j+1,dim)].red);
rowsum[i][j].blue=(src[RIDX(i,j-1,dim)].blue+src[RIDX(i,j,dim)].blue+src[RIDX(i,j+1,dim)].blue);
rowsum[i][j].green=(src[RIDX(i,j-1,dim)].green+src[RIDX(i,j,dim)].green+src[RIDX(i,j+1,dim)].green);
rowsum[i][j].num=3;
}
rowsum[i][dim-1].red=(src[RIDX(i,dim-2,dim)].red+src[RIDX(i,dim-1,dim)].red);
rowsum[i][dim-1].blue=(src[RIDX(i,dim-2,dim)].blue+src[RIDX(i,dim-1,dim)].blue);
rowsum[i][dim-1].green=(src[RIDX(i,dim-2,dim)].green+src[RIDX(i,dim-1,dim)].green);
rowsum[i][dim-1].num=2;
}
for(j=0;j{
snum=rowsum[0][j].num+rowsum[1][j].num;
dst[RIDX(0,j,dim)].red=(unsignedshort)((rowsum[0][j].red+rowsum[1][j].red)/snum);
dst[RIDX(0,j,dim)].blue=(unsignedshort)((rowsum[0][j].blue+rowsum[1][j].blue)/snum);
dst[RIDX(0,j,dim)].green=(unsignedshort)((rowsum[0][j].green+rowsum[1][j].green)/snum);
for(i=1;i{
snum=rowsum[i-1][j].num+rowsum[i][j].num+rowsum[i+1][j].num;
dst[RIDX(i,j,dim)].red=(unsignedshort)((rowsum[i-1][j].red+rowsum[i][j].red+rowsum[i+1][j].red)/snum);
dst[RIDX(i,j,dim)].blue=(unsignedshort)((rowsum[i-1][j].blue+rowsum[i][j].blue+rowsum[i+1][j].blue)/snum);
dst[RIDX(i,j,dim)].green=(unsignedshort)((rowsum[i-1][j].green+rowsum[i][j].green+rowsum[i+1][j].green)/snum);
}
snum=rowsum[dim-1][j].num+rowsum[dim-2][j].num;
dst[RIDX(dim-1,j,dim)].red=(unsignedshort)((rowsum[dim-2][j].red+rowsum[dim-1][j].red)/snum);
dst[RIDX(dim-1,j,dim)].blue=(unsignedshort)((rowsum[dim-2][j].blue+rowsum[dim-1][j].blue)/snum);
dst[RIDX(dim-1,j,dim)].green=(unsignedshort)((rowsum[dim-2][j].green+rowsum[dim-1][j].green)/snum);
}
}
本函数取消调用了avg函数,通过在函数中直接对像素点的三原色比例分别求平均值的方法来求像素的平均值。
因为取消了avg函数的调用,减少了大多数函数调用环节,并且将重复利用的数据储存在了数组之中,因此提升了速度。
但是本方法提升的速度不够显著。
仅是在dim较小的情况下才有较好的优化。
且当dim>512时,超出了设置的数组大小会报错。
第二种版本:
CPE分析:
rotate函数:
voidrotate(intdim,pixel*src,pixel*dst)
{
inti,j;
inttemp;
intit,jt;
intim,jm;
for(jt=0;jt{
jm=jt+32;
for(it=0;it{
im=it+32;
for(j=jt;j{
temp=dim-1-j;
for(i=it;i{
dst[RIDX(temp,i,dim)]=src[RIDX(i,j,dim)];
}
}
}
}
return;
}
这个函数跟第一种版本有较大的相似,但是是分成了32*32的小块。
提升的速度比第一种版本多,这是因为32*32的小块充分利用了cache储存,降低了冷不命中率。
如果再增大小块的大小的话,可能因为超出了cache储存,成了和原码同样的情况,降低空间局部性。
smooth函数:
voidsmooth(intdim,pixel*src,pixel*dst)
{
inti,j;
intdim0=dim;
intdim1=dim-1;
intdim2=dim-2;
pixel*P1,*P2,*P3;
pixel*dst1;
P1=src;
P2=P1+dim0;
dst->red=(P1->red+(P1+1)->red+P2->red+(P2+1)->red)>>2;
dst->green=(P1->green+(P1+1)->green+P2->green+(P2+1)->green)>>2;
dst->blue=(P1->blue+(P1+1)->blue+P2->blue+(P2+1)->blue)>>2;
dst++;
for(i=1;i{
dst->red=(P1->red+(P1+1)->red+(P1+2)->red+P2->red+(P2+1)->red+(P2+2)->red)/6;
dst->green=(P1->green+(P1+1)->green+(P1+2)->green+P2->green+(P2+1)->green+(P2+2)->green)/6;
dst->blue=(P1->blue+(P1+1)->blue+(P1+2)->blue+P2->blue+(P2+1)->blue+(P2+2)->blue)/6;
dst++;
P1++;
P2++;
}
dst->red=(P1->red+(P1+1)->red+P2->red+(P2+1)->red)>>2;
dst->green=(P1->green+(P1+1)->green+P2->green+(P2+1)->green)>>2;
dst->blue=(P1->blue+(P1+1)->blue+P2->blue+(P2+1)->blue)>>2;
dst++;
P1=src;
P2=P1+dim0;
P3=P2+dim0;
for(i=1;i{
dst->red=(P1->red+(P1+1)->red+P2->red+(P2+1)->red+P3->red+(P3+1)->red)/6;
dst->green=(P1->green+(P1+1)->green+P2->green+(P2+1)->green+P3->green+(P3+1)->green)/6;
dst->blue=(P1->blue+(P1+1)->blue+P2->blue+(P2+1)->blue+P3->blue+(P3+1)->blue)/6;
dst++;
dst1=dst+1;
for(j=1;j{
dst->red=(P1->red+(P1+1)->red+(P1+2)->red+P2->red+(P2+1)->red+(P2+2)->red+P3->red+(P3+1)->red+(P3+2)->red)/9;
dst->green=(P1->green+(P1+1)->green+(P1+2)->green+P2->green+(P2+1)->green+(P2+2)->green+P3->green+(P3+1)->green+(P3+2)->green)/9;
dst->blue=(P1->blue+(P1+1)->blue+(P1+2)->blue+P2->blue+(P2+1)->blue+(P2+2)->blue+P3->blue+(P3+1)->blue+(P3+2)->blue)/9;
dst1->red=((P1+3)->red+(P1+1)->red+(P1+2)->red+(P2+3)->red+(P2+1)->red+(P2+2)->red+(P3+3)->red+(P3+1)->red+(P3+2)->red)/9;
dst1->green=((P1+3)->green+(P1+1)->green+(P1+2)->green+(P2+3)->green+(P2+1)->green+(P2+2)->green+(P3+3)->green+(P3+1)->green+(P3+2)->green)/9;
dst1->blue=((P1+3)->blue+(P1+1)->blue+(P1+2)->blue+(P2+3)->blue+(P2+1)->blue+(P2+2)->blue+(P3+3)->blue+(P3+1)->blue+(P3+2)->blue)/9;
dst+=2;
dst1+=2;
P1+=2;
P2+=2;
P3+=2;
}
for(;j{
dst->red=(P1->red+(P1+1)->red+(P1+2)->red+P2->red+(P2+1)->red+(P2+2)->red+P3->red+(P3+1)->red+(P3+2)->red)/9;
dst->green=(P1->green+(P1+1)->green+(P1+2)->green+P2->green+(P2+1)->green+(P2+2)->green+P3->green+(P3+1)->green+(P3+2)->green)/9;
dst->blue=(P1->blue+(P1+1)->blue+(P1+2)->blue+P2->blue+(P2+1)->blue+(P2+2)->blue+P3->blue+(P3+1)->blue+(P3+2)->blue)/9;
dst++;
P1++;
P2++;
P3++;
}
dst->red=(P1->red+(P1+1)->red+P2->red+(P2+1)->red+P3->red+(P3+1)->red)/6;
dst->green=(P1->green+(P1+1)->green+P2->green+(P2+1)->green+P3->green+(P3+1)->green)/6;
dst->blue=(P1->blue+(P1+1)->blue+P2->blue+(P2+1)->blue+P3->blue+(P3+1)->blue)/6;
dst++;
P1+=2;
P2+=2;
P3+=2;
}
dst->red=(P1->red+(P1+1)->red+P2->red+(P2+1)->red)>>2;
dst->green=(P1->green+(P1+1)->green+P2->green+(P2+1)->green)>>2;
dst->blue=(P1->blue+(P1+1)->blue+P2->blue+(P2+1)->blue)>>2;
dst++;
for(i=1;i{
dst->red=(P1->red+(P1+1)->red+(P1+2)->red+P2->red+(P2+1)->red+(P2+2)->red)/6;
dst->green=(P1->green+(P1+1)->green+(P1+2)->green+P2->green+(P2+1)->green+(P2+2)->green)/6;
dst->blue=(P1->blue+(P1+1)->blue+(P1+2)->blue+P2->blue+(P2+1)->blue+(P2+2)->blue)/6;
dst++;
P1++;
P2++;
}
dst->red=(P1->red+(P1+1)->red+P2->red+(P2+1)->red)>>2;
dst->green=(P1->green+(P1+1)->green+P2->green+(P2+1)->green)>>2;
dst->blue=(P1->blue+(P1+1)->blue+P2->blue+(P2+1)->blue)>>2;
}
这段代码也是通过不调用avg函数来加速程序。
将Smooth函数处理分为4块,一为主体内部,由9点求平均值;二为4个顶点,由4点求平均值;三为四条边界,由6点求平均值。
从图片的顶部开始处理,再上边界,顺序处理下来,其中在处理左边界时,for循环处理一行主体部分,就是以上的代码。
第三种版本:
CPE分析:
rotate函数:
voidrotate(intdim,pixel*src,pixel*dst)
{
inti,j;
intdst_base=(dim-1)*dim;
dst+=dst_base;
for(i=0;i{
for(j=0;j{
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src+=dim;
dst++;
*dst=*src;
src++;
src-=(dim<<5)-dim;
dst-=31+dim;
}
dst+=dst_base+dim;
dst+=32;
src+=(dim<<5)-dim;
}
}
这个函数是通过循环展开来加速程序的。
将循环次数减少32倍,同时处理32个像素点来达成循环展开,因为这32个像素点的处理可以并行处理,因此减少了关键路径的长度,大大加速了程序。
smooth函数:
voidsmooth(intdim,pixel*src,pixel*dst)
{
inti,j,rij;
intrindex=dim;
dst[0].red=(src[0].red+src[1].red+src[dim].red+src[dim+1].red)>>2;
dst[0].blue=(src[0].blue+src[1].blue+src[dim].blue+src[dim+1].blue)>>2;
dst[0].green=(src[0].green+src[1].green+src[dim].green+src[dim+1].green)>>2;
dst[dim-1].red=(src[dim-1].red+src[dim-2].red+src[dim*2-1].red+src[dim*2-2].red)>>2;
dst[dim-1].blue=(src[dim-1].blue+src[dim-2].blue+src[dim*2-1].blue+src[dim*2-2