Sun Studio パフォーマンスアナライザを使用して、プログラムの重要な計算部分を調べます。そして、注意深くループまたはループの入れ子を解析し、オプティマイザが最適なコードを生成するのを抑制している、つまりパフォーマンスを下げているコーディングを除去します。標準以外のコーディングが多いと、移植が困難になり、さらにはコンパイラによる最適化を抑制する可能性があります。
パフォーマンスを上げるためのプログラムの書き直しテクニックに関しては、この章の最後に紹介する、さまざまな参考文献で取り上げられています。ここでは 3 つの代表的なアプローチを説明します。
プログラムの重要な計算作業を囲んでいるループ、あるいはループの入れ子内の入出力は、パフォーマンスを大幅に下げる原因となります。入出力ライブラリで消費される CPU 時間は、そのループで消費される時間のほとんどを占めます。また、入出力はプロセス割り込みの原因ともなるので、プログラムスループットを下げます。可能なかぎり、入出力を計算ループの外に出すことで、入出力ライブラリへの呼び出し回数が大幅に減ります。
副プログラムがループの深い入れ子から呼び出されると、何千回と呼び出される可能性もあります。呼び出しごとの各ルーチン内で消費される時間は少なくても、その合計の影響はかなりのものです。また、副プログラムの呼び出しは、その呼び出しを含むループの最適化を抑制します。 なぜなら、コンパイラは、その呼び出しのレジスタの状態に関して仮定を行うことができないからです。
副プログラム呼び出しの自動インライン化 (-inline=x,y,..z、または -O4 を使用する) は、コンパイラが実際の呼び出しを副プログラム自身で置き換える (副プログラムをループの中に入れる) ための 1 つの方法です。インライン化されるべきルーチンの副プログラムのソースコードは、呼び出し側のルーチンと同じファイルに存在しなければいけません。
副プログラム呼び出しを削減する方法はほかにもあります。
文関数を使用する。呼び出される外部関数が単純な数学関数である場合、その関数を文関数 (あるいは文関数の集合) として書き直すことができます。文関数はコンパイル時にインライン化され、最適化できます。
ループを副プログラムに入れる。つまり、副プログラムを書き換えて、(ループの外で) 呼び出される回数を減らし、呼び出しごとに値のベクトルあるいは配列を操作するようにします。
計算が多いループ内の操作が複雑であると、コンパイラの最適化は抑制される可能性があります。一般的に、算術的な IF と論理的な IF をすべてブロック IF に置き換えるのがよい方法であるとされています。
元のコード: 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) 整理されたコード: 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 を使用すると、コンパイラが最適なコードを生成する機会が多くなるだけでなく、読みやすくなるので、移植性も確保されます。