プログラムの並列化について
プログラムの並列化とは
並列化には、以下のような方法があります。
- 自動並列化 コンパイラによって並列化可能な処理を自動的に並列化します。
- OpenMP 複数のCPUを持つ1台のコンピュータ内で並列化する規格です。
- MPI 複数のコンピュータを接続した大規模な並列化を行ないます。
コンパイラが自動的に並列化可能な処理を判断しますので、利用者はこれまでに書いたプログラムをそのままで並列化することが可能です。 ただし、簡単に並列化が可能ですが、並列度の高いプログラムができるとは限りません。 並列度を高くすると、かえって処理時間が長くなる場合もあります。
OpenMPは、SMP(複数のCPUを持つ1台のコンピュータ)上で並列化を行う規格で、Fortran, C, C++言語のプログラムで利用することができます。 プログラムにOpenMPの並列化指示を入れることで、並列化を行ないます。 OpenMP並列化指示の無いプログラムは、並列化できません。 複数のコンピュータを使った並列化はできません。
MPI(Message Passing Interface)ライブラリは、複数の計算機と通信を行ない、並列処理を行うことができます。 複数の計算ノードを使った大規模な並列化が可能です。 ただし、プログラムの構造や規模によって、多くのCPUを使っても早くなるとは限りません。 MPIを利用するには、プログラムに明示的に並列化指示を入れる必要があります。 MPIの指示が無いプログラムは、並列化できません。
プログラムの構造やデータによって、並列処理の効率が違います。
並列化は、複数のCPUで、同時に複数の処理を行うことで、プログラムの実行時間を短するプログラミング手法です。 プログラムが、独立した処理に分割できない場合は、並列化の効率が悪く時間も短縮すす事ができません。
並列度(分割処理の数)を大きくした場合に、「処理を分割し、それぞれのCPU(メモリ)に処理命令とデータを分配し、計算した結果を統合する」といった、計算処理以外の通信部分が大きくなり、処理速度を低下させる場合もありますので、どれくらいの並列度が効率的かを確認し、CPU資源を有効に使うようにしてください。
並列化プログラムの再現性について
浮動小数点の丸め誤差、加算の演算順序によって結果が変わるなどが原因です。
必要とする有効桁数以下を無視するなどの対策が必要です。
Q. OpenMPについて質問です。
OpenMPのホームページ http://www.openmp.org/ から取ってきたサンプルプログラムを使って並列化の実験をしました。
並列なしでシングルプロセッサーでこのプログラムを実行すると2回繰り返しても同じ結果が得られました。
今度は並列4プロセッサーで実行すると2回繰り返して違う結果が得られました。
どうして並列化すると再現性が無くなるのでしょうか.
コンパイラーオプション、実行時の環境変数などはどう設定するのでしょう?
A.
1. 浮動小数点演算について
並列化に関する議論の前に、計算機の浮動小数点演算についてお話いたします。
例:1のプログラムをご覧下さい。
単純な足し算をするプログラムであり、res0とres1は足し合わせる順番が異なるだけです。本来であれば結果は同一になるはずですが、異なっています。
計算機における浮動小数点演算では、丸め誤差が生じるためです。
※この例で使ったプログラムでは、Intel ifort コンパイラの場合、結果が同じ(ただし、表示桁数が少ない)となった。 ここでは、丸め誤差の説明のため、g77 の結果で説明していますが、Intel コンパイラでも丸め誤差は生じます。
問題になるのは、結果の有効桁をどこまで要求するかということです。 (例えばkmオーダの議論で、mmやμmの差は通常考慮しません)
2. 並列化されているプログラムの場合
並列化の最も簡単な例は、並列スレッドで計算した部分和を加算し総和を求めるというものがあります。 www.openmp.orgのmd.fはその典型です。
並列スレッドで部分和を計算し、総和を求めるプログラムでは演算順序がタイミングにより変わります。(基本的に、制御がOSとライブラリに任されているためです。)つまり、上記1.と同様のことが起こっています。厳密な精度を求める場合は、プログラム内で工夫をする、もしくは並列化が不可能な場合もあります。
並列化されたプログラム、商用アプリケーションは多数存在しますが、必要としている有効桁まで結果が合っていればそれ以下は考慮しないことが慣例です。
まず、ご利用の環境で計算結果の差がどの程度のオーダで発生しているかをご確認ください。
入力パラメータが同一にもかかわらず、結果の差が許容範囲内にない場合は(桁が全く異なる等)お知らせください。
例:1 $ cat a.f implicit none real*4 a, b, c, d, res0, res1 parameter(a=0.0004,b=1.0000,c=0.0004,d=0.0002) res0 = (( a + b ) + c ) + d res1 = (( d + a ) + c ) + b write(*,*) res0 write(*,*) res1 end $ g77 -ffree-form -o a a.f $ ./a 1.00099993 1.00100005 ※ Intel ifort や gfortran コンパイラの出力は、res0, res1 が同じ。 ただし、表示桁数が少ない。 $ ifort -free -o a a.f $ ./a 1.001000 1.001000 $ gfortran -ffree-form -o a a.f $ ./a 1.001000 1.001000
並列化プログラムのコンパイル、計算機への投入について
マニュアルのページの 高速演算システム操作マニュアル(計算利用編) にサンプルのスクリプトなどと併せてやり方を掲載しておりますので、まずはご確認ください。