Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2176401
  • 博文数量: 436
  • 博客积分: 9833
  • 博客等级: 中将
  • 技术积分: 5558
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-29 10:27
文章存档

2013年(47)

2012年(79)

2011年(192)

2010年(118)

分类: Delphi

2012-11-25 13:32:42

Computer Systems A Programmer’s Perspective》读书笔记

5 优化程序性能

这章主要介绍了如何优化程序的执行效率,包括代码的优化,编译器的优化,CPU级别的优化。CPU级别的优化,微指令的概念,功能单元上微指令的并行,程序分支的预测等。

1.编译器优化程序的能力受几个因素限制:要求它们不能改变正确的程序行为;它们对程序的行为、对使用它们的环境了解有限;需要很快的完成编译工作。

2.编译器有时不能使用某些类型的优化,例如存储器别名使用的现象,编译器必须假设不同的指针可能会指向存储器中的同一个位置,因此造成了一个主要妨碍优化的因素。而第二个妨碍优化的因素是函数的调用。如书P324中的示例。

3.一般程序用一种方法来表示程序性能,这种度量标准是每元素的周期数(CPE),它能帮助我们在更详细的级别上理解迭代程序的循环性能。(迭代指执行一遍组成循环的语句块。

4. 通过查阅资料知道了: GCC的运行开关共分为11类,这是类开关从11个方面控制着GCC程序的运行,以达到特定的编译目的。优化开关(Optimization Options) -O1 –O2 –O3 –O0,这些开关分别控制优化的强度,-O3最强。

5.代码移动(code motion):包括识别出要执行多次(例如,在循环里)但是计算结果不会改变的计算,因而我们可以将计算机移动到代码前面的,不会被多次求值的部分。如书P330combine2函数。

6.过程调用会带来相当大的开销,而且妨碍大多数形式的程序优化,因此一般会尽量减少过程调用,同时对于性能至关重要的程序来说,为了速度,经常必须要损害一些模块性和抽象性。P334combine3函数

7.消除不必要的存储器引用,比如我们在循环中要不停的将某个值赋给一个指针,我们可以定义一个变量,现将每次求得的值赋给此变量,最后在把变量的值赋给指针。

8.超标量(superscalar):可以在每个时钟周期执行多个操作,而且是乱序的。

9.现代处理器整体设计主要有两个部分:ICU()EU()。前者负责从存储器总读出指令序列,并根据这些指令序列产生一组针对程序数据的基本操作,后者执行这些操作。处理器框图如书P3375.11

10.ICU,退役单元记录正在进行的处理,并确保它遵守机器级程序的顺序语义。指令解码时,关于指令的信息被放置在一个先进先出的队列中,这个信息会一直保持在队列中,知道两个结果中的一个发生。首先,一旦指令的操作完成了,而多有导致这条指令的分支点也都被确认为预测正确,那么这条指令就可以退役了。如果导致该指令的某个分支点预测错误,这条指令会被清空。任何对程序状态的更新只会在指令退役时才会发生。

11. 指令流水线是为了让计算机和其它电子设备能够加速指令的通过速度(单位时间内被运行的指令数量)而设计的技术。流水线是假设程序运行时有一连串的指令要被运行。大多数单元能够每个时钟周期开始一个新操作,仅有的例外是浮点乘法器和两个除法器。其中两个除法器根本就没有流水线化。

12.有无限资源的操作调度:即假设一个处理器有无限多个功能单元和完美的分支预测,此时其性能就只受功能单元的执行时间和吞吐量,以及程序中的数据相关性限制。

13.资源束缚下的操作调度,如功能单元的数量有限,功能单元流水化程度等,因此处理器必须要有调度策略,程序顺序也就是我们按照严格的顺序来执行机器级程序。

14.使用循环展开技术降低循环开销,循环开销包括计算循环的索引和测试循环条件。

15.在一个IA32处理器上,所有的浮点操作都是以扩展的80位精度执行的,而浮点寄存器也是按照这个格式存储值的。只有当寄存器中的值写入存储器中时,才把它转换成32位或64位格式。

16.剖析程序(UNIX平台):在编译时加上-pg的参数,这样,在执行程序的过程中会产生一个gmon.out文件,然后执行gprof a.out 就可以了。

总结:

(1)  编写高效程序需要两类活动:
第一、我们必须选择一组最好的算法和数据结构
;
第二、我们必须编写出编译器能够有效优化以转换成高效可执行代码的源代码.

(2) 优化程序性能的基本策略:

1.避免限制优化的因素,这样编译器就能产生高效的代码.
2.
消除连续的函数调用.在可能时,将计算移到循环之外.考虑有选择的妥协程序的模块性以获得更大的效率
.
3.
消除不必要的存储器引用.引入临时变量来保存中间结果.只有在最后的值计算出来时,才将结果存放到数组或全局变量中
.
4.
尝试各种与数组代码相对的指针形式
.
5.
通过展开循环降低循环开销
.
6.
通过诸如迭代分隔之类的技术,找到使用流水线的功能单元的方法.

 

未理解的内容:

循环分割里面的示例

对并行的限制

5.73关于处理器的操作调度问题

每元素的周期数怎么来的?

 

阅读(1076) | 评论(1) | 转发(0) |
0

上一篇:2012-11-14

下一篇:如何写读书笔记,要求

给主人留下些什么吧!~~

xuyuanchao_cnu2012-11-25 22:53:30

1.并行的限制包括:寄存器数量----并行度可能超过可用寄存器数量,也就是说不能有太多的程序并发执行。
                  执行时间---完成一个操作所需要的总周期数。并行执行并不代表会同时完成,而只是说前一个程序未完成时其他程序也可以执行,非顺序执行。
                  发射时间---连续的、独立操作之间的周期数
2.循环分割示例:循环分割就是将一个循环n(n为偶数)次的代码分成两部分,一部分是循环0,2,4,6....n,另一部分循环 1.3.5.7....n-1。这个示例里面其实是想执行这样一段代码:x0 = x0 + data;
                x1 =