openmp
OpenMPにおけるループ並列性
サーチ…
パラメーター
句 | パラメータ |
---|---|
private | コンマで区切られたプライベート変数のリスト |
firstprivate | private と同様ですが、ループに入る前に変数の値に初期化されます |
lastprivate | private と同様ですが、変数は終了時にループの最後の反復に対応する値を取得します |
reduction | リダクション演算子: 対応するリダクション変数のコンマ区切りリスト |
schedule | static 、 dynamic 、 guided 、 auto またはruntime の3つの昏睡状態の後の任意のチャンクサイズ |
collapse | 折りたたまれて並列化される完全にネストされたループの数 |
ordered | ループのいくつかの部分を順番に保つ必要があることを伝えます(これらの部分は、ループ本体の中でいくつかのordered 節で特定されます) |
nowait | ループ構成の最後にデフォルトで存在する暗黙のバリアを削除する |
備考
schedule
句の意味は次のとおりです。
-
static[,chunk]
:ラウンドロビン方式でchunk
サイズのバッチでループ反復を静的に(つまり、ループに入る前に配布が行われることを意味して)分散します。chunk
が指定されていない場合、chunk
は可能な限り均等であり、各スレッドは最大で1つのスレッドを取得します。 -
dynamic[,chunk]
:バッチが残らなくなるまで先入れ先出しポリシーでスレッドのchunk
サイズをバッチ単位でループ間で繰り返します。指定しない場合、chunk
は1に設定されます -
guided[,chunk]
:dynamic
と同じように、バッチサイズが小さくなり、小さくなる -
auto
:コンパイラや実行時ライブラリが最適なものを決めるようにする -
runtime
:実行時にOMP_SCHEDULE
環境変数を使用して決定を破棄します。実行時に環境変数が定義されていない場合は、デフォルトのスケジューリングが使用されます
schedule
のデフォルトは実装定義です。多くの環境ではstatic
、 dynamic
場合もあれば、 auto
場合もあります。したがって、明示的に設定することなく、実装が暗黙的に依存しないように注意してください。
上記の例では、融合形式をparallel for
またはparallel do
。しかし、ループ構築物はでそれを融合することなく使用することができるparallel
の形で、ディレクティブ#pragma omp for [...]
または!$omp do [...]
内のスタンドアロンディレクティブparallel
地域。
Fortranバージョンの場合のみ、並列化されたループのループインデックス変数は、デフォルトでは常にprivate
です。したがって、明示的にprivate
宣言する必要はありません(エラーではありませんが)。
CおよびC ++バージョンでは、ループインデックスは他の変数とまったく同じです。したがって、スコープが並列化されたループの外側にある場合for ( int i = ...)
ようfor ( int i = ...)
宣言されていなくてint i; ... for ( i = ... )
ようfor ( int i = ...)
宣言されている場合は、 private
に宣言する必要があります。
Cの典型的な例
#include <stdio.h>
#include <math.h>
#include <omp.h>
#define N 1000000
int main() {
double sum = 0;
double tbegin = omp_get_wtime();
#pragma omp parallel for reduction( +: sum )
for ( int i = 0; i < N; i++ ) {
sum += cos( i );
}
double wtime = omp_get_wtime() - tbegin;
printf( "Computing %d cosines and summing them with %d threads took %fs\n",
N, omp_get_max_threads(), wtime );
return sum;
}
この例では、100万コサインを計算し、それらの値を並行して合計します。また、並列化がパフォーマンスに何らかの影響を与えるかどうかを確認するために、実行に移ります。最後に、時間を測定するので、コンパイラが実行した作業を最適化しないようにしなければならないので、結果を返すだけでふりをします。
Fortranでの同じ例
program typical_loop
use omp_lib
implicit none
integer, parameter :: N = 1000000, kd = kind( 1.d0 )
real( kind = kd ) :: sum, tbegin, wtime
integer :: i
sum = 0
tbegin = omp_get_wtime()
!$omp parallel do reduction( +: sum )
do i = 1, N
sum = sum + cos( 1.d0 * i )
end do
!$omp end parallel do
wtime = omp_get_wtime() - tbegin
print "( 'Computing ', i7, ' cosines and summing them with ', i2, &
& ' threads took ', f6.4,'s' )", N, omp_get_max_threads(), wtime
if ( sum > N ) then
print *, "we only pretend using sum"
end if
end program typical_loop
ここでもまた、100万コサインを計算して蓄積します。ループに時間を要し、不要なコンパイラの最適化を避けるために、結果を使用してふりをします。
サンプルのコンパイルと実行
GCCバージョン4.4を使用している8コアのLinuxマシンでは、Cコードをコンパイルして次のように実行できます。
$ gcc -std=c99 -O3 -fopenmp loop.c -o loopc -lm
$ OMP_NUM_THREADS=1 ./loopc
Computing 1000000 cosines and summing them with 1 threads took 0.095832s
$ OMP_NUM_THREADS=2 ./loopc
Computing 1000000 cosines and summing them with 2 threads took 0.047637s
$ OMP_NUM_THREADS=4 ./loopc
Computing 1000000 cosines and summing them with 4 threads took 0.024498s
$ OMP_NUM_THREADS=8 ./loopc
Computing 1000000 cosines and summing them with 8 threads took 0.011785s
Fortranバージョンの場合、次のようになります。
$ gfortran -O3 -fopenmp loop.f90 -o loopf
$ OMP_NUM_THREADS=1 ./loopf
Computing 1000000 cosines and summing them with 1 threads took 0.0915s
$ OMP_NUM_THREADS=2 ./loopf
Computing 1000000 cosines and summing them with 2 threads took 0.0472s
$ OMP_NUM_THREADS=4 ./loopf
Computing 1000000 cosines and summing them with 4 threads took 0.0236s
$ OMP_NUM_THREADS=8 ./loopf
Computing 1000000 cosines and summing them with 8 threads took 0.0118s
構築のためにOpenMP並列を用いた2つのベクターの追加
void parallelAddition (unsigned N, const double *A, const double *B, double *C)
{
unsigned i;
#pragma omp parallel for shared (A,B,C,N) private(i) schedule(static)
for (i = 0; i < N; ++i)
{
C[i] = A[i] + B[i];
}
}
この例では、2つのベクトル(追加A
及びB
にC
スレッドのチームをスポーン(で指定することによって) OMP_NUM_THREADS
作業のチャンク(この例では、を介して静的に割り当てられ、例えば、environtment変数)各スレッドを割り当てるschedule(static)
発現)。
private(i)
オプション性に関しては備考欄を参照のこと。