web-dev-qa-db-fra.com

Envoi et réception du tableau 2D Over MPI

Le problème que j'essaie de résoudre est ce qui suit:

Le code série C++ J'ai calculé sur une grande matrice 2D. Pour optimiser ce processus, je souhaite diviser cette grande matrice 2D et exécuter 4 nœuds (par exemple) en utilisant MPI. La seule communication qui se produit entre les nœuds est le partage des valeurs de bord à la fin de chaque étape de la période. Chaque nœud partage les données de la matrice Edge, [I] [J], avec son voisin.

Basé sur la lecture sur MPI, j'ai le système suivant à mettre en œuvre.

if (myrank == 0)
{
 for (i= 0 to x)
 for (y= 0 to y)
 {
  C++ CODE IMPLEMENTATION 
  .... 
  MPI_SEND(A[x][0], A[x][1], A[x][2], Destination= 1.....)
  MPI_RECEIVE(B[0][0], B[0][1]......Sender = 1.....)
  MPI_BARRIER
}

if (myrank == 1)
{
for (i = x+1 to xx)
for (y = 0 to y)
{
 C++ CODE IMPLEMENTATION
 ....
 MPI_SEND(B[x][0], B[x][1], B[x][2], Destination= 0.....)
 MPI_RECEIVE(A[0][0], A[0][1]......Sender = 1.....)
 MPI BARRIER
}

Je voulais savoir si mon approche est correcte et que j'apprécierais également toutes les directives sur d'autres MPI fonctions aussi sur la mise en œuvre.

Merci, Ashwin.

21
Ashmohan

Juste pour amplifier un peu les points de Joel:

Cela va beaucoup plus facile si vous allouez vos tableaux de manière à ce qu'ils sont contigus (quelque chose "des" tableaux multidimensionnels "ne vous donnent pas automatiquement :)

int **alloc_2d_int(int rows, int cols) {
    int *data = (int *)malloc(rows*cols*sizeof(int));
    int **array= (int **)malloc(rows*sizeof(int*));
    for (int i=0; i<rows; i++)
        array[i] = &(data[cols*i]);

    return array;
}

/*...*/
int **A;
/*...*/
A = alloc_2d_init(N,M);

Ensuite, vous pouvez faire des envois et des récompenses de l'ensemble de la matrice NXM avec

MPI_Send(&(A[0][0]), N*M, MPI_INT, destination, tag, MPI_COMM_WORLD);

et quand vous avez terminé, libérez la mémoire avec

free(A[0]);
free(A);

Aussi, MPI_Recv est une recette de blocage et MPI_Send peut être un envoi de blocage. Une chose qui signifie, selon le point de Joel, est que vous n'avez certainement pas besoin de barrières. En outre, cela signifie que si vous avez un modèle d'envoi/recevez comme ci-dessus, vous pouvez vous mettre dans une situation d'impasse - tout le monde envoie, personne ne reçoit. Plus sûr est:

if (myrank == 0) {
   MPI_Send(&(A[0][0]), N*M, MPI_INT, 1, tagA, MPI_COMM_WORLD);
   MPI_Recv(&(B[0][0]), N*M, MPI_INT, 1, tagB, MPI_COMM_WORLD, &status);
} else if (myrank == 1) {
   MPI_Recv(&(A[0][0]), N*M, MPI_INT, 0, tagA, MPI_COMM_WORLD, &status);
   MPI_Send(&(B[0][0]), N*M, MPI_INT, 0, tagB, MPI_COMM_WORLD);
}

Une autre approche plus générale est d'utiliser MPI_Sendrecv:

int *sendptr, *recvptr;
int neigh = MPI_PROC_NULL;

if (myrank == 0) {
   sendptr = &(A[0][0]);
   recvptr = &(B[0][0]);
   neigh = 1;
} else {
   sendptr = &(B[0][0]);
   recvptr = &(A[0][0]);
   neigh = 0;
}
MPI_Sendrecv(sendptr, N*M, MPI_INT, neigh, tagA, recvptr, N*M, MPI_INT, neigh, tagB, MPI_COMM_WORLD, &status);

ou des envois non bloquants et/ou reçoivent.

36
Jonathan Dursi

Tout d'abord, vous n'avez pas besoin de beaucoup de barrière secondaire, vous devriez vraiment envoyer vos données sous forme de bloc unique en tant que multiples envoi/réception Bloquant leur chemin entraînera de mauvaises performances.

4
Joel Falcou