私が書いているopenmpコードの予期せぬ(私にとって!)動作を観察しました。コードの構造は以下の通り:私はこのコードの3つのバージョンにコンパイルしているOMP_NUM_THREADS = 1の#pragma omp atomicのパフォーマンスの問題
#pragma omp parallel for
for(int i=0;i<N;i++){
// lots of calculations that produce 3 integers i1,i2,i3 and 3 doubles d1,d2,d3
#pragma omp atomic
J1[i1] += d1;
#pragma omp atomic
J2[i2] += d2;
#pragma omp atomic
J3[i3] += d3;
}
:OpenMPのなしのOpenMP(-fopenmp)
2)で
1)
3) openmpを使用していますが、3つの原子操作はありません(原子操作が必要なのでテストと同じです)
環境変数O MP_NUM_THREADS = 1、バージョン2に関して大幅な減速が見られる)。バージョン3はバージョン2と同じ速さで実行されます)。
私はこの動作の理由を知りたいと思います(なぜ、アトミック操作でコードがシングルスレッド化されても遅くなるのですか?)、バージョン1のようなコードをコンパイル/バージョン2と同じ速さで実行されます)。
質問の最後に上記の動作を示す動作例を添付します。
g++ -fopenmp -o toy_code toy_code.cpp -std=c++11 -O3
2):私は1)コンパイル
g++ -o toy_code_NO_OMP toy_code.cpp -std=c++11 -O3
及び3)と:
g++ -fopenmp -o toy_code_NO_ATOMIC toy_code_NO_ATOMIC.cpp -std=c++11 -O3
コンパイラのバージョンは、GCCバージョン5.3.1 20160519(Debianのあります5.3.1-20)。 3つのバージョンの実行時間である。
1)1分24秒
2)51秒
3)51秒任意のアドバイスを事前に
ありがとうございます!
// toy_code.cpp
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <cmath>
#include <omp.h>
#define Np 1000000
#define N 1000
int main(){
double* Xp, *Yp, *J,*Jb;
Xp = new double[Np];
Yp = new double[Np];
J = new double [N*N];
Jb = new double [N*N];
for(int i=0;i<N*N;i++){
J[i]=0.0;
Jb[i]=0.0;
}
for(int i=0;i<Np;i++){
Xp[i] = rand()*1.0/RAND_MAX - 0.5;
Yp[i] = rand()*1.0/RAND_MAX - 0.5;
}
for(int n=0; n<2000; n++){
#pragma omp parallel for
for(int p=0;p<Np;p++){
double rx = (Xp[p]+0.5)*(N-1);
double ry = (Yp[p]+0.5)*(N-1);
int xindex = (int)floor(rx+0.5);
int yindex = (int)floor(ry+0.5);
int k;
k=xindex*N+yindex;
#pragma omp atomic
J[k]+=1;
#pragma omp atomic
Jb[k]+=1;
}
}
delete[] Xp;
delete[] Yp;
delete[] J;
delete[] Jb;
return 0;
}
openmpが有効な場合、プラグマはGOMPコードに展開され、おそらくシーケンシャルコードよりもオーバーヘッドが発生します –