CSAPP第六次讨论课:尝试给所给程序提升性能

一、题一

有如下代码:

  sum = 0; 
  for (i = 0; i < length; i++) 
             sum += x[i] * y[i]; 

利用在第 5 章学习的相关技术,分析可能影响性能的部分,并尝试进行性能提升。要求:
(1)利用反汇编技术,与 gcc 汇编器优化进行比较;
(2)比较循环展开次数对性能的影响,如展开 2 次和 3 次,展开
次数越多越好吗?
(3)其他可能优化的方法

(1)利用反汇编技术,与 gcc 汇编器优化进行比较;

首先将代码补充完整:
在这里插入图片描述

然后进行无优化后的反汇编:
在这里插入图片描述

上图是进行无优化的情况,将其可执行文件反汇编得到的,我们可以发现每次循环都要从内存中读x[i]、y[i]、sum、i、length,经过运算后将sum、i写入内存中,看上图可得无优化版本每次循环总计读8次写2次。
接下来,我们进行-O1级别的优化,然后反汇编(下图):
在这里插入图片描述

当我们进行了-O1级别的优化后,发现i的值被保存在寄存器%eax中,length的值10也没有保存在内存中,经过-O1级别的优化后,和无优化版本相比较我们可以看到每次循环只需要读2次并不需要写内存,因为sum的值保存在%edx中。

接下来进行-O2级别的优化,然后反汇编(下图):
在这里插入图片描述

-O2级别的优化和-O1级别的优化没有太多差别,唯一区别在-O1级别的版本则是在读第二个数y[i]时,就已经准备好相乘了,-O2级别则是两次load后再相乘,因为这段代码关键路径在加法上。乘法对性能影响不大。

(2)比较循环展开次数对性能的影响,如展开 2 次和 3 次,展开次数越多越好吗?

循环展开两次:
在这里插入图片描述

循环展开三次:
在这里插入图片描述
在这里插入图片描述

  上图为循环两次展开无优化级别版本,我们可以发现循环展开两次和不做任何优化相比,循环两次展开将sum的值第一次保存在寄存器%edx中等待第二次运算结束才写入内存,所以循环展开两次比不展开版本有所优化,循环展开三次也会再次减少内存的写入,由于本题给出的代码并没有指出数组x[]和数组y[]的类型,只有当前为int型或者int *时循环展开才有可能提升程序运行效率,而如果数组x[]和数组y[]为float,double,float * ,double *型,则循环展开就并不能提升性能,这种情况下就要进行循坏展开和多路并行的方法来提高程序效率。
  并不是展开次数越多越好,循环展开受吞吐量界限限制,整数乘法的一个周期的时间成为了限制因素,再快不能快过一个周期。

(3)其他可能优化的方法

其他优化方法:
方法一:循环展开+多路并行(展开两次,2路并行)
为了比较是否进行了优化,加入了一个计算时钟周期的函数,对代码进行如下修改:
在这里插入图片描述
运行比较:
在这里插入图片描述

我们可以发现无任何优化版本该段代码运行需要1532个时钟周期,进行了循环展开两次+2路并行的方法只需要1255个时钟周期。

方法二:
重新结合变换:
在这里插入图片描述
运行比较:
在这里插入图片描述

可以看到进行重新结合变换之后,程序性能提高了。

二、题二

题 2:将一个有向图 g 转换成其相应的无向图 g’,无向图中有一条
从顶点 u 到顶点 v 的边,当且仅当原有向图中有一条 u 到 v 或者 v 到
u 的边。有向图 g 由如下的它的邻接矩阵 G 表示:如果 N 是 g 中顶
点的数量,那么 G 是一个 N*N 的矩阵,它的元素是全 0 或者全 1。
设若 g 的顶点命名为 v0,v1,……,vN-1。那么如果有一条从 vi 到
vj 的边,则 G[i][j]值为 1,否则为 0。注意:邻接矩阵对角线上的元
素总是 1,而无向图的邻接矩阵是对称的。仅用一个循环实现这段代
码:

在这里插入图片描述

请结合第 5 章~ 6 章所学的内容,尝试设计一个运行得尽可能快的函
数。

优化方案一:访问一半数据

for(i = 0 ; i < dim ; i++)
   for(j = i+1 ; j < dim ; j++)
    {
		temp = G[j*dim+i]|G[i*dim+j];
		G[i*dim+j]=temp;
		G[j*dim+i]=temp;
	}

  实际本题只需要将邻接矩阵补全为对称矩阵即可,所以当我们访问上三角的时候,可同时处理下三角,没有必要对下三角进行重复的循环修改,这样优化后我们程序访问的数据就可以减少为原来的一半,并且我们将原来的逻辑或改为按位或,这样虽说在每次运算提升的性能不大,但当数据量较大时,我们这种改变会起到较大的性能提升。

优化方案二:使用分块来提高时间局部性
在这里插入图片描述
  在此种方案的优化中,我们在方案一的基础上继续优化,和原始的程序相比,原始程序内层循环主要是按列循环,每次循环不命中概率都会比较大,不命中就会从下一层存储器中读取数据,而当我们采用分块技术,在循环中除了将该块从内存中读到高速缓冲区中会不命中,其它读写时有较大的命中、较低的不命中,而从内存读取速度是远远小于从缓存中读取数据的,所以总体上我们采用分块技术后,程序的性能得到了较大的提升。

  综上:本题我们可以采用读取访问一半数据、逻辑或改为按位或、使用分块来提高时间局部性的方法来优化程序。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值