热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

CSAPP实验四:性能优化实验(Perflab)

本系列文章为中国科学技术大学计算机专业学科基础课《计算机系统》布置的实验,上课所用教材和内容为黑书CSAPP,当时花费很大精力和弯路,现来

       本系列文章为中国科学技术大学计算机专业学科基础课《计算机系统》布置的实验,上课所用教材和内容为黑书CSAPP,当时花费很大精力和弯路,现来总结下各个实验,本文章为第四个实验——性能优化实验(Perflab)。


一、实验名称:perflab


二、实验学时: 3


三、实验内容和目的:

       此次实验进行图像处理代码的优化。图像处理提供了许多能够通过优化而得到改良的函数。在此次实验中,我们将考虑两种图像处理操作:roate, 此函数用于将图像逆时针旋转90°;以及smooth,对图像进行“平滑”或者说“模糊”处理。

       对于此次实验,我们将认为图像是以一个二维矩阵 M 来表示的,并以 Mi,j 来表记(i,j)位置的像素值。像素值是由红,绿,蓝(RGB)三个值构成的三元组。我们仅考虑方形图像。以 N 来表记图像的行数(同时也是列数)。行和列均以C风格进行编号——从0到 N - 1 。

       在这种表示方法之下,rotate 操作可以借由以下两种矩阵操作的结合来简单实现:


  • 转置:对于每个(i,j),交换 Mi,j 与 Mj,i 。
  • 行交换:交换第 i 行与第 N - 1 - i 行。

       详情见下图:

        smooth 操作可以通过求每个像素与周围像素(最多是以该像素为中心的3×3的九宫格)的均值。详见图2,像素 M2[1][1] 与 M2[N - 1][N - 1] 由下式给出:


 四、实验步骤及结果:

        首先将 perflab-handout.tar 拷贝至一个受保护的文件夹,用于完成此次实验。

        然后在命令行输入命令:tar xvf perflab-handout.tar 这将使数个文件被解压至当前目录。

        你可以进行修改并最终提交的唯一文件是 kernels.c 程序 driver.c 是一个驱动程序,你可以用它来评估你解决方案的性能。使用命令:make driver 来生成驱动代码,并用命令 ./driver 来使其运行。

        查看文件 kernels.c,你会发现一个C 结构体:team。你需要将你小组成员的信息填入其中。请马上填写,以防你忘记。


      1.naive_rotate

/**naive_rotate - The naive baseline version of rotate*/
char naive_rotate_descr[] ="naive_rotate: Naive baseline implementation";
void naive_rotate(int dim, pixel *src,pixel *dst)
{int i, j;for (i = 0; i }

         在头文件defs.h中找到了宏定义:

#defineRIDX(i,j,n) ((i)*(n)+(j))

        那么这段代码就很容易为一幅画的旋转,它将将所有的像素进行行列调位、导致整幅图画进行了90度旋转。

        但是由于这串代码的步长太长,导致cache的命中率非常低,所以总体运算效率低。因此,我们考虑到cache的大小,应在存储的时候进行32个像素依次存储(列存储)。(32个像素排列是为了充分利用一级缓存(32KB), 采用分块策略, 每一个块大小为32)

        这样可以做到cache友好、可以大幅度提高效率。


      2.perf_rotate

        考虑矩形分块32*1,32路循环展开,并使dest地址连续,以减少存储器写次数

//宏定义一个复制函数,方便程序编写
#define COPY(d,s) *(d)=*(s)
char rotate_descr[] = "rotate: Currentworking version";void rotate( int dim,pixel *src,pixel *dst)
{int i,j;for(i=0;i=0;j-=1)
{ pixel*dptr=dst+RIDX(dim-1-j,i,dim);pixel*sptr=src+RIDX(i,j,dim);
//进行复制操作COPY(dptr,sptr);sptr+=dim;COPY(dptr+1,sptr);sptr+=dim;COPY(dptr+2,sptr);sptr+=dim;COPY(dptr+3,sptr);sptr+=dim;COPY(dptr+4,sptr);sptr+=dim;COPY(dptr+5,sptr);sptr+=dim;COPY(dptr+6,sptr);sptr+=dim;COPY(dptr+7,sptr);sptr+=dim;COPY(dptr+8,sptr);sptr+=dim;COPY(dptr+9,sptr);sptr+=dim;COPY(dptr+10,sptr);sptr+=dim;COPY(dptr+11,sptr);sptr+=dim;COPY(dptr+12,sptr);sptr+=dim;COPY(dptr+13,sptr);sptr+=dim;COPY(dptr+14,sptr);sptr+=dim;COPY(dptr+15,sptr);sptr+=dim;COPY(dptr+16,sptr);sptr+=dim;COPY(dptr+17,sptr);sptr+=dim;COPY(dptr+18,sptr);sptr+=dim;COPY(dptr+19,sptr);sptr+=dim;COPY(dptr+20,sptr);sptr+=dim;COPY(dptr+21,sptr);sptr+=dim;COPY(dptr+22,sptr);sptr+=dim;COPY(dptr+23,sptr);sptr+=dim;COPY(dptr+24,sptr);sptr+=dim;COPY(dptr+25,sptr);sptr+=dim;COPY(dptr+26,sptr);sptr+=dim;COPY(dptr+27,sptr);sptr+=dim;COPY(dptr+28,sptr);sptr+=dim;COPY(dptr+29,sptr);sptr+=dim;COPY(dptr+30,sptr);sptr+=dim;COPY(dptr+31,sptr);
}
}

      3.smooth

char naive_smooth_descr[] ="naive_smooth: Naive baseline implementation";
void naive_smooth(int dim, pixel *src,pixel *dst)
{int i, j;for (i = 0; i }

        这段代码频繁地调用avg函数,并且avg函数中也频繁调用initialize_pixel_sum 、accumulate_sum、assign_sum_to_pixel这几个函数,且又含有2层for循环,而我们应该减少函数调用的时间开销。所以,需要改写代码,不调用avg函数。 

        特殊情况,特殊对待:

        Smooth函数处理分为4块,一为主体内部,由9点求平均值;二为4个顶点,由4点求平均值;三为四条边界,由6点求平均值。从图片的顶部开始处理,再上边界,顺序处理下来,其中在处理左边界时,for循环处理一行主体部分,于是就有以下优化的代码。


      4.perf_smooth

charsmooth_descr[] = "smooth: Current working version";
void smooth(intdim, pixel* src, pixel* dst) {int i, j;int dim0 = dim;int dim1 = dim - 1;int dim2 = dim - 2;pixel* P1, * P2, * P3;pixel* dst1;P1 = src;P2 = P1 + dim0;//左上角像素处理 采用移位运算代替avg的某些操作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 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 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 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 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 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;
//全部处理完毕
}

      5. 实验结果

 对于rotate操作平均加速了13.1倍

 对于smooth操作平均加速了48.4倍


推荐阅读
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
author-avatar
aRuis
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有