Open MPを用いて並列計算 バグの出現編
前回の記事で並列計算を試みたことを書いた。簡単な並列計算はこれで十分できそうなのだが、私が研究で使っているプログラムがなぜか上手く動かない。
今回はこのプログラムの並列化をするのが目標となる。実際のプログラムは研究内容と関わるため割愛。7重ループを用いたFORTRAN77のプログラムである。
目標:7重ループの最も外側のループのみを並列化。多分このループは独立しているはず。
1. エラーその1
前回のようにとりあえず、プログラムの初めに
program ○○
use omp_lib
implicit double precision(a-h, o-z)
のようにする。(implicit noneを使えというツッコミはとりあえずなしで。)
また、並列化させたい部分に
!$omp parallel
!$omp do
do 50 j = 1, nj
というように元のプログラムに追記していく。
これで実行するとSegmentation faultという始末。。。
解決策1 : スタックサイズの変更
メモリのスタックサイズが足りないためにsegmentation faultとなることは並列計算をするときにはよくあるらしい。とりあえずの解決法として、ターミナルで
ulimit -s unlimited
とすることで解決できる。unlimitedの部分を具体的な数値で指定することもできる。
現在の設定を見るには、
ulimit -a
とすれば良い。
→結果: 計算は回ったものの、数値が発散してしまった。
解決策2 : プログラムの中身の検討
結局はここに戻ってくる。まずは並列化させたいループの初めでデバッグ用のwrite文を追加
do 50 jy = 1,njy
ys=(jy-0.5)*isy
※ここでisy=1
(途中数行省略)
write(6, *) 'debug' , omp_get_thread_num(), jy, ys, isy
こうすると出力は...
(3列目) - 0.5 = (4列目)になるはずなのに、そうはなっていないことがわかった。
これは、各スレッドごとに変数が共有されていて、上書きが生じていることが原因だと推測できる。
・つまり、各スレッドごとに独立した変数を持つように設定すれば良い
調べたところこのようなものが見つかった。NAG万歳。
このページによると、並列計算の開始時に変数の属性を宣言すれば良い。
つまり
!$ omp parallel private(jy,ys)
!$ omp do
というように書けば問題のys, jy を各スレッドで独立に扱うことができる。(他のスレッドと共有させたい場合には private の代わりに shared を用いる)
変数の属性を指定してあげた場合、以下のような出力を得られる。
jy, ys についてはうまく設定できたことがわかる。(但し計算結果は発散)
他の変数についてもprivate属性を設定すれば上手く計算できそうだ。
まとめ
並列計算を導入するときにそのままomp do文を付け足すだけだと、変数が各スレッドで共有されてしまって予期せぬ計算結果が出てしまうことがあるので、それを独立させることが必要!