2012-05-02 23 views
10

Tengo la siguiente estructura.Creando un MPI_Datatype para una estructura que contiene punteros

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

quiero transferir esta estructura utilizando MPI_Send y MPI_Receive. ¿Cómo creo un MPI_Datatype para esta estructura?

+0

¿Por qué querrías enviar punteros entre los procesos de MPI? No son portátiles en sistemas de memoria distribuida. – talonmies

Respuesta

8

Enviar punteros a otra máquina no tiene sentido (sin juego de palabras). Debido al direccionamiento virtual, es probable que el puntero apunte a una ubicación de memoria no válida en la máquina receptora, y aunque no sea así, no ha enviado realmente los datos a los que apuntaba.

Sin embargo, con el uso adecuado de MPI_Address() y un tipo de datos MPI_Hindexed, es posible describir el diseño de la memoria de sus datos (supongo que sus punteros apuntan a matrices dinámicas). P.ej. Si Ai puntos a 3 int s, y Ax puntos a 5 double s, necesitará un tipo Hindexed con 3 bloques: 3 MPI_INT s, 5 s, y , con las compensaciones adquiridas utilizando MPI_Address().

No olvide redefinir y volver a enviar el tipo de datos si cambia el número de elementos que se van a enviar o reasigna las matrices por completo. Y si envía varias estructuras, tendrá que definir y confirmar este tipo de datos para cada una, ya que su tipo de datos MPI es específico de una instancia particular de estas estructuras.

También tenga en cuenta que tendrá que hacer un desempaquetado similarmente complicado en el extremo receptor si desea recrear la estructura original.

+0

Gracias por la ayuda. Intenté esto pero era un camino de ida y vuelta y estaba creando demasiados tipos de datos. Así que cambié mi representación de datos en su lugar. Sí, los punteros fueron a matrices dinámicas. – ap040

9

MPI está diseñado para funcionar con matrices de estructuras en lugar de con estructuras de matrices.

El MPI_Hindexed que @suszterpatt propuso es un truco terrible. Solo le permitirá enviar un elemento del tipo de estructura y solo el elemento que se utilizó para definir el tipo de datos MPI. Para otras variables del mismo tipo de estructura, se garantiza que las compensaciones calculadas serán incorrectas. Además de , los tipos Hindexed usan uno y el mismo tipo de datos MPI para todos los elementos y, por lo tanto, no le permiten enviar tanto ints como dobles.

La cosa sabia que hacer es transformar su programa para utilizar matrices de estructuras:

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

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

Ahora usted puede crear un MPI estructurado tipo point_type y utilizarlo para enviar nz elementos de ese tipo dando column.A como el dirección 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, ...); 

Esta primera crea un tipo de datos MPI point_struct que describe la disposición de los miembros de la estructura, pero no tiene en cuenta ningún relleno en la linea d y, por lo tanto, no se puede usar para enviar de manera confiable una matriz de tales estructuras. Por lo tanto, se crea un segundo tipo de datos point_type con la extensión correcta usando MPI_Type_create_resized.

En el lado receptor que le mirar el mensaje con MPI_Probe, extraer el número de elementos con MPI_Get_count con un tipo de point_type (que va directamente al campo nz), asignar el campo A y utilizarlo en MPI_Recv para recibir el nz elementos:

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

Si ese cambio de código es posible si todavía se puede pasar por la etapa intermedia de la transformación de su estructura antes de enviarlo, un proceso generalmente se llaman (des) cálculo de referencias. En su caso hacer algo como esto (supongo que almacene el número de elementos de la matriz, tanto en Ai y Ax en el 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); 

En el lado receptor debe hacer lo contrario: asignar suficiente una gran búfer que puede contener la estructura, recibir el mensaje en ella y luego hacer la transformación opuesta.

Una vez más, no necesita transmitir el valor real de nz ya que se puede extraer fácilmente de la longitud del mensaje usando MPI_Get_count.

+0

+1 esto es muy informativo – pyCthon

+0

Gracias, esto fue útil. Usé una representación intermedia como sugirió y fue mucho mejor. – ap040

+0

¿Estás seguro del "disp [0]"? Si el elemento cero es un carácter, no sabría si estaba en el byte izquierdo o derecho de la unidad de alineación más pequeña. En otras palabras: calcularía su compensación explícitamente. –

1

"La cosa sabia que hacer es transformar su programa para utilizar matrices de estructuras"

A menudo eso es conceptualmente también mejor.

Me gustaría señalar otro mecanismo: usando MPI_Pack y MPI_Unpack. Por ejemplo, con la estructura original puede empaquetar el primer entero, luego empacar las dos matrices. El receptor descomprimiría el número entero y luego sabría cuántas de las otras cosas para desempaquetar.

Esta es también una buena solución si no se puede acceder directamente a su objeto, pero solo se puede acceder a través de un iterador más o menos.

Cuestiones relacionadas