web-dev-qa-db-fra.com

Comment MPI_Scatter et MPI_Gather sont-ils utilisés à partir de C?

Jusqu'à présent, mon application lit un fichier txt avec une liste d'entiers. Ces entiers doivent être stockés dans un tableau par le processus maître, c'est-à-dire un processeur de rang 0. Cela fonctionne très bien.

Maintenant, lorsque j'exécute le programme, j'ai une instruction if vérifiant s'il s'agit du processus maître et s'il l'est, j'exécute le MPI_Scatter commande.

D'après ce que je comprends, cela subdivisera le tableau avec les nombres et le transmettra aux processus esclaves, c'est-à-dire tous avec un rang> 0. Cependant, je ne sais pas comment gérer le MPI_Scatter. Comment le processus esclave "souscrit" pour obtenir le sous-tableau? Comment puis-je dire aux processus non maîtres de faire quelque chose avec le sous-tableau?

Quelqu'un peut-il s'il vous plaît fournir un exemple simple pour me montrer comment le processus maître envoie des éléments à partir du tableau, puis demander aux esclaves d'ajouter la somme et de la retourner au maître, qui additionne toutes les sommes ensemble et l'imprime?

Mon code jusqu'à présent:

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

//A pointer to the file to read in.
FILE *fr;

int main(int argc, char *argv[]) {

int rank,size,n,number_read;
char line[80];
int numbers[30];
int buffer[30];

MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);

fr = fopen ("int_data.txt","rt"); //We open the file to be read.

if(rank ==0){
printf("my rank = %d\n",rank);

//Reads in the flat file of integers  and stores it in the array 'numbers' of type int.
n=0;
while(fgets(line,80,fr) != NULL) {
  sscanf(line, "%d", &number_read);
  numbers[n] = number_read;
  printf("I am processor no. %d --> At element %d we have number: %d\n",rank,n,numbers[n]);
  n++;
}

fclose(fr);

MPI_Scatter(&numbers,2,MPI_INT,&buffer,2,MPI_INT,rank,MPI_COMM_WORLD);

}
else {
MPI_Gather ( &buffer, 2, MPI_INT, &numbers, 2, MPI_INT, 0, MPI_COMM_WORLD); 
printf("%d",buffer[0]);
}
MPI_Finalize();
return 0;
}
27
DSF

Il s'agit d'une incompréhension courante du fonctionnement des opérations en MPI avec les nouveaux utilisateurs; en particulier avec les opérations collectives, où les gens essaient de commencer à utiliser la diffusion (MPI_Bcast) Uniquement à partir du rang 0 , en attendant l'appel à "pousser" les données vers les autres processeurs. Mais ce n'est pas vraiment ainsi que les routines MPI fonctionnent; la plupart des communications MPI nécessitent à la fois l'expéditeur) et le récepteur pour effectuer des appels MPI.

En particulier, MPI_Scatter() et MPI_Gather() (et MPI_Bcast, Et bien d'autres) sont collectifs opérations; ils doivent être appelés par toutes les tâches du communicateur. Tous les processeurs du communicateur effectuent le même appel et l'opération est effectuée. (C'est pourquoi la diffusion et la collecte nécessitent toutes deux comme l'un des paramètres le processus "racine", d'où toutes les données vont/viennent). En procédant de cette manière, l'implémentation MPI a beaucoup de possibilités pour optimiser les modèles de communication.

Voici donc un exemple simple (mis à jour pour inclure rassembler):

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

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

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    int *globaldata=NULL;
    int localdata;

    if (rank == 0) {
        globaldata = malloc(size * sizeof(int) );
        for (int i=0; i<size; i++)
            globaldata[i] = 2*i+1;

        printf("Processor %d has data: ", rank);
        for (int i=0; i<size; i++)
            printf("%d ", globaldata[i]);
        printf("\n");
    }

    MPI_Scatter(globaldata, 1, MPI_INT, &localdata, 1, MPI_INT, 0, MPI_COMM_WORLD);

    printf("Processor %d has data %d\n", rank, localdata);
    localdata *= 2;
    printf("Processor %d doubling the data, now has %d\n", rank, localdata);

    MPI_Gather(&localdata, 1, MPI_INT, globaldata, 1, MPI_INT, 0, MPI_COMM_WORLD);

    if (rank == 0) {
        printf("Processor %d has data: ", rank);
        for (int i=0; i<size; i++)
            printf("%d ", globaldata[i]);
        printf("\n");
    }

    if (rank == 0)
        free(globaldata);

    MPI_Finalize();
    return 0;
}

L'exécuter donne:

gpc-f103n084-$ mpicc -o scatter-gather scatter-gather.c -std=c99
gpc-f103n084-$ mpirun -np 4 ./scatter-gather
Processor 0 has data: 1 3 5 7 
Processor 0 has data 1
Processor 0 doubling the data, now has 2
Processor 3 has data 7
Processor 3 doubling the data, now has 14
Processor 2 has data 5
Processor 2 doubling the data, now has 10
Processor 1 has data 3
Processor 1 doubling the data, now has 6
Processor 0 has data: 2 6 10 14
60
Jonathan Dursi