PCクラスタで利用可能なintelコンパイラでは、「最適化」と「ベクトル化」の2種類の方法でプログラムを効率化することができます。基本的には、コンパイルオプションの指定のみで、ある程度の効果を得ることが出来ますが、自身でプログラム中に指示行を追加することで、さらに効率化を図ることが出来ます。

 
最適化
実行時間の短縮、コードサイズの削減を目的とした処理の効率化を行います。
※弊害として、計算結果が変わることがあります。

 
ベクトル化
ループ中で繰り返される規則的に並んだ配列データ(ベクトルデータと呼びます)の演算に対して、コンパイラがベクトル命令を適用します。

 

【TIPS】ループアンロール
高速化技法の1つ。ループ命令を展開することで、並列実行可能なコードを増やし、高速化を図ります。ただし、ループを展開する分だけコード量が増加します。

do j = 1, n
do k = 1, n
do i = 1, n
a(i,j) = a(i,j) + b(i,k) * (k,j)
enddo
enddo
enddo

do j = 1, n
do k = 1, n, k
do i = 1, n
a(i,j) = a(i,j) + b(i,k) * (k,j)
& + b(i,k+1) * (k+1,j)
& + b(i,k+2) * (k+2,j)
& + b(i,k+3) * (k+3,j)
enddo
enddo
enddo

配列aに対してのロード・ストア命令が4分の1になり、メモリアクセスが減少するため、高速化が期待できます。

【TIPS】ロード・ストア命令
プログラムは、メモリからレジスタという記憶装置へデータを読み込み計算を行います。
 
ロード命令:メモリからレジスタへデータを読み込むこと
ストア命令:レジスタ内のデータをメモリへ書き込むこと
 
を指しています。
 
上記の例では、kのループ数が減少することで、配列aにアクセスする回数が減るため、ロード・ストア命令の回数が減少します。

 

基本的な使用例

ifort -O0 -qopt-report-phase=all -qopt-report=2 source_file

# :最適化レベル
# :コンパイラメッセージ

 

最適化レベル(-Oオプション)

-O0 すべての最適化・ベクトル化を無効にする
-O1 -O2のうち、コードサイズを増大させる最適化を無効にする。ベクトル化を無効にする
-O2 ベクトル化の有効化、最適化(組み込み関数のインライン展開、不変な変数・関数の削除、ループアンロールなど)の実施
-O3 プリフェッチ、ループ変数、パディングなどを行う(-O2よりも実行速度が遅くなる可能性あり)
コンパイル速度も遅くなります

 

最適化レポート出力(-qopt-reportオプション)

コンパイラが行った最適化、ベクトル化の内容やそれらを阻害している要因などのレポートを出力します。
レポートはソースファイル名.optrptというファイル名で出力されます。

 

レポート出力フェーズ指定(-qopt-report-phase)

レポートで出力する内容を指定します。
何も指定しなければ全てのレポートを出力します。

-qopt-report-phase=all 全てのフェーズをレポート。(デフォルト)
-qopt-report-phase=vec ベクトル化に関するフェーズをレポート。
-qopt-report-phase=loop ループの最適化に関するフェ-ズをレポート。
-qopt-report-phase=par 自動並列化に関するフェーズをレポート。
    ※この他にもいくつかのフェーズが存在します。
    ※カンマで区切ることで複数指定することが可能です。(例:-qopt-report-phase=par,vec)

 

レポート出力レベル指定(-qopt-report)

レポートで出力するレベル(どの程度詳細な内容にするか)を指定します。
-qopt-reportで指定できるレベルの上限はフェーズによって異なります。
たとえば、vecフェーズの場合0~5、loopフェーズの場合0~2となります。
上限を超えたレベルを指定した場合、自動的に各フェーズの上限レベルに設定されます。
以下は-qopt-report-phase=vecの場合の例です。

-qopt-report=0 レポートを出力しません。
-qopt-report=1 ベクトル化されたループを出力。
-qopt-report=2 レベル1の内容+ベクトル化されなかったループとその簡単な理由を出力。
-qopt-report=3 レベル2の内容+ベクトル化機能によるループのサマリー情報を出力。(デフォルト)
-qopt-report=4 レベル3の内容+ベクトル化されたループとされなかったループの詳細な情報を出力。
-qopt-report=5 レベル4の内容+判明した依存関係または想定される依存関係の詳細な情報を出力。

 

最適化レポート出力の詳細については以下のページをご覧ください。
-qopt-reportマニュアル
 

指示行の使用について

コンパイラに対する最適化・ベクトル化の「ヒント」や、強制的な最適化・ベクトル化の「指示」をプログラムに埋め込むことができます。指示行は、本来最適化・ベクトル化できない依存関係がある箇所に対しても働くため、結果が変わってしまうことがあります。あくまでユーザの責任で追加する必要があります。また、FortranとCで、書き方がやや異なります。
 

指示行一覧

!DEC$ IVDEP  (Fortran)
#pragma ivdep (C)

依存関係がないというヒントをコンパイラに与えます。
ベクトル化の効果が無いと判断した場合はベクトル化は行いません。

 

!DEC$ vector always  (Fortran)
#pragma vector always (C)

効率性ヒューリスティックを無視します。

 

!DEC$ VECTOR NONTEMPORAL  (Fortran)
#pragma vector nontemporal (C)

ストリーミング・ストアを使用するようにヒントを与えます。

 

!DEC$ VECTOR [UN]ALIGNED  (Fortran)
#pragma vector [un]aligned (C)

アライメントされている[されていない] ことを表明します。

 

!DEC$ NOVECTOR  (Fortran)
#pragma novector (C)

対象ループのベクトル化を無効にします。

 

!DEC$ DISTRIBUTE POINT  (Fortran)
#pragma distribute point (C)

この位置でループを分割するようにヒントを与えます。

 

!DEC$ LOOP COUNT ()  (Fortran)
#pragma loop count () (C)

予測される反復数のヒントを与えます。

 

!DEC$ SIMD  (Fortran)
#pragma simd (C)

ベクトル化を強制します。

 
 

使用例

プログラム作成者にはベクトル化できることが分かっていても、コンパイラでは判断できない場合があります。

 

例えば、次のプログラムですが、

コンパイラは、不明な変数Xにより「依存関係の可能性」を想定し、DO文のベクトル化が妨げられます。
下記のように、SIMD指示行を挿入し、コンパイラにヒントを与えることで、ベクトル化を行うことが可能です。

 

コンパイル時に-qopt-report-phase=vec、-qopt-report=5を指定することで、ベクトル化を阻害する原因となるデータを含んだ、
すべてのベクトル化レポートを出力することが可能です。
基本的には、このレポートを元に指示行を挿入していくことをお勧めします。

 

【TIPS】ベクトル化を阻害する要因
ベクトル化を阻害する要因には以下があります。

 

    ・データの依存関係
    ・関数、サブルーチンの呼び出し
    ・構造体へのアクセス
    ・条件分岐
    ・ループの終了条件が不明
    ・ポインタアクセス

 

さらに知りたい場合は、下記の資料をご覧ください。
閲覧するためには、当センターの利用者番号(アカウント)が必要です。
 

intel Fortranコンパイラマニュアル

intel C++コンパイラマニュアル


 

参考資料

インテルコンパイラー v10 最適化クイック・リファレンス・ガイド(要認証)