2012-05-02 12 views

risposta

8

L'invio di puntatori a un'altra macchina è inutile (non è previsto il gioco di parole). A causa dell'indirizzamento virtuale, il puntatore probabilmente punta a una posizione di memoria non valida sulla macchina ricevente, e anche in caso contrario, non hai effettivamente inviato i dati a cui puntava.

Tuttavia, con l'uso corretto di MPI_Address() e un tipo di dati MPI_Hindexed, è possibile descrivere il layout di memoria dei dati (presumo che i puntatori puntino agli array dinamici). Per esempio. se Ai punti a 3 int s, e Ax punti a 5 double s, avrete bisogno di un tipo di Hindexed con 3 blocchi: 3 MPI_INT s, 5 MPI_DOUBLE s, e 1 MPI_INT, con gli offset acquisite utilizzando MPI_Address().

Non dimenticare di ridefinire e ricominciare il tipo di dati se si modifica il numero di elementi da inviare o riallineare interamente gli array. E se stai inviando più strutture, dovrai definire e impegnare questo tipo di dati per ognuna, poiché il tuo tipo di dati MPI è specifico per una particolare istanza di queste strutture.

Ricordare inoltre che sarà necessario eseguire un disimballaggio altrettanto delicato sul lato ricevente se si desidera ricreare la struttura originale.

+0

Grazie per l'aiuto. Ho provato questo, ma era un modo approssimativo e stava creando troppi tipi di dati. Quindi ho cambiato la mia rappresentazione dei dati. Sì, i riferimenti erano agli array dinamici. – ap040

9

MPI è progettato per funzionare con array di strutture piuttosto che con strutture di array.

Il MPI_Hindexed che @suszterpatt ha proposto è un terribile hack. Permetterà solo di inviare un elemento del tipo di struttura e solo l'elemento che è stato utilizzato per definire il tipo di dati MPI. Per altre variabili dello stesso tipo di struttura è in gran parte garantito che gli offset calcolati saranno errati. Inoltre i tipi Hindexed utilizzano uno stesso tipo di dati MPI per tutti gli elementi e quindi non consentono di inviare sia ints che double.

La cosa saggia da fare è quello di trasformare il vostro programma di utilizzare array di strutture:

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

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

Ora è possibile creare un MPI tipo strutturato point_type e utilizzarlo per inviare nz elementi di quel tipo dando column.A come il indirizzo del buffer:

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

Questa prima crea un tipo di dati MPI point_struct che descrive la disposizione dei membri della struttura, ma non tiene conto di imbottitura in en e quindi non può essere utilizzato per inviare in modo affidabile una matrice di tali strutture. Pertanto, un secondo tipo di dati point_type con l'estensione corretta viene creato utilizzando MPI_Type_create_resized.

Sul lato del ricevitore si sbirciare il messaggio con MPI_Probe, estrarre il numero di elementi con MPI_Get_count con un tipo di point_type (che va dritto al campo nz), allocare il campo A e utilizzarlo in MPI_Recv per ricevere il nz elementi:

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

Se questa modifica del codice è impossibile si può ancora passare attraverso il passaggio intermedio di trasformare la struttura prima di inviarlo, un processo di solito chiamati (ONU) marshalling. Nel tuo caso fare qualcosa di simile (suppongo che si memorizza il numero di elementi di matrice sia Ai e Ax nel campo nz):

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

Sul lato del ricevitore è necessario fare il contrario: allocare abbastanza grande buffer che può contenere la struttura, ricevere il messaggio al suo interno e quindi eseguire la trasformazione opposta.

Ancora una volta, non è necessario trasmettere il valore effettivo di nz poiché può essere facilmente estratto dalla lunghezza del messaggio utilizzando MPI_Get_count.

+0

+1 questo è molto istruttivo – pyCthon

+0

Grazie, questo è stato utile. Ho usato una rappresentazione intermedia come mi hai suggerito ed era molto meglio. – ap040

+0

Sei sicuro del "disp [0]"? Se l'elemento zero è un carattere, non saprei se fosse nel byte sinistro o destro della più piccola unità di allineamento. In altre parole: calcolerei il suo offset in modo esplicito. –

1

"La cosa saggia da fare è quello di trasformare il vostro programma di utilizzare matrici di strutture"

Spesso questo è concettualmente anche meglio.

vorrei sottolineare un altro meccanismo: utilizzando MPI_Pack e MPI_Unpack. Ad esempio, con la struttura originale è possibile comprimere il primo numero intero, quindi imballare i due array. Il ricevitore decomprimerà il numero intero e poi saprà quanti altri oggetti disfare.

Questa è anche una buona soluzione se l'oggetto non è direttamente accessibile, ma è accessibile solo attraverso un iteratore o giù di lì.

Problemi correlati