现在的位置: 首页 > 综合 > 正文

程序性能优化的常用技术

2012年12月02日 ⁄ 综合 ⁄ 共 1566字 ⁄ 字号 评论关闭

程序性能优化的常用技术

 

 

Version 1.0

2008-4-28

以下内容主要摘自《程序设计方法与优化》(西交大出版)。

l        
优化分类:

Ø        
算法级优化,

Ø        
语音级优化,如减少需要执行的语句,指针移动代替内存copy,初始化操作放到开始等

Ø        
指令级优化,常针对关键部分进行。

l        
优化内容:

1,  代码替换:使用周期短的指令代替周期长的指令;

2,  分支预测,指令预读:Pentium以上CPU执行指令前会预读一些指令,有分支会造成预读失效;

3,  并行指令;

4,  MMX指令,一次可处理8字节的数据;

l        
CC++基本优化方法:

1、    
自加、自减指令有利于编译器生成高效代码,a=a-n会比a-=n多出几条汇编指令;

2、    
使用位移代替*/,如a=a*9
>> a=(a<<3)+a

3、    
减少运算强度,如用a&7代替a%8

4、    
提取公共子表达式:e=b*c/d; f=b/d*a     >>   t=b/d; e=c*t; f=a*t;

5、    
避免整数除法——除法是最慢的;

6、    
将不依赖循环的操作提到循环之外;

7、    
内存换速度,如将某些复杂运算的结果存储起来,使用时直接查表;

8、    
数据类型,32位快于16位或者8位;无符号型常用于除法余数、循环计数、数组下标,有符合型常用于浮点型的转换;

9、    
数组类型较指针有利于编译器执行优化;

10、  使用for(;;)代替while(1),前者只生成一条汇编代码,而后者是好几条,且有寄存器操作;

11、  分解小循环以利用CPU指令缓存,for(i=0;i<4;i++){r[i]=m[i]*v[i]}的效率不如去掉循环直接写4条语句;

一个测试数据:VC6Debug版未分解版本耗时2.3秒,分解版本1.4秒;Release版未分解时耗时0.7秒,分解版本耗时0秒;

12、  避免读写依赖——数据必须正确写入后才能再次读取,如:

For(u_int k=1; k<10;
k++){

       X[k] = x[k-1]+y[k];            //x[k]依赖x[k-1],而后者在不断变化

}

更改为:

T=x[0];

For(u_int k=1; k<10;
k++){

       T += y[k];

       X[k]=t;

}

VC6下的测试,Debug版两种方式性能基本无差别,大概都是4秒;Release版后者比前者快,如前者需1.7秒,后者只需0.7秒;

13、  多算式融合,如将a[i];i++ >> a[i++],前者可能需要读两次i而后者只需一次;

14、  优化switchswitch可能转化为跳转表或比较链/数(case使用小而连续的整数可保证它转化为跳转表);将最可能的值放到前面有利于比较链形式时的性能——对多if判断也应这样做;

15、  注意指针参数,编译器难以对指针参数进行优化,建议多使用本地变量而避免频繁使用指针变量;

16、  避免C++中临时对象的产生,构函中使用初始化列表而非传统赋值,避免内部对象的默认构造;

17、  使用staticinline

18、  使用指针及引用代替结构赋值;

19、  I/O,提供文件I/O的方法——内存缓冲与内存映射文件;

 

一些编程风格建议:

l        
使用初始化列表而不是在构函中赋值,并尽量使其顺序与成员定义的顺序一致,这可以避免某些编译器的告警;

l        
基类中定义的virtual函数,子类中override时给函数也加上virtual关键字,这样代码读起来比较方便;

l        
文件最后留几个空行,以避免某些编译器的告警;

l        
注意文件名大小写;

l        
编译宏定义写到文件中尽可能靠前的位置;

 

 

抱歉!评论已关闭.