以下内容整理自《Software Optimization Guide for AMD64 Processors》。转载请注明出处:http://blog.csdn.net/qingheuestc, by EinsteinInIct。
1,在单精度浮点变量后面加上f,可以显示的通知编译器不把单精度当多双精度来处理。(除非内存非常紧张,否则最好不要用)
2,当用数组模式进行访问时,使用数组名比使用指针能够给编译器提供更多的信息进行优化。当然有的时候并非如此,因此要通过test来看哪种方法更合适。
3,对于一些长度确定的短小的循环,考虑将其展开。不但可以减小分支预测等的开销,而且可以充分利用register进行优化,消除数据依赖性等。
4,在符合分支条件中,选择合适的表达式顺序以充分利用short circuit特性。(需要严密的测试性能差异)
5,If语句中,考虑两点:
a)逻辑表达式的短路特性
b)将经常发生的事情放在附近
6,动态内存分配时,注意对地址进行对齐。
7,在循环中,利用register来避免不必要的store-to-load开销(解除raw依赖)。
8,匹配store和load size(??)
9,在没有连续或者近似连续的case的地方,用if,else来替代switch。另外,在switch中,按照可能性的顺序从高到低排列case,可以减小分支比较的次数。
10,使用函数原型,对于static的函数加上static修饰符,有时可以给编译器提供更多的信息以供优化。
11,养成使用const修饰符的习惯,不但可以是代码更加robust,而且可以方便编译器进行优化。对于使用的数据,修饰信息越多,对于代码的理解越到位,也更加方便进行优化。
12,消除循环中的不变量,不仅是数据,也包括控制流。从最内层循环一直往外进行优化。
13,利用循环展开等方法尽量让流水线,寄存器等更加饱满,以充分利用宝贵资源。
14,将大的表达式拆分成小的表达式以避免重复计算,因为ansi中的一些标准禁止编译器进行拆分。
15,对于结构体中的变量的声明,按照size从大到小的顺序排列并进行padding,这样,他们就能够很好的对齐(??)。而且结构体的数组也能够很好的对齐。对于局部变量的声明,也按照从大到小的顺序进行定义。
16,当一个表达式中有多个整数除法时,以乘代除,提高速度。
17,避免在一个函数内部频繁的对指针进行解引用。因为指针可能存在别名的问题,编译器不敢贸然进行优化。这样,频繁的解引用有可能造成访存量增加而成为瓶颈。如果必要,可以在函数开头将指针指向的内容拷贝到局部变量中来,这样或许会充分利用register。
18,对于数组的索引,使用ptrdiff_t不但可以提高可移植性,而且通常会得到更好的性能。
19,考虑整数操作数的符号对性能的影响,选择合适的数据类型。Amd64中,signed integer 到float的转换比unsigned integer到float的转换更快。
a) Unsigned types
i. Division and remainders
ii. Loop counters
iii. Array indexing
b) Signed types
i. Integer to floating pointconversion
20,加速浮点除和开方运算
如果应用中有大量浮点除或者开方运算,可以考虑通过inline汇编用sse指令或3Dnow来实现,或者是用支持sse和3Dnow的编译器。亦或者通过设置X87的精度来提高速度。
21,对于32位的浮点到整数转换,有专门的3Dnow指令PF2ID来实现。对于double to int,可以用以下方法:#define DOUBLE2INT(i, d) \
{double t = ((d) +6755399441055744.0); i = *((int *)(&t));}
double x;
int i;
DOUBLE2INT(i,x);
22,
When using ld, include the followingcommand line option:
-Bsymbolic
If using gcc to build a library, add this option to the command-line:
-Wl,-Bsymbolic
Key Optimization
1,避免内存尺寸的不匹配(比如写两个4字节的连续内存,然后读开始地址的8字节数据抑或相反),应该让读和写的尺寸都一样大。这样方便进行forwarding,否则此时的延迟是非常大的。因为不但要写,还要读。解决方案是利用cpu中已有的指令和存储单元(register),保证数据读写尺寸的一致性。
2,保证数据对象是自然对齐(地址是尺寸的倍数)的(很重要)。
3,对于一个快速通用的内存拷贝,调用ms或者gcc工具提供的memcpy(),该函数对各种blocksize和alignment都做了优化。对于小的数据块,使用inline汇编:load,load,store,store