2014-07-17 16 views
6

Ho provato a impostare un gruppo di processi generati in un unico intracomm. Ho bisogno di generare processi separati in directory di lavoro uniche poiché questi sottoprocessi scriveranno un sacco di file. Dopo che tutti i processi sono stati generati, si desidera unirli in un unico comunicatore intra. Per provarlo, ho creato un semplice programma di test.MPI unire più intercom in un unico intracomm

int main(int argc, const char * argv[]) { 
    int rank, size; 

    const int num_children = 5; 
    int error_codes; 

    MPI_Init(&argc, (char ***)&argv); 

    MPI_Comm parentcomm; 
    MPI_Comm childcomm; 
    MPI_Comm intracomm; 
    MPI_Comm_get_parent(&parentcomm); 

    if (parentcomm == MPI_COMM_NULL) { 
     printf("Current Command %s\n", argv[0]); 

     for (size_t i = 0; i < num_children; i++) { 
      MPI_Comm_spawn(argv[0], MPI_ARGV_NULL, 1, MPI_INFO_NULL, 0, MPI_COMM_WORLD, &childcomm, &error_codes); 
      MPI_Intercomm_merge(childcomm, 0, &intracomm); 
      MPI_Barrier(childcomm); 
     } 
    } else { 
     MPI_Intercomm_merge(parentcomm, 1, &intracomm); 
     MPI_Barrier(parentcomm); 
    } 

    printf("Test\n"); 

    MPI_Barrier(intracomm); 

    printf("Test2\n"); 

    MPI_Comm_rank(intracomm, &rank); 
    MPI_Comm_size(intracomm, &size); 

    printf("Rank %d of %d\n", rank + 1, size); 

    MPI_Barrier(intracomm); 
    MPI_Finalize(); 
    return 0; 
} 

Quando eseguo questo ottengo tutti i 6 processi, ma la mia IntraComm sta parlando solo tra il genitore e l'ultimo figlio generato. L'output risultante è

Test 
Test 
Test 
Test 
Test 
Test 
Test2 
Rank 1 of 2 
Test2 
Rank 2 of 2 

C'è un modo per unire più comunicatori in un singolo comunicatore? Si noti inoltre che sto generando questi uno alla volta poiché ho bisogno che ogni sottoprocesso venga eseguito in una directory di lavoro univoca.

risposta

4

Se hai intenzione di farlo chiamando più volte lo MPI_COMM_SPAWN, dovrai farlo con più attenzione. Dopo aver chiamato SPAWN la prima volta, il processo generato dovrà anche prendere parte alla prossima chiamata a SPAWN, altrimenti verrà escluso dal communicator che stai unendo. finisce per assomigliare a questo:

Individual Spawns

Il problema è che solo due processi partecipano ogni MPI_INTERCOMM_MERGE e non è possibile unire i tre comunicatori in modo che non avrete mai finisce con un grande comunicatore in questo modo.

Se avete invece ogni processo partecipare alla fusione come va, si finisce con un grande comunicatore alla fine:

Group Spawns

Naturalmente, si può solo generare tutti i processi in più allo stesso tempo, ma sembra che potresti avere altre ragioni per non farlo.

+0

Quindi il processo dicendo 1 depone le uova 2, poi 2 depone le uova 3, ecc ... stavo cercando di evitare di 'MPI_Comm_spawn_multiple' in modo che potessi evitare il caos di configurare matrici di comandi, informazioni, ecc. poiché alla fine finirò per farlo in Fortran. – user1139069

+0

No, 0 spawn 1, quindi 0 e 1 spawn 2, ecc. –

5

Mi rendo conto di essere un anno non aggiornato con questa risposta, ma ho pensato che forse altre persone potrebbero voler vedere un'implementazione di questo. Come ha affermato l'intervistato originario, non c'è modo di unire tre (o più) comunicatori. Devi costruire il nuovo intra-comm uno alla volta. Ecco il codice che uso. Questa versione elimina l'intra-comm originale; si può o non può decidere di farlo a seconda della particolare applicazione:

#include <mpi.h> 


// The Borg routine: given 
// (1) a (quiesced) intra-communicator with one or more members, and 
// (2) a (quiesced) inter-communicator with exactly two members, one 
//  of which is rank zero of the intra-communicator, and 
//  the other of which is an unrelated spawned rank, 
// return a new intra-communicator which is the union of both inputs. 
// 
// This is a collective operation. All ranks of the intra- 
// communicator, and the remote rank of the inter-communicator, must 
// call this routine. Ranks that are members of the intra-comm must 
// supply the proper value for the "intra" argument, and MPI_COMM_NULL 
// for the "inter" argument. The remote inter-comm rank must 
// supply MPI_COMM_NULL for the "intra" argument, and the proper value 
// for the "inter" argument. Rank zero (only) of the intra-comm must 
// supply proper values for both arguments. 
// 
// N.B. It would make a certain amount of sense to split this into 
// separate routines for the intra-communicator processes and the 
// remote inter-communicator process. The reason we don't do that is 
// that, despite the relatively few lines of code, what's going on here 
// is really pretty complicated, and requires close coordination of the 
// participating processes. Putting all the code for all the processes 
// into this one routine makes it easier to be sure everything "lines up" 
// properly. 
MPI_Comm 
assimilateComm(MPI_Comm intra, MPI_Comm inter) 
{ 
    MPI_Comm peer = MPI_COMM_NULL; 
    MPI_Comm newInterComm = MPI_COMM_NULL; 
    MPI_Comm newIntraComm = MPI_COMM_NULL; 

    // The spawned rank will be the "high" rank in the new intra-comm 
    int high = (MPI_COMM_NULL == intra) ? 1 : 0; 

    // If this is one of the (two) ranks in the inter-comm, 
    // create a new intra-comm from the inter-comm 
    if (MPI_COMM_NULL != inter) { 
     MPI_Intercomm_merge(inter, high, &peer); 
    } else { 
     peer = MPI_COMM_NULL; 
    } 

    // Create a new inter-comm between the pre-existing intra-comm 
    // (all of it, not only rank zero), and the remote (spawned) rank, 
    // using the just-created intra-comm as the peer communicator. 
    int tag = 12345; 
    if (MPI_COMM_NULL != intra) { 
     // This task is a member of the pre-existing intra-comm 
     MPI_Intercomm_create(intra, 0, peer, 1, tag, &newInterComm); 
    } 
    else { 
     // This is the remote (spawned) task 
     MPI_Intercomm_create(MPI_COMM_SELF, 0, peer, 0, tag, &newInterComm); 
    } 

    // Now convert this inter-comm into an intra-comm 
    MPI_Intercomm_merge(newInterComm, high, &newIntraComm); 


    // Clean up the intermediaries 
    if (MPI_COMM_NULL != peer) MPI_Comm_free(&peer); 
    MPI_Comm_free(&newInterComm); 

    // Delete the original intra-comm 
    if (MPI_COMM_NULL != intra) MPI_Comm_free(&intra); 

    // Return the new intra-comm 
    return newIntraComm; 
} 
Problemi correlati