深入理解计算机系统:程序性能优化

首先需要说明的是编译器的优化是在保证正确的情况下进行的,在正确的基础之上再考虑性能的优化。

1、有可能造成的障碍优化因素

并不是所有的程序编译器都能够帮我们进行优化,编译器在进行优化时也需要对环境进行判断,有两个因素是影响编译器优化的。

  1.1、编译器必须假设不同的指针可能指向存储器的同一位置,这样做是为了防止二义性。

  1.2、有时候函数可能修改全局变量,当多次调用函数时,编译器不敢冒然的对函数进行优化。

2、表示程序的性能,一般用每元素周期数(CPE),其实就是,执行的周期数与数的范围n所成的正比例关系的斜率。N和周期数可以画出一条直线,这条直线的斜率就是CPE

3、具体进行优化的策略

  3.1、消除循环的低效率:固定不变的东西提出循环,减少每次循环都计算相同的内容,这一点对性能的提升时很明显的。

  3.2、减少过程的调用:消除循环中的过程调用,可通过函数提前得到需要操作的对象,这样会提高速度,但是模块性降低。

  3.3、消除不必要的存储器引用:函数参数为指针时,如果循环中用到指针,需要对指针的地址进行访问,则每一次访问都会进行取指,执行,存储等操作,这时最好在函数中声明临时变量,在循环中用临时变量,这样直接就可以对变量进行赋值,循环结束之后,再将结果赋给指针地址。

  3.4、处理器优化

  现代微处理器取得的了不起的功绩之一是:采用复杂而奇异的微处理器结构,其中,多条指令可以并行的执行,同时又呈现出一种简单的顺序执行指令的表象。

  现在一些高端处理器,工业界成为超标量,他的设计主要有两个部分:指令控制单元和执行单元。

  指令控制单元,从指令高速缓存中取出指令,对指令的取值、计算、存储都是通过调用执行单元完成,当遇到分支时,会进行分支预测,提前执行分支内容,甚至提前于判断的结果,当得到结果时,如果判断正确,继续执行,不正确则返回判断点,继续执行。

  执行单元,主要包括功能单元和数据高速缓存器,功能单元中有加法寄存器、乘除寄存器、加载、存储等功能,直接和数据高速缓存交互。描述功能单元的运算周期有两个参数,一个是延迟,就是执行加法或乘法的总时间,另一个是发射时间,两个连续同类型运算之间的最小时钟周期,其实是流水线的间隔。

 处理器操作的抽象模型:

 For (int i=0;i<5;i++)

         Acc = acc *I;

 以上是一个循环,在处理器对循环进行操作的时候,会将I,acc等值存入到寄存器中,这样寄存器可以分成四类:只读、只写、局部和循环有关的寄存器,其中循环寄存器之间的操作链决定了限制性能的数据相关。

 循环1acc *  |  i+

 循环2acc *  |  i+

 循环3acc *  |  i+

 在这个例子中,存放acci的寄存器是循环寄存器,下一个循环的执行需要执行完acc*i+,因此决定性能的就是这两个操作,其中*的周期长,位于关键路径上,因此按照他算。

 3.5、循环展开

 3.5.1、通过增加每次迭代计算的元素的数量,减少循环的迭代次数。

 3.5.2、一次计算两个数的和,或三个数的和。这种展开对正数有用,而对浮点数没用。对于正数来说多个连加可以合并,看成一个加,对于浮点数来说,处理器的处理还是单个进行加。

 3.6、提高并行性

 3.6.1在循环中增加循环变量,一个变量存储奇数的和,另一个存储偶数的和,然后相加,这样,相当于另个乘法并行执行,对于提高浮点数的性能也有帮助。

 3.6.2

 For (int i=0;i<5;i++)

         Acc = acc *(a[i] * a[i+1]);

 以上的代码看似简单,其实对于性能提升也很大,关键在于循环中括号的位置,后面的那个乘法结果并没有存储在循环寄存器中,他与循环无关,因此真正在循环链上的只有一个乘法操作。

 在循环优化中,最关键的是看循环链上及关键路径上的运算量有没有减少,只要将循环量上的循环量运算操作减少,性能就能优化。

 3.7、遇到问题选择适当的算法和数据结构。

4、以上的解决方式是理论,在实际中还有一些限制因素。

 4.1、  寄存器溢出,如果并行度超过了寄存器数量,处理器会将临时值放到栈中,性能急剧下降。

 4.2、  分支预测错误的惩罚,处理器会进行分支预测,提前执行分之内容,但是一旦错误,就会进行相应的回撤,需要大量的始终周期。

注意:不要过分关心可预测的分支;

书写适合用条件传送实现的代码,对于任意性很大的数据,处理器也是瞎蒙,这时可用条件操作代替,即? :操作符。

5、存储器的加载:

有时候加载也会影响程序的性能,关于加载的影响,最根本的是看加载和存储的是否是同一位置,如果位置不同,则可并发执行,当时当操作的地址相同时,需要等待加载存储完成之后,再进行下一个循环的加载存储,可能成为循环的关键路径。

6、程序的性能调试,用到了工具gprof命令。详细内容见:http://blog.sina.com.cn/s/blog_6a5e34ad0100xwno.html

7、Amdahl定律:

 描述:系统优化某部件所获得的系统性能的改善程度,取决于该部件被使用的频率,或所占总执行时间的比例。

  主要应用:改善“系统瓶颈”性能。

  Amdahl定律定义了加速比:

  加速比=采用改进措施后性能/未采用改进措施前的性能=未采用改进措施前执行某任务时间/采用改进措施后执行某任务的时间

  n个处理器加速因子S=n/[1+(n-1)f]:f为非平行百分比,n越大,S不能超过1/f

  概括地讲,阿姆达尔定律并不否定并行计算的价值。相反,它提醒我们要想达到并行性能就必须考虑整个程序。

posted @ 2011-12-02 10:31  magicdog  阅读(1166)  评论(0)    收藏  举报