格子ボルツマン モデリング用の CUDA コードを MPI しようとしていますが、MPI_Send 関数と MPI_Recv 関数でイライラする問題に遭遇しました。デバイス バッファーへの単純なデバイス バッファー MPI send/recv コードを備えた CUDA 対応 MPI があることを確認したので、CPU/ホストを経由せずに GPU デバイス メモリ間で配列を正常に送受信できます。
私のコードは、さまざまなノード間で z 方向に沿って分割された 3D ラティス用であり、これらの分割間で流体が流れるように、ノード間に Halos が渡されます。Halos は GPU 上にあります。以下のコードは簡略化したもので、コンパイルするとメイン コードと同じエラーが発生します。ここで、ランク 0 ノードの GPU Halo はランク 1 ノードへの MPI_Send() であり、MPI_Recv() です。現時点では、私の問題は非常に単純に思えます。MPI_Send と MPI_Recv の呼び出しを機能させることができません! コードは「//CODE DOES NOT REACH HERE.」に進みません。MPI_etc() 呼び出しが機能していないと結論付けました。
私のコードは基本的に次のとおりです。コードの多くは削除されていますが、同じエラーでコンパイルするには十分です。
#include <mpi.h>
using namespace std;
//In declarations:
const int DIM_X = 30;
const int DIM_Y = 50;
const int Q=19;
const int NumberDevices = 1;
const int NumberNodes = 2;
__host__ int SendRecvID(int UpDown, int rank, int Cookie) {int a =(UpDown*NumberNodes*NumberDevices) + (rank*NumberDevices) + Cookie; return a;} //Use as downwards memTrnsfr==0, upwards==1
int main(int argc, char *argv[])
{
//MPI functions (copied from online tutorial somewhere)
int numprocessors, rank, namelen;
char processor_name[MPI_MAX_PROCESSOR_NAME];
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numprocessors);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Get_processor_name(processor_name, &namelen);
/* ...code for splitting other arrays removed... */
size_t size_Halo_z = Q*DIM_X*DIM_Y*sizeof(double); //Size variable used in cudaMalloc and cudaMemcpy.
int NumDataPts_f_halo = DIM_X*DIM_Y*Q; //Number of data points used in MPI_Send/Recv calls.
MPI_Status status; //Used in MPI_Recv.
//Creating arrays for GPU data below, using arrays of pointers:
double *Device_HaloUp_Take[NumberDevices]; //Arrays on the GPU which will be the Halos.
double *Device_HaloDown_Take[NumberDevices]; //Arrays on the GPU which will be the Halos.
double *Device_HaloUp_Give[NumberDevices]; //Arrays on the GPU which will be the Halos.
double *Device_HaloDown_Give[NumberDevices]; //Arrays on the GPU which will be the Halos.
for(int dev_i=0; dev_i<NumberDevices; dev_i++) //Initialising the GPU arrays:
{
cudaSetDevice(dev_i);
cudaMalloc( (void**)&Device_HaloUp_Take[dev_i], size_Halo_z);
cudaMalloc( (void**)&Device_HaloDown_Take[dev_i], size_Halo_z);
cudaMalloc( (void**)&Device_HaloUp_Give[dev_i], size_Halo_z);
cudaMalloc( (void**)&Device_HaloDown_Give[dev_i], size_Halo_z);
}
int Cookie=0; //Counter used to count the devices below.
for(int n=1;n<=100;n++) //Each loop iteration is one timestep.
{
/* Run computation on GPUs */
cudaThreadSynchronize();
if(rank==0) //Rank 0 node makes the first MPI_Send().
{
for(Cookie=0; Cookie<NumberDevices; Cookie++)
{
if(NumberDevices==1) //For single GPU codes (which for now is what I am stuck on):
{
cout << endl << "Testing X " << rank << endl;
MPI_Send(Device_HaloUp_Take[Cookie], NumDataPts_f_halo, MPI_DOUBLE, (rank+1), SendRecvID(1,rank,Cookie), MPI_COMM_WORLD);
cout << endl << "Testing Y " << rank << endl; //CODE DOES NOT REACH HERE.
MPI_Recv(Device_HaloUp_Give[Cookie], NumDataPts_f_halo, MPI_DOUBLE, (rank+1), SendRecvID(0,rank+1,0), MPI_COMM_WORLD, &status);
/*etc */
}
}
}
else if(rank==(NumberNodes-1))
{
for(Cookie=0; Cookie<NumberDevices; Cookie++)
{
if(NumberDevices==1)
{
cout << endl << "Testing A " << rank << endl;
MPI_Recv(Device_HaloDown_Give[Cookie], NumDataPts_f_halo, MPI_DOUBLE, (rank-1), SendRecvID(1,rank-1,NumberDevices-1), MPI_COMM_WORLD, &status);
cout << endl << "Testing B " << rank << endl; //CODE DOES NOT REACH HERE.
MPI_Send(Device_HaloUp_Take[Cookie], NumDataPts_f_halo, MPI_DOUBLE, 0, SendRecvID(1,rank,Cookie), MPI_COMM_WORLD);
/*etc*/
}
}
}
}
/* Then some code to carry out rest of lattice boltzmann method. */
MPI_Finalize();
}
2 つのノード (コード内の NumberNodes==2 変数) があるため、1 つをランク ==0、もう 1 つをランク==1==NumberNodes-1 としています。ランク 0 のコードは if(rank==0) ループに行き、そこで「Testing X 0」を出力しますが、MPI_Send() 関数で事前にブレークするため、「Testing Y 0」を出力することはありません。この時点で変数 Cookie は 0 です。これは、GPU/デバイスが 1 つしかないため、SendRecvID() 関数が "(1,0,0)" を取るためです。MPI_Send の最初のパラメーターはポインターです。Device_Halo_etc はポインターの配列であり、データが送信される場所は (rank+1)=1 です。
同様に、ランク 1 コードは if(rank==NumberNodes-1) ループに移動し、MPI_Recv 呼び出しを完了する前にコードが停止するため、"Testing A 1" を出力しますが、"Testing B 1" を出力しません。私の知る限り、MPI_Recv のパラメータは正しいです。(rank-1)=0 が正しいので、送受信されるデータ ポイントの数は正しく、ID は同じです。
私がこれまでに試したことは、それぞれが正確に同じタグを持っていることを確認することです (ただし、SendRecvID() はそれぞれの場合 (1,0,0) を取るため、とにかく同じです) 999 程度を手書きで作成しましたが、これで変わりはない。また、両方の MPI 呼び出しで Device_Halo_etc パラメーターを &Device_Halo_etc に変更しました。念のため、そこでポインターを台無しにしましたが、違いはありません。これまでのところ動作させる唯一の方法は、MPI_Send/Recv() 呼び出しの Device_Halo_etc パラメーターをホスト上の任意の配列に変更して、転送するかどうかをテストすることです。そうすることで、最初の MPI 呼び出しを通過させることができます。もちろん、次のものに行き詰まりますが、それでも、Send/Recv の変数の数を 1 に変更した場合にのみ機能します (NumDataPts_f_halo==14250 ではなく)。そしてもちろん、ホスト アレイを移動することは重要ではありません。
追加のリンク変数を使用して nvcc コンパイラを使用してコードを実行します (メソッドをどこかにオンラインでコピーしたため、これらがどのように機能するかはよくわかりませんが、より単純なデバイスからデバイスへの MPI 呼び出しが機能していることを考えると、これで問題はないと思います)。 :
nvcc TestingMPI.cu -o run_Test -I/usr/lib/openmpi/include -I/usr/lib/openmpi/include/openmpi -L/usr/lib/openmpi/lib -lmpi_cxx -lmpi -ldl
そしてコンパイル:
mpirun -np 2 run_Test
そうすると、通常は次のようなエラーが表示されます。
Testing A 1
Testing X 0
[Anastasia:16671] *** Process received signal ***
[Anastasia:16671] Signal: Segmentation fault (11)
[Anastasia:16671] Signal code: Invalid permissions (2)
[Anastasia:16671] Failing at address: 0x700140000
[Anastasia:16671] [ 0] /lib/x86_64-linux-gnu/libc.so.6(+0x364a0) [0x7f20327774a0]
[Anastasia:16671] [ 1] /lib/x86_64-linux-gnu/libc.so.6(+0x147fe5) [0x7f2032888fe5]
[Anastasia:16671] [ 2] /usr/lib/libmpi.so.1(opal_convertor_pack+0x14d) [0x7f20331303bd]
[Anastasia:16671] [ 3] /usr/lib/openmpi/lib/openmpi/mca_btl_sm.so(+0x20c8) [0x7f202cad20c8]
[Anastasia:16671] [ 4] /usr/lib/openmpi/lib/openmpi/mca_pml_ob1.so(+0x100f0) [0x7f202d9430f0]
[Anastasia:16671] [ 5] /usr/lib/openmpi/lib/openmpi/mca_pml_ob1.so(+0x772b) [0x7f202d93a72b]
[Anastasia:16671] [ 6] /usr/lib/libmpi.so.1(MPI_Send+0x17b) [0x7f20330bc57b]
[Anastasia:16671] [ 7] run_Test() [0x400ff7]
[Anastasia:16671] [ 8] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7f203276276d]
[Anastasia:16671] [ 9] run_Test() [0x400ce9]
[Anastasia:16671] *** End of error message ***
--------------------------------------------------------------------------
mpirun noticed that process rank 0 with PID 16671 on node Anastasia exited on signal 11 (Segmentation fault).
--------------------------------------------------------------------------
Linux Ubuntu 12.04LTSで実行されているデュアルGT650m NVIDIAグラフィックスカードを搭載したLenovo Y500であるラップトップ(アナスタシア)でコードを実行しています。nvcc --version
「リリース 5.0、V0.2.1221」をmpirun --version
提供し、「mpirun (Open MPI) 1.5.4」を提供します。