並列計算いろは (その6)


前回に引き続き,今回は記述子並び3)REDUCTION(xxx:yyy),4)IF(xxx)について説明します.

REDUCTIN
REDUCTION(縮約)演算とは,図1のdoループで,配列aの各要素の合計sを求めるように,配列全体の値を使用して,1つのスカラーの値を求める場合をいいます.代表的な縮約演算としてはこの他に,
     内積演算 s=s+a(i)*b(i)
最大値(最小値)を求める計算
sai=max(sai,a(i))
などが考えられます.さて図1の合計計算で,sはループを1回通過するたびに,値が変わりますから,このままでは並列性はありません.この縮約演算で変数sをPRIVATE変数とみなし,2つのスレッドで並列化することを考えてみましょう.この場合プログラムの流れは図2のようになります.
       
                 スレッド1     スレッド2

  図1 シングル計算          図2 並列計算

一見したところこれで良さそうですが,ここで問題が生じます.それは,@の計算後にAの計算が行われる場合には正しい結果を得られますが,Aが先に行われたり,共有変数sに@で右辺の結果をストアしているときにAのsが割り込んだりすると,正しい結果が得られないことです.正しい結果を得るには,この縮約計算で、2つのスレッドから同時にsをアクセスしないように命令する必要があります.それがREDUCTIONパラメターです.書き方は,上の場合にはREDUCTION(+:s)というようにして,:の前xxxには演算子を,:のあとyyyには変数を書けばよいのです.変数が2つ以上ある場合にはREDUCTION(+:s,ss)のように,コンマで区切って並べます.前述の縮約演算内積や最大値を求める場合はREDUCTION(+:s)やREDUCTION(MAX:sai)となります.通常コンパイラーで-O3 -apoとすれば,この縮約演算は,自動並列化されますが,doループの中が複雑であったり,自分で!$OPMをプログラムに入れたりした場合には,縮約演算をしていれば必ずこのREDUCTIONパラメターを書かねばなりません.

IF
ループを並列で実行するか,逐次に実行するかを条件をつけて決定したいという場合に使います.
たとえば行列の計算で,次元Nが1000以上のときは並列計算をし,それ以下では(オーバーヘッドが増えかえって遅くなるので),逐次計算をしたいというようなときに使います.IFの括弧の中が真のとき並列計算がされ,偽のときには逐次計算がなされます.
 
!$OPM PARALLEL DO IF(N>1000)
do i=1,n
 
以上PARALLEL DO デレクティブでよく使われる代表的な4つの記述子並びについて述べてきました.この他にもPRIVATE,SHAREDなどといろいろありますが,大抵の場合前述の4つで間に合うはずです.関心のある方はhttp://phase.etl.go.jp/mirrors/openmp/をご覧下さい.
 実はPARALLEL DO文を使うに当たっては,慎重さが不可欠です.次回はどのような場合に使ったら良いか,その辺をお話します.