2012-04-13 10 views
3

私はMPIと並列化されたアプリケーションをいくつかのタスクに分けています。各プロセッサには1つのタスクしか割り当てられず、同じタスクが割り当てられたプロセッサのグループにはそれ自身のコミュニケータが割り当てられます。タスクは定期的に同期する必要があります。現在のところ、MPI_COMM_WORLDを介して同期が行われていますが、他のタスクがそのコードブロックに到達することは保証されていないため、一括操作を使用できないという欠点があります。より具体的な例として mpiコミュニケータ間の一括操作

task1: equation1_solver, N nodes, communicator: mpi_comm_solver1 
task2: equation2_solver, M nodes, communicator: mpi_comm_solver2 
task3: file IO   , 1 node , communicator: mpi_comm_io 

私はTASK1上のアレイをMPI_SUMとTASK3に表示された結果を持っていると思います。これを行う効率的な方法はありますか? (愚かな質問であれば謝罪しますが、私はカスタムMPIコミュニケータの作成と使用に関する多くの経験はありません)

答えて

4

チャールズはまさに正しいです。コミュニケータの間でコミュニケータを話すことができます(または、この文脈では「通常の」コミュニケータと区別するために、イントラコミュニケータを使用します)。

私はいつもこれらのコミュニケータの使用が新しいことについて少し混乱していることを発見しました。意味のある基本的な考え方ではなく、メカニックがMPI_Reduceを使ってこれらのいずれかを使っています。削減を行うタスクのグループは、リモートコミュニケータのルートランクを指定します。リモートランクコミュニケータ内では、すべてではなく、ルートはMPI_PROC_NULLをルートとして指定しますが、実際のルートはMPI_ROOTです。下位互換性のために行うこと、ちょっと?

#include <mpi.h> 
#include <stdio.h> 


int main(int argc, char **argv) 
{ 
    int commnum = 0;   /* which of the 3 comms I belong to */ 
    MPI_Comm mycomm;  /* Communicator I belong to */ 
    MPI_Comm intercomm; /* inter-communicator */ 
    int cw_rank, cw_size; /* size, rank in MPI_COMM_WORLD */ 
    int rank;    /* rank in local communicator */ 

    MPI_Init(&argc, &argv); 
    MPI_Comm_rank(MPI_COMM_WORLD, &cw_rank); 
    MPI_Comm_size(MPI_COMM_WORLD, &cw_size); 

    if (cw_rank == cw_size-1)  /* last task is IO task */ 
     commnum = 2; 
    else { 
     if (cw_rank < (cw_size-1)/2) 
      commnum = 0; 
     else 
      commnum = 1; 
    } 

    printf("Rank %d in comm %d\n", cw_rank, commnum); 

    /* create the local communicator, mycomm */ 
    MPI_Comm_split(MPI_COMM_WORLD, commnum, cw_rank, &mycomm); 

    const int lldr_tag = 1; 
    const int intercomm_tag = 2; 
    if (commnum == 0) { 
     /* comm 0 needs to communicate with comm 2. */ 
     /* create an intercommunicator: */ 

     /* rank 0 in our new communicator will be the "local leader" 
     * of this commuicator for the purpose of the intercommuniator */ 
     int local_leader = 0; 

     /* Now, since we're not part of the other communicator (and vice 
     * versa) we have to refer to the "remote leader" in terms of its 
     * rank in COMM_WORLD. For us, that's easy; the remote leader 
     * in the IO comm is defined to be cw_size-1, because that's the 
     * only task in that comm. But for them, it's harder. So we'll 
     * send that task the id of our local leader. */ 

     /* find out which rank in COMM_WORLD is the local leader */ 
     MPI_Comm_rank(mycomm, &rank); 

     if (rank == 0) 
      MPI_Send(&cw_rank, 1, MPI_INT, cw_size-1, 1, MPI_COMM_WORLD); 
     /* now create the inter-communicator */ 
     MPI_Intercomm_create(mycomm, local_leader, 
           MPI_COMM_WORLD, cw_size-1, 
           intercomm_tag, &intercomm); 
    } 
    else if (commnum == 2) 
    { 
     /* there's only one task in this comm */ 
     int local_leader = 0; 
     int rmt_ldr; 
     MPI_Status s; 
     MPI_Recv(&rmt_ldr, 1, MPI_INT, MPI_ANY_SOURCE, lldr_tag, MPI_COMM_WORLD, &s); 
     MPI_Intercomm_create(mycomm, local_leader, 
           MPI_COMM_WORLD, rmt_ldr, 
           intercomm_tag, &intercomm); 
    } 


    /* now let's play with our communicators and make sure they work */ 

    if (commnum == 0) { 
     int max_of_ranks = 0; 
     /* try it internally; */ 
     MPI_Reduce(&rank, &max_of_ranks, 1, MPI_INT, MPI_MAX, 0, mycomm); 
     if (rank == 0) { 
      printf("Within comm 0: maximum of ranks is %d\n", max_of_ranks); 
      printf("Within comm 0: sum of ranks should be %d\n", max_of_ranks*(max_of_ranks+1)/2); 
     } 

     /* now try summing it to the other comm */ 
     /* the "root" parameter here is the root in the remote group */ 
     MPI_Reduce(&rank, &max_of_ranks, 1, MPI_INT, MPI_SUM, 0, intercomm); 
    } 

    if (commnum == 2) { 
     int sum_of_ranks = -999; 
     int rootproc; 

     /* get reduction data from other comm */ 

     if (rank == 0) /* am I the root of this reduce? */ 
      rootproc = MPI_ROOT; 
     else 
      rootproc = MPI_PROC_NULL; 

     MPI_Reduce(&rank, &sum_of_ranks, 1, MPI_INT, MPI_SUM, rootproc, intercomm); 

     if (rank == 0) 
      printf("From comm 2: sum of ranks is %d\n", sum_of_ranks); 
    } 

    if (commnum == 0 || commnum == 2); 
      MPI_Comm_free(&intercomm); 

    MPI_Finalize(); 
} 
+0

ありがとうございます。詳細はここにあります。私はこれをすべて消化するのに少し時間がかかると思う... – mgilson

4

コミュニケーションの両方のタスクのノードを含む新しいコミュニケータを作成するだけです。 MPIグループとコミュニケーターを見てください。多くの例はネット上で見つけることができますhere for instance

+0

は、あなたがそれをmpi_comm_solver1' '上で集団的操作を行うと、その後、簡単な' MPI_Send'で他のタスクに結果を送信するに比べて、これを行うことがいかにはるかに効率的な任意の見積もりを持っていますか? – mgilson

関連する問題