2012-04-13 4 views
3

Ich habe eine Anwendung, die mit MPI parallelisiert ist und in eine Reihe von verschiedenen Aufgaben aufgeteilt ist. Jedem Prozessor ist nur eine Aufgabe zugewiesen und der Gruppe von Prozessoren, denen die gleiche Aufgabe zugewiesen ist, wird ein eigener Kommunikator zugewiesen. Die Aufgaben müssen regelmäßig synchronisiert werden. Gegenwärtig erfolgt die Synchronisation über MPI_COMM_WORLD, aber das hat den Nachteil, dass keine kollektiven Operationen verwendet werden können, da nicht garantiert ist, dass andere Aufgaben jemals diesen Block Code erreichen werden.mpi kollektive Operationen von einem Kommunikator zum anderen

Als konkreteres Beispiel:

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 

würde Ich mag auf task1 ein Array MPI_SUM und das Ergebnis bei task3 erscheinen haben. Gibt es einen effizienten Weg, dies zu tun? (Ich entschuldige mich, wenn das eine dumme Frage ist, ich habe nicht viel Erfahrung mit dem Erstellen und Verwenden von benutzerdefinierten MPI-Communicators)

Antwort

4

Charles ist genau richtig; die Interkommunikatoren erlauben es Ihnen, zwischen Kommunikatoren zu sprechen (oder, um "normale" Kommunikatoren in diesem Zusammenhang zu unterscheiden, "Intra-Kommunikatoren", was mich nicht als eine Verbesserung empfindet).

Ich habe immer die Verwendung dieser Interkommunikatoren ein wenig verwirrend für die Neulinge gefunden. Nicht die Grundideen, die einen Sinn ergeben, sondern die Mechanik, die (etwa) MPI_Reduce mit einer von diesen verwendet. Die Gruppe von Aufgaben, die die Reduktion durchführen, spezifiziert den Root-Rang auf dem Fernkommunikator, soweit so gut; aber innerhalb der Remote-Rank-Communicator, jeder nicht der Stamm angibt, MPI_PROC_NULL als root, während die tatsächliche Wurzel MPI_ROOT angibt. Die Dinge, die man für Rückwärtskompatibilität tut, hey?

#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

Danke. Das Detail hier wird geschätzt. Ich denke, es wird eine Weile dauern, bis ich all das verdaue ... – mgilson

4

Alles, was Sie brauchen, ist ein neuer Communicator erstellen, der Knoten aus beiden Aufgaben enthält, die Sie miteinander kommunizieren möchten. Sehen Sie sich MPI-Gruppen und Communicators an. Sie können viele Beispiele im Netz finden, here for instance.

+0

Haben Sie eine Schätzung, wie viel effizienter es dies im Vergleich zu tun, ist auf 'mpi_comm_solver1' die kollektive Operation zu tun, und dann mit einem einfachen' MPI_Send' das Ergebnis an die anderen Aufgabe zu senden? – mgilson

Verwandte Themen