分子動力学アルゴリズムで周期的な境界条件を実装するために、serial
コードのCUDA
バージョンを記述しようとしています。考え方は、ボックスの外にある位置の粒子のほんの一部が、2つのうちの1つを使用して戻される必要があるということです。ways
、最初の方法を使用する回数に制限があります。Cudaアトミックと条件分岐
本質的に、それは以下のMWEにまでわかります。私は配列x[N]
を持っています。ここではN
が大きく、次のコードはserial
です。
#include <cstdlib>
int main()
{
int N =30000;
double x[30000];
int Nmax = 10, count = 0;
for(int i = 0; i < N; i++)
x[i] = 1.0*(rand()%3);
for(int i = 0; i < N; i++)
{
if(x[i] > 2.9)
{
if(count < Nmax)
{
x[i] += 0.1; //first way
count++;
}
else
x[i] -= 0.2; //second way
}
}
}
のみx[i]
の30000個の要素のごく一部(約12〜15)のためにそのx[i] > 2.9
を想定してください。 i
の順序は重要ではない
注、すなわちアルゴリズムは、潜在的に並列化作り、10
最低i
はx[i] += 0.1
を使用することが必要ではありません。私はmain.cu
はもちろん
#include <cstdlib>
__global__ void PeriodicCondition(double *x, int *N, int *Nmax, int *count)
{
int i = threadIdx.x+blockIdx.x*blockDim.x;
if(i < N[0])
{
if(x[i] > 2.9)
{
if(count[0] < Nmax[0]) //===============(line a)
{
x[i] += 0.1; //first way
atomicAdd(&count[0],1); //========(line b)
}
else
x[i] -= 0.2; //second way
}
}
}
int main()
{
int N = 30000;
double x[30000];
int Nmax = 10, count = 0;
srand(128512);
for(int i = 0; i < N; i++)
x[i] = 1.0*(rand()%3);
double *xD;
cudaMalloc((void**) &xD, N*sizeof(double));
cudaMemcpy(xD, &x, N*sizeof(double),cudaMemcpyHostToDevice);
int *countD;
cudaMalloc((void**) &countD, sizeof(int));
cudaMemcpy(countD, &count, sizeof(int),cudaMemcpyHostToDevice);
int *ND;
cudaMalloc((void**) &ND, sizeof(int));
cudaMemcpy(ND, &N, sizeof(int),cudaMemcpyHostToDevice);
int *NmaxD;
cudaMalloc((void**) &NmaxD, sizeof(int));
cudaMemcpy(NmaxD, &Nmax, sizeof(int),cudaMemcpyHostToDevice);
PeriodicCondition<<<938,32>>>(xD, ND, NmaxD, countD);
cudaFree(NmaxD);
cudaFree(ND);
cudaFree(countD);
cudaFree(xD);
}
として読み込むnvcc -arch sm_35 main.cu
でコンパイルMWE、以下のCUDA
バージョンを考え、(line a)
上if
条件が(line b)
で更新される変数を使用しているため、これは正しくありません、これは最新のものではない可能性があります。これはCuda atomics change flagと多少似ていますが、クリティカルセクションを使用するのがどのように役立つかどうか、またどのように役立つかはわかりません。
if
の条件が(line a)
であることをすべてのスレッドがチェックすると、コードがあまりにもシリアルにならないように、count[0]
が最新であることを確認する方法はありますか?
@claudeの答えは良いものだと思うし、 'count [0]'が常にインクリメントされることを許すことができれば、とてもシンプルできれいです。シリアルコードの正確な振る舞いを再現するために( 'count'は' Nmax'に達するまで増加し、その後停止します)、 'atomicCAS'の周りに構築されたカスタム原子を使用することができます。私はパフォーマンス面ではクロードの回答よりもコストがかかると思っています。 –