24 Stimmen

Senden und Empfangen von 2D-Arrays über MPI

Das Problem, das ich zu lösen versuche, ist folgendes:

Der serielle C++-Code, den ich habe, rechnet über eine große 2D-Matrix. Um diesen Prozess zu optimieren, möchte ich diese große 2D-Matrix aufteilen und mit MPI auf (sagen wir) 4 Knoten ausführen. Die einzige Kommunikation, die zwischen den Knoten stattfindet, ist die gemeinsame Nutzung der Kantenwerte am Ende eines jeden Zeitschritts. Jeder Knoten teilt die Daten der Kantenmatrix, A[i][j], mit seinem Nachbarn.

Basierend auf der Lektüre über MPI, habe ich das folgende Schema zu implementieren.

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
}

Ich wollte wissen, ob mein Ansatz richtig ist und wäre auch dankbar für Hinweise auf andere MPI-Funktionen, die ich für die Implementierung in Betracht ziehen sollte.

Danke, Ashwin.

44voto

Jonathan Dursi Punkte 48657

Um Joels Argumente noch ein wenig zu verstärken:

Dies geht viel einfacher, wenn Sie Ihre Arrays so zuordnen, dass sie zusammenhängend sind (etwas, das C's "multidimensionale Arrays" nicht automatisch bieten:)

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);

Dann können Sie Sendungen und Empfänge des gesamten NxM-Arrays mit

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

und wenn Sie fertig sind, geben Sie den Speicher mit

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

Auch, MPI_Recv ist ein blockierender Empfänger, und MPI_Send kann eine blockierende Sendung sein. Eine Sache, die das bedeutet, wie Joel sagte, ist, dass man definitiv keine Barrieren braucht. Außerdem bedeutet es, dass man sich in eine Sackgasse manövrieren kann, wenn man ein Sende-/Empfangsschema wie oben hat - jeder sendet, keiner empfängt. Sicherer ist:

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);
}

Ein anderer, allgemeinerer Ansatz ist die Verwendung von 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);

oder nicht blockierende Sends und/oder Recieves.

4voto

Joel Falcou Punkte 6057

Erstens brauchen Sie nicht so viel Barriere Zweitens sollten Sie Ihre Daten wirklich in einem einzigen Block senden, da mehrere Sende-/Empfangsblocks zu einer schlechten Leistung führen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X