使用 Sun Studio 性能分析器可确定程序的关键计算部分。 然后仔细分析循环或循环嵌套,消除有可能抑制优化器生成优化代码或者不然会降低性能的编码。有许多影响可移植性的非标准编码习惯也可能会抑制编译器的优化。
本章最后所列的某些参考书籍更为详细地论述了用于提高性能的重编程技巧。有三种主要方法值得在此提出:
包含程序主要计算工作的循环或循环嵌套中的 I/O 会严重降低性能。花在 I/O 库上的 CPU 时间数量可能构成了循环所用时间的主要部分。(I/O 还会引起进程中断,因而降低程序处理能力。)尽可能将 I/O 移出计算循环,可以大大减少 I/O 库的调用次数。
循环嵌套深层调用的子程序可能会被调用数千次。即使每次调用花在每个例程上的时间很少,但累加效果却可能会很大。另外,由于编译器在调用期间不能对寄存器状态作出假设,所以子程序调用会抑制包含这些调用的循环的优化。
子程序调用的自动内联(使用 -inline=x,y,..z 或 -O4)是一种让编译器用子程序本身替换实际调用的方法(即将子程序拉到循环中)。要内联的例程的子程序源代码必须与调用例程存在于相同的文件中。
还有其他几种消除子程序调用的方法:
使用语句函数。如果正在调用的外部函数是一个简单的数学函数,可以将该函数改写为语句函数或语句函数集。语句函数采用内联编译,可以进行优化。
将循环推到子程序中。即改写子程序,减少其调用次数(循环外),并使其在每次调用时能对向量或数组值进行操作。
计算密集型循环内的复杂条件操作对编译器进行的优化尝试具有很强的抑制作用。一般而言,消除所有算术和逻辑 IF 操作而代之以块 IF 操作是一条很好的规则,应予以遵守:
Original Code: IF(A(I)-DELTA) 10,10,11 10 XA(I) = XB(I)*B(I,I) XY(I) = XA(I) - A(I) GOTO 13 11 XA(I) = Z(I) XY(I) = Z(I) IF(QZDATA.LT.0.) GOTO 12 ICNT = ICNT + 1 ROX(ICNT) = XA(I)-DELTA/2. 12 SUM = SUM + X(I) 13 SUM = SUM + XA(I) Untangled Code: IF(A(I).LE.DELTA) THEN XA(I) = XB(I)*B(I,I) XY(I) = XA(I) - A(I) ELSE XA(I) = Z(I) XY(I) = Z(I) IF(QZDATA.GE.0.) THEN ICNT = ICNT + 1 ROX(ICNT) = XA(I)-DELTA/2. ENDIF SUM = SUM + X(I) ENDIF SUM = SUM + XA(I) |
使用块 IF 不仅可以提高编译器生成优化代码的机会,而且可以增强可读性并确保可移植性。