7

私はMPIが初めてです。私は 4 つのプロセスを持っています: プロセス 1 から 3 はベクトルを設定してプロセス 0 に送信し、プロセス 0 はベクトルを 1 つの非常に長いベクトルに収集します。機能するコード (投稿するには長すぎる) がありますが、プロセス 0 の recv 操作はぎこちなく、非常に遅いです。

要約すると、コードは次のことを行います。

MPI::Init();
int id = MPI::COMM_WORLD.Get_rank();

if(id>0) {
    double* my_array = new double[n*m]; //n,m are int
    Populate(my_array, id);
    MPI::COMM_WORLD.Send(my_array,n*m,MPI::DOUBLE,0,50);
}

if(id==0) {
    double* all_arrays = new double[3*n*m];
    /* Slow Code Starts Here */
    double startcomm = MPI::Wtime();
    for (int i=1; i<=3; i++) {
    MPI::COMM_WORLD.Recv(&all_arrays[(i-1)*m*n],n*m,MPI::DOUBLE,i,50);
    }
    double endcomm = MPI::Wtime();
    //Process 0 has more operations...
}
MPI::Finalize();

合計時間の 50%を占めていることがendcomm - startcommわかります (プログラムが完了するのに 1.5 秒かかるのに対し、0.7 秒)。

プロセス 1 ~ 3 からベクトルを受け取り、プロセス 0 に保存するより良い方法はありall_arraysますか?

MPI::Comm::Gather を調べましたが、使い方がわかりません。特に、プロセス 1 の配列を all_arrays の最初の配列、プロセス 2 の配列を 2 番目の配列などに指定できますか? ありがとう。

編集:「遅い」ループを削除し、代わりに「if」ブロックの間に次を配置しました。

MPI_Gather(my_array,n*m,MPI_DOUBLE,
    &all_arrays[(id-1)*m*n],n*m,MPI_DOUBLE,0,MPI_COMM_WORLD);

同じ遅いパフォーマンスが発生しました。これは、ルート プロセスが個々の受信が完了するのを「待機」してから、次の受信を試行するという事実と関係がありますか? それとも、それについて考えるのは正しい方法ではありませんか?

4

1 に答える 1

6

はい、MPI_Gatherまさにそれを行います。MPI_Gatherのanlページから:

int MPI_Gather(void *sendbuf, int sendcnt, MPI_Datatype sendtype, 
               void *recvbuf, int recvcnt, MPI_Datatype recvtype, 
               int root, MPI_Comm comm)

ここに、sendbuf各プロセスの配列があります(my_array)。は、短い配列が収集される受信プロセスrecvbufの長い配列( )です。all_arrays受信プロセスの短い配列は、長い配列の隣接する位置にコピーされているため、自分で行うことを心配する必要はありません。各プロセスの配列は、長い配列に連続して配置されます。

編集:

受信プロセスが収集でsendbufに寄与しない場合は、代わりにMPI_Gathervを使用することをお勧めします(これを指摘してくれた@HristoIlievに感謝します)。

于 2012-05-07T23:50:13.337 に答える