最適な性能を得るためによく使うコンパイル・オプション

対象 PGI 一般的に使用するオプション fast fastsse

 一般にコンパイルを使用するときの最適化オプションを説明しています。PGI コンパイラを使って実行モジュールが、最速になるように最適化する一般的なオプションの説明です。 (PGI 16.1 以降、Windows 版の C++ コンパイラの提供は廃止されました。)
2016年2月6日更新 Copyright © 株式会社ソフテック

最適な性能を得るためによく使うコンパイル・オプション

 PGI の F77, F2003, C, C++ のコンパイラを使用する際に、性能を最大限最適化するためのオプション(複数のオプションを組み合わせた「セット・オプション」があります。以下は、pgfortran を使用した場合の例ですが、コンパイラのオプションの設定方法は、他の言語コンパイラでも同じです。一般に、デフォルトで指定するオプションは、以下の STEP 1 のものをお使い下さい。

STEP 1 : 性能を最大化する一般的なベース・オプション

pgfortran/pgcc/pgc++ -fast -Minfo test.f 
pgfortran/pgcc/pgc++ -O2 -Minfo test.f 
      (PGI 13.1から -O2 でも -fast と同等な機能オプションとなります)		
あるいは、
pgfortran/pgcc/pgc++ -fast -Mipa=fast,inline -Minfo test.f  (IPA最適化を有効化)

 Linux版のpgc++コマンドは、 PGI 13.1から、OS X版は、PGI 15.1 から。それ以前は、pgcppのみ。
  Windows 版は pgcpp or pgCC コマンドのみ(PGI 16.1以降当該コマンドが廃止されました)
-fast 等の複合オプションの内容を知りたい場合は、-flags オプションを付けて確認する
pgfortran -fastsse -flags

 -fastsse    == -fast
 -fast       Common optimizations; includes -O2 -Munroll=c:1 -Mnoframe -Mlre -Mautoinline
             == -Mvect=sse -Mcache_align -Mflushz -Mpre

 性能を最大化するために、常に、-fastsse あるいは、-fast オプションを付けてコンパイルして下さい。さらに、
-Mipa=inline オプションを追加すると手続き間を含めた自動インライン化が有効となり、性能向上が望めます。特に、C/C++プログラムでは、インライン化は大きな性能向上が期待できます。PGI 7.1 以降では、64ビット用の C/C++ コンパイラの -fast 複合オプション(-fastsse)の中に、-Mautoinline オプションが加わりました。 C/C++ コンパイルで、-fast (-fastsse)を指定すると、自動インラインモードでコンパイルされます。
 もう一つ、C/C++ の場合は、–Msafeptr と言うコマンド・オプションは、ポインタ間でそのメモリ上の場所の重なりが存在しない場合(no pointer aliasing) 、C/C++プログラムの性能を劇的に向上させます。但し、このオプションは、デフォルトでは有効ではありませんので、こうしたポインタ間の alias 依存性がない(重なりがない)場合は、
-Msafeptr オプションを指定するとさらなる最適化が行われます。

PGI 13.1(2013年)から -Oオプションの最適化レベルの一部変更
最適化レベルを指定する -O、-O2 の内容が変更されました。これは、PGI 13.1 から適用されています。以下にその概要を記します。下線部分が従来のものとの変更点です。

  • -O0 は、レベル0 であり、最適化を行わない。個々の言語文に対して基本ブロックが生成される。
  • -O1 は、レベル1 であり、局所最適化を行う。基本ブロックのスケジューリングが行われる。またレジスタ割り当て最適化も実施される。
  • -O は、レベルが指定されない場合、以下のレベル 2 グローバル最適化を行う。これには、従来のスカラ最適化、導入変数の削除や問題のないループの移動等の最適化を含む。ただし、SIMD ベクトル化は行わない。
  • -O2 は、レベル2 であり、グローバル最適化を行う。このレベルは、全てのレベル1局所最適化、上記-Oオプションで説明したレベル2グローバル最適化が実施される。これに加え、SIMD コード生成やキャッシュ整列、部分的な冗長性排除等の高度な最適化も実施する。(従来の -fastsse 機能を加えた意味合いとなる)
  • -O3 は、レベル3 であり、アグレッシブなグローバル最適化を行います。全てのレベル 1, 2 の最適化だけでなく、効果のあるなしに関わらず、スカラの置き換え、より積極的な最適化を行います。
  • -O4 レベル4 であり、全てのレベル 1, 2, 3 の最適化だけでなく、浮動小数点演算式の中で不変変数に対する巻上げ最適化を行う。
pgcc/pgc++ -fast -Mipa=fast,inline -Msmartalloc -Minfo test.c (test.cpp)
  Linux版のpgc++コマンドは、 PGI 13.1から、OS X版は、PGI 15.1 から。それ以前は、pgcppのみ。
  Windows 版は pgcpp or pgCC コマンドのみ(PGI 16.1以降コマンドが廃止されました)

 C++プログラム においては、特にインライン展開は重要であるため、-Mipa=inline オプションを使用しない場合は、明示的に自動インライン化を行うための -Minline=levels:10 オプションを常に使用することを強く推奨します。また、 --no_exceptions は、例外処理を無効にするオプションですが、これを指定すると性能向上する場合が多いです。(なお、この --no_exceptions を伴ってコンパイルしたプログラム自体が例外処理を行っている場合は、実行時にエラーとなりますのでご注意ください) PGI 11.0以降、C++コンパイラは、低コスト例外処理のハンドリング(--zc_eh)をデフォルトとしました。C/C++ プログラムに対しては、-Msmartalloc (Linux上のみ)も有効です。これは、最適化されたメモリ割付機能を使用することを指示するものです。

pgc++  -fast -Minline=levels:10 ---no_exceptions -Minfo test.cpp
  Linux版のpgc++コマンドは、 PGI 13.1から、OS X版は、PGI 15.1 から。それ以前は、pgcppのみ。
  Windows 版は pgcpp or pgCC コマンドのみ(PGI 16.1以降コマンドが廃止されました)
  • -fast、-fast オプションは、以下のオプションを組み合わせたセット・オプションです。

-fast : -O2 -Munroll=c:1 -Mnoframe -Mlre –Mpre -Mautoinline
-fastsse : -fast -Mvect=sse -Mscalarsse -Mcache_align -Mflushz

なお、このオプションの中で、 -Mlre オプションは、loop-carried redundant removal と言う最適化手法です。loop-carried とは、ループ iteration 処理内と言う意味で、この中で共通数式(冗長数式)あるいは冗長な配列の参照を削除する最適化となります。たまに、この高度な最適化によって、数値結果に差異が生じる場合があります。この場合は、以下のようにして、-Mlre の最適化のみを抑止することが可能です。-fastsse の後に -Mlre=noassoc を指定することにより、-Mlre 最適化が抑止されます。同様に、-Mpreオプションも冗長演算部の削除を行うものですが、-Mnopreによって抑止されます。

  pgfortran -fastsse -Mlre=noassoc ....

※PGI 7.0 以降の 64ビットCPUターゲットに対するコンパイル環境
-fast オプションは、従来の -fastsseオプションと同じ機能を有するオプションに変更しました。従来の -fast と等価な機能として、-nfast と言うオプションが新設されました。

※PGI 7.1 以降の 64ビットCPUターゲットに対するコンパイル環境
C/C++ コンパイラの -fast 複合オプションの中に、-Mautoinline オプションが加わりました。

  • -Mipa=fast オプションは、内部手続き(関数)間の各種グローバルな最適化を 1 パスで行うためのオプションです。なお、このオプションを指定して作成されるオブジェクト・ファイルのサイズは大きくなります。fast フラグは、-Mipa=align,arg,const,f90ptr,shape,globals,localarg,ptr を組み合わせたフラグ・セットです。
  • -Mipa=inline オプションは、インライン対象となるサブルーチン、あるいは関数を探し、これらを呼び出す(call)ブロック内に自動インライン化するためのオプションです。特に、IPA 最適化の中でこのオプション・フラグを有効化した場合、全ての手続き間(C/C++の場合は、複数のソースファイル間)でインライン対象となる関数等を検出し、インライン化を行います。後述の -Minline オプションは、さらに、明示的かつ厳格にインライン対象を指示するために使用するオプションとなります。
  • -Minline オプションは、明示的、かつ細かな指示を行うためのインライン展開のオプションです。現在は、
    -Mipa=inline オプションによって手続き間のインラインが可能であるため、こちらで代用することが多いですが、-Mipa オプションを使用しない場合のインライン展開は、-Minline オプションによって行います。
  • -Mautoinline[=levels:n,mazsize:n,totalsize:n] オプションは、C/C++ルーチンをインライン化するように、コンパイラに指示するオプションです。PGI 2010 (10.0)以降の C/C++ コンパイラ専用のオプションです。コンパイル・オプション –O2 (-fast) を指定した際 –Mautoinline は有効化されますが、以下のパラメータを細かく指定する場合は明示的にオプションリストに追加して下さい。
    • levels:n は、インラインを行うレベル階層を最大 n まで行うことを指示。デフォルトは10 。
    • maxsize:n は、n サイズを超える関数のインラインを行わない。デフォルトは 100。
    • totalsize:n は、インライン h 対象が、n サイズ時にインラインを止めることを指示。 デフォルトは800。

情報

上記の -fast あるいは、-Mipa オプションに関してはコンパイル時だけでなく、リンク時においても指定する必要があります。特に Makefile 等で、コンパイルフェーズとリンクフェーズを分けて行う場合は、リンケージのオプションにも同じように指定してください。リンク時において、上記のオプションを付けない場合、こちらに示すようなエラーが発生します

STEP 2 : STEP 1 の次にさらに付加するオプション

pgfortran -fast -Mipa=fast -O3 -Mvect=prefetch=d:8 -Minfo test.f 
  • -O3 オプションは、-O2 よりもアグレッシブな最適化を行いますが、コード特性により常に高速化が図られると言うわけではありません。 -fast より後に記述してください。 -fast 系のセットオプションに内在する -O2 を上書きします。
  • -O4 オプションは、PGI 7.0 から新設されました。O4 レベルの最適化は、浮動小数点演算式の中で不変変数に対する巻上げ最適化を行うようになります。PGI 7.1 では、algebraic transformationとレジスタ・アロケーション最適化が追加されました。
  • -Mvect=prefetch=d:<p>,n:<q> オプションは、ベクトル化の最適化において、メモリ階層でのキャッシュ上へのプリフェッチを極力行うためのオプションです。性能が向上する場合が多いです。このオプションの詳細については、チュートリアル「ソフトウェア・プリフェッチで性能向上」をご覧ください。

情報

性能最適化のオプションを使い分ける際は、必ず、それぞれのオプションを指定して、性能を評価してください。PGI に限らず、コンパイラ共通の特性により、場合によっては遅くなる場合もあるため、一番最速なオプションを評価し使用して下さい。

メモリ・アロケーション、Hugeページの使用、TLBエントリの最適化

【プロセッサのTLBエントリ数のチューニング オプション】
  pgcc/pgc++/pgfortran -fast -Msmartalloc=huge:448  {source_file} 
【オプション】
  -M[no]smartalloc[=huge|huge:<n>|hugebss] 
  • -Msmartalloc オプション自体(サブオプションなしの指定方法)は、メインルーチン中に最適化された mallopt ルーチンのコールを加えます。これは、PGI 6.2 以降に新設されたものですが、Core2/Barcelona 等の新しいプロセッサ以外の従来のプロセッサに対しても有効です。これを有効にするためには、Fortran、C、C++の「メインプログラム」を含むファイルをコンパイルする際に、このオプ ションを付する必要がある。デフォルトは、-Mnosmartalloc。
  • PGI 7.1 以降、-Msmartalloc オプションは、Linux 並びに Windows 上での large TLBs をサポートするために強化されました。このオプションは、最適な malloc ルーチンを有効にするために、メインプログラムをコンパイルする際に使用することが必要です。
  • サブ・オプション huge は、シングルプログラムで使用される大きな 2MB ページを有効にするために指定します。これは、実行するために必要な TLB エントリ数を削減する効果があります。このオプションは、AMD の Barcelona やインテル(R)の Core2 システムで特に有効です。古いプロセッサ・アーキテクチャでは、TLB エントリの数が少ないため、大きな効果は期待できない可能性があります。 サポートするサブ・オプションは、以下のとおりです。

huge : huge page のランタイムライブラリをリンクします
huge:<n> : huge page のランタイムライブラリをリンクし、使用されるページの数の限度を n に設定します
hugebss : huge page の中に BSS セクションを置きます

huge サブ・オプションは、それ自身、必要とされる huge page の数をアロケートしようとします。Huge page の数は、:n サブ・オプションで制限を設けることができ、あるいは、環境変数 PGI_HUGE_SIZE でも設定できます。hugebss は、プログラムの初期化されていないデータセクションを huge page の中に置きます。

情報

上記の -Msmartalloc オプションは、コンパイル時とリンク時の両方で指定する必要があります。特に Makefile 等で、コンパイルフェーズとリンクフェーズを分けて行う場合は、どちらにも本オプション指定してください。

その他の有効なオプション(明示的に行う関数・サブプログラムのインライン展開)

【インライン展開される側のソースライン数 約1000行まで許す】
  pgcc/pgc++/pgfortran -fast -Minline=size:1000 {source_file} 
  
【インライン展開される多重レベル数】
  pgcc/pgc++/pgfortran -fast -Minline=levels:3 {source_file}
  
【複数のサブオプションを組み合わせる場合】
  pgcc/pgc++/pgfortran -fast -Minline=size:1000,levels:3 {source_file}
  • 関数・サブプログラムをコールする親プログラムの中に、これらをインライン展開することは、コール・オーバーヘッドを削減する上で、性能が向上する場合があります。これは、特に C 言語系のプログラムにおいて有効となります。PGI のインライン展開機能を指示するサブオプションは、上記に示した以外にもありますが、ここでは、よく使用する二つのサブオプションを紹介します。
  • -Minline=size:number オプションは、インライン展開の対象となる関数・サブプログラムの最大ソース行数 (number) を指示するものです。
  • -Minline=levels:number オプションは、インライン展開される関数のレベル数を指示するものです。デフォルトは、1 です。これは、インライン展開された関数・サブプログラム自体がさらにその上位で展開される段数を指定するものです。
その他のインライン展開を行うための機能フラグは、以下のとおりです。インライン対象となる関数名を指定することができます。
-Minline[=[lib:]<inlib> | [name:]<func>  | except:<func>  | size:<n>  | levels:<n> ] 
						
[lib:]<inlib>             "inlib"ライブラリの中の関数を抽出してインライン展開する
[name:]<func>        関数"func"をインライン展開する
except:<func>         関数"func"をインライン展開しない
size:<n>                 インライン対象のソース行数 n 以下のものをインライン展開
levels:<n>               インライン展開される関数のレベル数

高度な最適化(コンパイラ・ディレクティブを使用する)

コンパイラのオプションだけではなく、ソースプログラムに直接コンパイラへの最適化指示を行うためのディレクティブも用意されています。以下の例は、メモリ階層でのデータ・プリフェッチを明示的に指示するための例です。

     real*8 a(m,n), b(n,p), c(m,p), arow(n)
...
      do j = 1, p
cmem$ prefetch arow(1),b(1,j)
cmem$ prefetch  arow(5),b(5,j)
cmem$ prefetch  arow(9),b(9,j)
        do k = 1, n, 4
cmem$ prefetch  arow(k+12),b(k+12,j)
          c(i,j) = c(i,j) + arow(k) * b(k,j)
          c(i,j) = c(i,j) + arow(k+1) * b(k+1,j)
          c(i,j) = c(i,j) + arow(k+2) * b(k+2,j)
          c(i,j) = c(i,j) + arow(k+3) * b(k+3,j)
        enddo
      enddo