2012-03-25 13 views
27

He definido una estructura personalizada y quiero enviarla a otro proceso MPI utilizando MPI_Bsend (o MPI_Send).serialización de estructuras en C y transferencia sobre MPI

Aquí es mi estructura:

struct car{ 
    int shifts; 
    int topSpeed; 
}myCar; 

Sin embargo, aparte de los tipos primitivos MPI no parecen apoyar la "transmisión" directa de los tipos de datos complejos como la estructura anteriormente. He oído que podría tener que usar "serialización". ¿Cómo debo hacerlo y enviar 'myCar' al proceso 5?

Respuesta

48

Jeremiah tiene razón - MPI_Type_create_struct es el camino a seguir aquí.

Es importante recordar que MPI es una biblioteca, no está integrada en el idioma; por lo tanto, no puede "ver" cómo se ve una estructura para serializarla por sí misma. Entonces, para enviar tipos de datos complejos, debe definir explícitamente su diseño. En un lenguaje que tiene soporte nativo para la serialización, un conjunto de envoltorios MPI puede hacer uso de eso; mpi4py utiliza, por ejemplo, el pickle de python para enviar de forma transparente tipos de datos complejos; pero en C, tienes que arremangarte y hacerlo tú mismo.

Por su estructura, que se parece a esto:

#include <stdio.h> 
#include <stdlib.h> 
#include <mpi.h> 
#include <stddef.h> 

typedef struct car_s { 
     int shifts; 
     int topSpeed; 
} car; 

int main(int argc, char **argv) { 

    const int tag = 13; 
    int size, rank; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 

    if (size < 2) { 
     fprintf(stderr,"Requires at least two processes.\n"); 
     exit(-1); 
    } 

    /* create a type for struct car */ 
    const int nitems=2; 
    int   blocklengths[2] = {1,1}; 
    MPI_Datatype types[2] = {MPI_INT, MPI_INT}; 
    MPI_Datatype mpi_car_type; 
    MPI_Aint  offsets[2]; 

    offsets[0] = offsetof(car, shifts); 
    offsets[1] = offsetof(car, topSpeed); 

    MPI_Type_create_struct(nitems, blocklengths, offsets, types, &mpi_car_type); 
    MPI_Type_commit(&mpi_car_type); 

    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    if (rank == 0) { 
     car send; 
     send.shifts = 4; 
     send.topSpeed = 100; 

     const int dest = 1; 
     MPI_Send(&send, 1, mpi_car_type, dest, tag, MPI_COMM_WORLD); 

     printf("Rank %d: sent structure car\n", rank); 
    } 
    if (rank == 1) { 
     MPI_Status status; 
     const int src=0; 

     car recv; 

     MPI_Recv(&recv, 1, mpi_car_type, src, tag, MPI_COMM_WORLD, &status); 
     printf("Rank %d: Received: shifts = %d topSpeed = %d\n", rank, 
       recv.shifts, recv.topSpeed); 
    } 

    MPI_Type_free(&mpi_car_type); 
    MPI_Finalize(); 

    return 0; 
} 
+0

Gracias por su respuesta muy completa y rápida. Realmente lo aprecio. Me tienes completamente cubierto. (Sin embargo, creo que se olvidó de incluir en la causa principal; de lo contrario, el compilador genera errores ...) – kstratis

+0

Tiene razón: es necesario para el offsetof(). He actualizado el código apropiadamente. –

5

Mire MPI_Type_create_struct para crear un tipo de datos MPI personalizado para su objeto. Un ejemplo de uso está en http://beige.ucs.indiana.edu/I590/node100.html.

+0

Todavía estoy un poco confundido ..! Supongamos que defino la estructura MPI y ahora quiero usarla.El enlace que ha indicado establece: MPI_Type_create_struct (5, array_of_block_lengths, array_of_displacements, array_of_types, & new_type); ¿Debo hacer algo como myCar = & new_type? – kstratis

+0

Y más al punto ... ¿Podría darme un ejemplo simple pero concreto de crear y transmitir la estructura específica? – kstratis

+0

Problema resuelto. El enlace que proporcionó brinda toda la "teoría" pero puede confundir fácilmente a los programadores aficionados debido a los desplazamientos y los detalles de bajo nivel. Sin embargo, parece describir con precisión el mecanismo subyacente. – kstratis

6

Aunque la respuesta de Jonathan Dursi es correcta, es demasiado complicado. MPI proporciona constructores de tipo más simples y menos generales más adecuados para su problema. MPI_Type_create_struct SOLO se necesita cuando tiene diferentes tipos de base (por ejemplo, un int y un float).

Para su ejemplo, existen varias soluciones mejores:

  • Suponiendo que los dos números enteros están alineados en una zona de memoria contigua (es decir, como una matriz de enteros), que no es necesario un tipo de datos derivados en absoluto. Sólo tienes que enviar/recibir dos elementos de tipo MPI_INT con la dirección de una variable de tipo car para ser utilizado como el envío/recepción de buffer:

    MPI_Send(&send, 2, MPI_INT, dest, tag, MPI_COMM_WORLD); 
    MPI_Recv(&recv, 2, MPI_INT, src, tag, MPI_COMM_WORLD, &status); 
    
  • Si desea utilizar un tipo de datos derivados (por ejemplo, para facilitar la lectura o el gusto de hacerlo), puede utilizar MPI_Type_contiguous que corresponde a las matrices:

    MPI_Type_contiguous(2, MPI_INT, &mpi_car_type); 
    
  • En caso de que los dos números enteros, están alineados de manera diferente (la mayoría no es probable el caso, pero depende de la máquina y existen implementaciones de MPI para muchos de diferentes plataformas), puede usar MPI_Type_indexed_block: Se toma una matriz de desplazamientos (como MPI_Type_create_struct), pero sólo un argumento oldtype y el bloque de longitud de cada bloque es 1 por definición:

    MPI_Aint offsets[2]; 
    offsets[0] = offsetof(car, shifts) ; //most likely going to be 0 
    offsets[1] = offsetof(car, topSpeed); 
    MPI_Type_indexed_block(2, offsets, MPI_INT); 
    

Mientras que la otra solución es semánticamente correcta, es mucho más difícil de leer y puede incurrir en una gran penalización de rendimiento.