MPI_Type_create_subarray und MPI_Gather
Habe ich zu lösen, ein wenig mpi problem. Ich habe 4 slaves verarbeitet und jede dieser schicken will, ein 2d-subarray (CHUNK_ROWS X CHUNK_COLUMNS) zur master-0. Master 0 sammelt alle Brocken in ddd[ZEILEN][SPALTEN], und drucken Sie es. Ich will MPI_Gather()
#include <mpi.h>
#include <iostream>
using namespace std;
#define ROWS 10
#define COLUMNS 10
#define CHUNK_ROWS 5
#define CHUNK_COLUMNS 5
#define TAG 0
int** alloca_matrice(int righe, int colonne)
{
int** matrice=NULL;
int i;
matrice = (int **)malloc(righe * sizeof(int*));
if(matrice != NULL){
matrice[0] = (int *)malloc(righe*colonne*sizeof(int));
if(matrice[0]!=NULL)
for(i=1; i<righe; i++)
matrice[i] = matrice[0]+i*colonne;
else{
free(matrice);
matrice = NULL;
}
}
else{
matrice = NULL;
}
return matrice;
}
int main(int argc, char* argv[])
{
int my_id, numprocs,length,i,j;
int ndims, sizes[2],subsizes[2],starts[2];
int** DEBUG_CH=NULL;
int** ddd=NULL;
char name[BUFSIZ];
MPI_Datatype subarray=NULL;
//MPI_Status status;
MPI_Init(&argc, &argv) ;
MPI_Comm_rank(MPI_COMM_WORLD, &my_id) ;
MPI_Comm_size(MPI_COMM_WORLD, &numprocs) ; //Ottiene quanti processi sono attivi
MPI_Get_processor_name(name, &length);
if(my_id!=0){
//creo una sottomatrice ripulita dalle ghost cells
ndims=2;
sizes[0] = CHUNK_ROWS+2;
sizes[1] = CHUNK_COLUMNS+2;
subsizes[0] = CHUNK_ROWS;
subsizes[1] = CHUNK_COLUMNS;
starts[0] = 1;
starts[1] = 1;
MPI_Type_create_subarray(ndims,sizes,subsizes,starts,MPI_ORDER_C,MPI_INT,&subarray);
MPI_Type_commit(&subarray);
DEBUG_CH = alloca_matrice(CHUNK_ROWS+2,CHUNK_COLUMNS+2);
for(i=0; i<CHUNK_ROWS+2; i++){
for(j=0; j<CHUNK_COLUMNS+2; j++){
if(i==0 || i==CHUNK_ROWS+1 || j==0 || j==CHUNK_COLUMNS+1)
DEBUG_CH[i][j] = 5;
else
DEBUG_CH[i][j] = 1;
}
}
//MPI_Send(DEBUG_CH[0],1,subarray,0,TAG,MPI_COMM_WORLD);
}
if(my_id==0){
ddd = alloca_matrice(ROWS,COLUMNS);
}
MPI_Gather(DEBUG_CH[0],1,subarray,ddd[0],CHUNK_ROWS*CHUNK_COLUMNS,MPI_INT,0,MPI_COMM_WORLD);
if(!my_id){
for(i=0; i<ROWS; i++){
for(j=0; j<COLUMNS; j++){
printf("%d ",ddd[i][j]);
}
printf("\n");
}
}
if(my_id)
MPI_Type_free(&subarray);
MPI_Finalize(); //Chiusura di MPI.
return 0;
}
Danke an alle.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Also das ist ein wenig subtiler und erfordert ein gewisses Verständnis von, wie das Sammeln von kollektiven Orten, die komplexe Typen.
Wenn man sich die meisten Beispiele von MPI_Gather, Sie sind von 1-d-arrays, und es ist ziemlich einfach zu interpretieren, was geschehen soll; Sie sind immer (sagen wir) 10 int-Werte aus jedem Prozess und zu Sammeln ist smart genug, um das 10 int-Werte von Rang 0 an den start, die 10 von Rang 1 an den Positionen 10-19 in das array, und so weiter.
Mehr komplexe layouts wie diese sind ein wenig komplizierter, aber. Zunächst das Format der Daten von der sender-Sicht unterscheidet sich von der layout-Daten aus dem Empfänger. In den sender-Sicht, Sie beginnen bei array-element
[1][2]
gehen Sie zu[1][5]
(in ein array der Größe 7x7), dann springen Sie auf array-Elemente[2][3]
-[2][5]
usw.Es gibt CHUNK_ROWS Blöcke von Daten, getrennt durch jeweils 2 ints.
Nun überlegen, wie der Empfänger hat, um Sie zu empfangen. Lassen Sie uns sagen, es ist empfangen von Rang 0 ist-Daten. Es geht zu erhalten, die in array-Elemente
[0][0]-[0][4]
-- so weit, so gut; aber dann ist es für den nächsten block von Daten in[1][0]-[1][4]
in ein array der Größe 10x10. Das ist ein Sprung über die 5 Elemente. Das layout im memory ist anders. So wird der Empfänger zu empfangen und in eine andereSubarray
geben Sie dann den Absender senden aus, da der Speicher-layout ist anders.So, während Sie könnte gesendet werden, von etwas, das aussieht wie dieses:
werden Sie empfangen in etwas, das aussieht wie dieses:
Entscheidend, den Unterschied in der
sizes
array.Nun sind wir immer ein wenig näher. Beachten Sie, Ihre MPI_Gather Linie verpasst, so etwas wie dieses:
Gab es ein paar Dinge, die nicht funktioniert hat zu der vorherigen version
MPI_Gather(DEBUG_CH[0],1,subarray,ddd[0],CHUNK_ROWS*CHUNK_COLUMNS,MPI_INT,0,MPI_COMM_WORLD);
-- beachten Sie zunächst, dass Sie verweisenddd[0]
, aber für jeden Rang, außer Rang 0,ddd=NULL
, und so wird dies scheitern. So erstellen Sie eine neue variable namens sagenrecvptr
, und in Rang null, aufddd[0]
. (Es spielt keine Rolle, wo die anderen Prozesse denken, es ist, wie Sie sind nicht erhalten.) Außerdem denke ich, dass Sie nicht wollen, zu empfangenCHUNK_ROWS*CHUNK_COLUMS
MPI_INTs
, denn damit wären Sie zusammenhängend in den Speicher, und mein Verständnis ist, dass Sie wollen, Sie Lagen auf dem gleichen Weg wie auf der slave-tasks, aber in den größeren array.Ok, so, jetzt sind wir immer irgendwo, aber die oben noch wird nicht funktionieren, für einen interessanten Grund. Für den 1d-array-Beispiele ist es leicht genug, um herauszufinden, wo der N-TEN Reihen von Daten geht. Die Art, wie es berechnet wird, indem der Umfang der Daten erhalten, und ab dem nächsten element nur nach diesem einen. Aber das funktioniert hier nicht. "Gleich nach" das Ende der Rang-null-Daten nicht dort, wo Rang eins der Daten gestartet werden soll (
[0][5]
), aber stattdessen[4][5]
-- das element nach dem letzten element im Rang 0s subarray. Hier die Daten, die Sie Eingang aus verschiedenen Reihen überlappt! So werden wir zu tüfteln, mit den Grenzen der Datentypen auf, die Sie manuell angeben, wo die einzelnen rank-Daten beginnt. Der zweite ist der einfache Teil; Sie nutzen die MPI_Gatherv Funktion, wenn Sie brauchen, um manuell geben Sie die Menge der Daten, die von jedem Prozessor, oder, wo es geht. Der erste ist der schwierigste Teil.MPI lassen Sie uns geben Sie die unteren und oberen Grenzen der angegebenen Daten geben -- wo, ein Stück Erinnerung, das erste bit der Daten, die für diese Art gehen würde, und wo er "endet", die hier nur bedeutet, wo der nächste starten konnte. (Die Daten erstrecken kann, vorbei an der oberen Grenze der Typ, die würde ich argumentieren, macht diese Namen irreführend, aber so ist der Lauf der Dinge.) Sie können angeben, dass dies, was Sie wollen, dass macht es einfacher für Sie; da wir den Umgang mit Elementen, die in einer
int
array, lassen Sie uns das Ausmaß unserer Art eine MPI_INT in der Größe.(Hinweis: wir haben nur dazu, die erhaltene Art; von der Art der Versendung, da wir nur das senden einer von Ihnen, es spielt keine Rolle).
Nun, wir verwenden gatherv, um anzugeben, wo jedes element beginnt-in Einheiten der "Größe" dieser neuen Größe angepasst geben, die nur 1 integer. Also, wenn wir etwas wollen, gehen Sie in der großen Auswahl an
[0][5]
die Verschiebung vom start des large-array ist 5, und wenn wir wollen, dass es gehen Sie dort an der position[5][5]
die Verschiebung ist 55.Beachten Sie schließlich, dass die gather-und scatter-kollektive gehen alle davon aus, dass auch der "master" beteiligt ist. Es ist am einfachsten, dies funktioniert, wenn sogar der Meister hat Ihr eigenes Stück des globalen Arrays.
Also, Folgendes funktioniert bei mir: