2012-05-02 5 views
10

Ich habe folgende Struktur.Erstellen eines MPI_Datatype für eine Struktur mit Zeigern

typedef struct 
{ 
int *Ai; 
double *Ax; 
int nz; 
}column; 

Ich möchte diese Struktur übertragen MPI_Send und MPI_Receive verwenden. Wie erstelle ich eine MPI_Datatype für diese Struktur?

+0

Warum möchten Sie jemals Zeiger zwischen MPI-Prozessen senden? Sie sind in verteilten Speichersystemen nicht tragbar. – talonmies

Antwort

8

Das Senden von Zeigern zu einer anderen Maschine ist sinnlos (kein Wortspiel beabsichtigt). Aufgrund der virtuellen Adressierung wird der Zeiger wahrscheinlich auf einen ungültigen Speicherort auf dem empfangenden Computer zeigen, und selbst wenn nicht, haben Sie nicht die Daten tatsächlich gesendet, auf die es zeigte.

Mit der richtigen Verwendung von MPI_Address() und einem MPI_Hindexed-Datentyp ist es jedoch möglich, das Speicherlayout Ihrer Daten zu beschreiben (ich nehme an, dass Ihre Zeiger auf dynamische Arrays zeigen). Z.B. wenn Ai Punkte auf 3 int s und Ax Punkte auf 5 double s, benötigen Sie einen Hindexed Typen mit 3 Blöcken: 3 MPI_INT s, 5 MPI_DOUBLE s und 1 MPI_INT mit der Offsets MPI_Address() erworben.

Vergessen Sie nicht, den Datentyp neu zu definieren und erneut zu verwenden, wenn Sie die Anzahl der zu sendenden Elemente ändern oder die Arrays vollständig neu zuweisen. Und wenn Sie mehrere Strukturen senden, müssen Sie diesen Datentyp für jeden definieren und festschreiben, da Ihr MPI-Datentyp für eine bestimmte Instanz dieser Strukturen spezifisch ist.

Denken Sie auch daran, dass Sie auf der Empfängerseite ein ähnlich schwieriges Entpacken durchführen müssen, wenn Sie die ursprüngliche Struktur wiederherstellen möchten.

+0

Danke für die Hilfe. Ich habe es versucht, aber es war eine runde Sache und hat zu viele Datentypen erstellt. Also habe ich stattdessen meine Datendarstellung geändert. Ja, die Zeiger waren auf dynamische Arrays. – ap040

9

MPI ist entworfen, um mit Arrays von Strukturen eher als mit Strukturen von Arrays zu arbeiten.

Die MPI_Hindexed die @suszterpatt vorgeschlagen ist ein schrecklicher Hack. Sie können nur ein Element des Strukturtyps und nur das Element senden, mit dem der Datentyp MPI definiert wurde. Bei anderen Variablen des gleichen Strukturtyps ist meistens sichergestellt, dass die berechneten Offsets falsch sind. Neben Hindexed Typen verwenden ein und denselben MPI-Datentyp für alle Elemente und damit können Sie nicht sowohl Eingänge und Doppel senden.

Die kluge Sache zu tun ist, Ihr Programm zu verwandeln Arrays von Strukturen zu verwenden:

typedef struct 
{ 
    int i; 
    double z; 
} point; 

typedef struct 
{ 
    point *A; 
    int nz; 
} column; 

Jetzt können Sie eine MPI-strukturierter Typ point_type und verwenden Sie es schaffen nz Elemente dieses Typs senden column.A als die Angabe Pufferadresse:

int lens[3]; 
MPI_Aint base, disps[2]; 
MPI_Datatype oldtypes[2], point_struct, point_type; 

MPI_Get_address(&point, disps); 
MPI_Get_address(&point.z, disps+1); 
base = disps[0]; 

lens[0] = 1; disps[0] = MPI_Aint_diff(disps[0], base); oldtypes[0] = MPI_INT; 
lens[1] = 1; disps[1] = MPI_Aint_diff(disps[1], base); oldtypes[1] = MPI_DOUBLE; 
MPI_Type_create_struct(2, lens, disps, oldtypes, &point_struct); 
MPI_Type_create_resized(point_struct, 0, sizeof(point), &point_type); 
MPI_Type_commit(&point_type); 

MPI_Send(column.A, column.nz, point_type, ...); 

Diese erste erstellt eine MPI-Datentyp point_struct, die das Layout der Strukturelemente beschreibt, sondern für jede Polsterung nicht berücksichtigt bei der en d und kann daher nicht verwendet werden, um ein Array solcher Strukturen zuverlässig zu senden. Daher wird ein zweiter Datentyp point_type mit dem richtigen Umfang erstellt, indem MPI_Type_create_resized verwendet wird.

Auf der Empfängerseite die Nachricht mit MPI_Probe, extrahiert die Anzahl der Elemente mit MPI_Get_count mit einer Art von point_type (das geht direkt zu dem nz Feld), zuteilen das A Feld und es verwendet, in MPI_Recv peek würde die erhalten nz Elemente:

MPI_Status status; 
MPI_Probe(source, tag, comm, &status); 
MPI_Get_count(&status, point_type, &column.nz); 
if (nz == MPI_UNDEFINED) 
    ... non-integral message was received, do something 
column.A = (point *)malloc(column.nz*sizeof(point)); 
MPI_Recv(column.A, column.nz, point_type, source, tag, comm, MPI_STATUS_IGNORE); 

Wenn das Codeänderung ist nicht möglich, Sie immer noch Ihre Struktur durch den Zwischenschritt der Transformation vor dem Senden gehen können, ein Prozess in der Regel (un-) Marshalling genannt. In Ihrem Fall etwas tun (ich nehme an, dass Sie die Anzahl der Array-Elemente in beiden Ai speichern und Ax im nz Feld):

point *temp = (point *)malloc(nz*sizeof(point)); 
for (int i = 0; i < column.nz; i++) 
{ 
    temp[i].i = column.Ai[i]; 
    temp[i].z = column.Az[i]; 
} 
MPI_Send(temp, nz, point_type, ...); 
free(temp); 

Auf der Empfängerseite Sie das Gegenteil tun müssen: zuteilen eine ausreichend große Puffer, der die Struktur halten kann, die Nachricht darin empfangen und dann die umgekehrte Umwandlung durchführen.

Erneut müssen Sie den tatsächlichen Wert nz nicht übertragen, da er einfach aus der Länge der Nachricht mit MPI_Get_count extrahiert werden kann.

+0

+1 das ist sehr informativ – pyCthon

+0

Danke, das war hilfreich. Ich habe eine Zwischenrepräsentation verwendet, wie Sie es vorgeschlagen haben, und es war viel besser. – ap040

+0

Sind Sie sicher über "disp [0]"? Wenn das Nullelement ein Zeichen ist, würde ich nicht wissen, ob es in dem linken oder rechten Byte der kleinsten Ausrichtungseinheit war. Mit anderen Worten: Ich würde seinen Offset explizit berechnen. –

1

„Die kluge Sache zu tun ist, Ihr Programm zu verwandeln Arrays von Strukturen zu verwenden“

Oft das ist vom Konzept her auch besser.

Ich möchte auf einen anderen Mechanismus hinweisen: mit MPI_Pack und MPI_Unpack. Zum Beispiel könnten Sie mit der ursprünglichen Struktur die erste Ganzzahl packen und dann die beiden Gruppen packen. Der Empfänger würde die ganze Zahl entpacken und dann wissen, wie viele der anderen Dinger auszupacken sind.

Dies ist auch eine gute Lösung, wenn Ihr Objekt nicht direkt zugänglich ist, aber nur über einen Iterator oder so zugegriffen werden kann.

Verwandte Themen