深入理解计算机系统第5章笔记
优化程序性能
1.编写高效程序特点:
a)必须选择一组合适的算法和数据结构
要特别警觉,避免使用那些会渐进地产生糟糕性能的算法或编码技术
b)必须编写出编译器能够有效优化以转换成高效可执行代码的源代码
如,用好的风格重写条件操作,使得编译采用条件数据传送
c)利用多核和多处理器并行计算
通过使用例如多个累积变量和重新结合等技术,找到方法提高指令级并行
d)消除循环的低效率
展开循环,降低开销,并且使得进一步的优化成为可能
e)减少过程调用
消除连续的函数调用,在可能时,将计算移到循环外,考虑有选择地妥协程序的模块性以获得更大的效率
f)消除不必要的存储器引用
引入临时变量来保存中间结果,只有在最后的值计算出来时,才将结果存放到数组或全局变量中
2.现代微处理器取得的了不起的功绩之一是:它们采用复杂而奇异的微处理器结构,其中,多条指令可以并行地执行,同时又呈现一 种简单地顺序执行的表象
3.现代微处理器可以在每个时钟周期执行多个操作,而且是乱序的,意思就是指令执行的顺序不一定要与它们在机器程序中的顺序 一致,与第4章研究过的流水线相比,乱序处理器需要更大更复杂的硬件,但是它们能更好地达到更高的指令级并行度
4.通常指令控制单元(ICU)会在当前正在执行的指令很早之前取指,这样它才有足够的时间对指令译码,并把操作发送到执行单元 (EU).不过,当程序遇到分支(jnz/retn等)时,程序有两个可能的前进方向,现代处理器采用了一种称为分支预测的技术,处理器会猜 测是否会选择分支并取指和译码,如果后来发现选错了,会将状态重新设置到分支点的状态,并取指和译码
5.循环展开是一种程序变换,通过增加每次迭代计算的元素的数量,减少循环的迭代次数.编译器可以很容易地执行循环展开,只要 优化级别设置得足够高,许多编译器都能例行公事地做到这一点.用命令行选项”-funroll-loops”调用GCC,会执行循环展开.
循环展开能够从两个方面改程序的性能,下图中psum2函数是一个循环展开的示例.
a)减少了不利操作的数量,如:循环索引计算和条件分支
b)提供了一些方法,可以进一步变化代码,减少整个计算中关键路径上的操作数量
c)编译器可以很容易地执行循环展开,只要优化级别设置得足够高,许多编译器都能例行公事地做到这一点
6.每个运算都是由两个周期计数值来刻画的:一个是延迟,它表示完成运算所需要的总时间;另一个是发射时间,它表示两个连续的 同类型运算之间需要的最小时钟周期数.
7.提高并行性
a)多个累积变量
对于一个可结合和可交换的合并运算来说,比如说整数加法或乘法,我们可以通过将一组合并运算分割成两个或更多的部分,并在
最后合并结果来提高性能(利用功能单元的流水线能力来提高性能)
b)重新结合变换
重新结合变换能够减少计算中关键路径上操作的数量,通过更好地利用功能单元的流水线能力得到更好的性能
8.unix系统提供了一个剖析程序GPROF,它会计算每个函数花费的时间和函数被调用的次数
9.为什么函数调用和递归效率低?
系统每次函数调用都要分配存储空间,并将调用点压栈记录,在函数调用结束后还要释放空间,恢复栈空间,所以函数调用浪费时间 和空间,而递归正是函数自己调用自己,于是效率低