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
.
Perché mai desidera inviare puntatori tra i processi MPI? Sono non portatili nei sistemi di memoria distribuita. – talonmies