2012-03-25 17 views
27

Ho definito una struttura personalizzata e desidero inviarla a un altro processo MPI utilizzando MPI_Bsend (o MPI_Send).serializzazione della struct in C e trasferimento su MPI

Ecco il mio struct:

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

Tuttavia, a parte tipi primitivi MPI non sembra supportare "trasmissione" diretta dei tipi di dati complessi come struct sopra. Ho sentito che potrei dover usare "serializzazione". Come dovrei andare su di esso e inviare su 'myCar' per elaborare 5?

risposta

48

Jeremiah ha ragione - MPI_Type_create_struct è il modo per andare qui.

È importante ricordare che MPI è una libreria, non integrata nella lingua; quindi non può "vedere" come appare una struttura per serializzarlo da solo. Pertanto, per inviare tipi di dati complessi, è necessario definirne esplicitamente il layout. In una lingua che ha il supporto nativo per la serializzazione, una serie di wrapper MPI può in qualche modo farne uso; mpi4py, ad esempio, utilizza python pickle per inviare in modo trasparente tipi di dati complessi; ma in C, devi rimboccarti le maniche e farlo da solo.

Per la vostra struttura, sembra che questo:

#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

Grazie per la tua risposta completa e rapida. Lo apprezzo molto. Mi hai completamente coperto. (Comunque penso che ti sia dimenticato di includere in alto perché altrimenti il ​​compilatore dà errori ..) – kstratis

+0

Hai ragione - serve per l'offset di(). Ho aggiornato il codice in modo appropriato. –

5

Vedere MPI_Type_create_struct per creare un tipo di dati MPI personalizzato per il proprio oggetto. Un esempio di utilizzo è http://beige.ucs.indiana.edu/I590/node100.html.

+0

Sono ancora un po 'confuso ... Supponiamo di definire la struttura MPI e ora voglio usarlo.Il link che hai fornito dichiara: MPI_Type_create_struct (5, array_of_block_lengths, array_of_displacements, array_of_types, & new_type); Dovrei ora fare qualcosa come myCar = & new_type? – kstratis

+0

E altro al punto ... Potresti per favore darmi un esempio semplice ma concreto di creare e trasmettere la struttura specifica? – kstratis

+0

Problema risolto. Il link che hai fornito fornisce tutta la "teoria", ma potrebbe facilmente confondere i programmatori dilettanti a causa degli spostamenti e dei dettagli di basso livello. Tuttavia sembra proprio descrivere il meccanismo sottostante. – kstratis

6

Anche se la risposta di Jonathan Dursi è corretta, è troppo complicato. MPI fornisce costruttori di tipi più semplici e meno generali più adatti al tuo problema. MPI_Type_create_struct è SOLO necessario quando si hanno diversi tipi di base (ad es., Int e float).

Per esempio, diverse soluzioni migliori esistono:

  • Supponendo che i due interi sono allineati in un'area di memoria contigua (vale a dire, come un array di interi), non è necessario un tipo di dati derivato affatto. Basta inviare/ricevere due elementi di tipo MPI_INT con l'indirizzo di una variabile di tipo car da utilizzare come l'invio/ricezione buffer:

    MPI_Send(&send, 2, MPI_INT, dest, tag, MPI_COMM_WORLD); 
    MPI_Recv(&recv, 2, MPI_INT, src, tag, MPI_COMM_WORLD, &status); 
    
  • Se si desidera utilizzare un tipo di dati derivati ​​(ad esempio, per migliorare la leggibilità o il gusto di farlo), è possibile utilizzare MPI_Type_contiguous che corrisponde ad array:

    MPI_Type_contiguous(2, MPI_INT, &mpi_car_type); 
    
  • Nel caso in cui i due interi sono allineate in modo diverso (la maggior parte non probabile il caso, ma è dipendente dalla macchina ed esistono implementazioni MPI per un sacco di diverse piattaforme), è possibile utilizzare MPI_Type_indexed_block: Si prende un array di spostamenti (come MPI_Type_create_struct), ma solo argomento oldtype e il blocco di lunghezza di ogni blocco è 1 per definizione:

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

Mentre l'altra soluzione è semanticamente corretta, è molto più difficile da leggere e può comportare una grossa penalizzazione delle prestazioni.