2017-02-27 4 views
0

Ich möchte eine generische MPI-Methode erstellen, sagen wir eine bcast für ein bestimmtes Objekt. aber ich muss primitive Typen in MPI_Datentypen konvertieren? eine Idee, wie ich es machen kann?Generischer MPI-Code

template <typename T> 
void bcast_data(std::vector<T> vec) 
{ 
... 
} 

Ich brauche für int MPI_INT zu verwenden, MPI_DOUBLE für Doppel, ... so brauche ich ein Typ-Umwandlungsverfahren, dachte ich an eine Enumeration von dataypes schaffen, die mir die MPI_datatypes geben könnte, aber es erfordert Weitergabe der Typ als Eingabeargument.

eine Idee?

Dank

+0

Werfen Sie einen Blick auf boost :: mpi. Es ist im Grunde ein C++ Wrapper für MPI und macht genau das. – OutOfBound

Antwort

2

Sie können "Typ Traits" Idiom verwenden T ein generisches Objekt serialisiert werden. Dies bietet Ihnen den Vorteil, dass Sie Unterstützung für neue Typen hinzufügen können, ohne die Implementierung zu ändern.

Werfen Sie einen Blick auf diese MPI-Wrapper, die ich vor Jahren schrieb: https://github.com/motonacciu/mpp.

Sie wollen eine Art Eigenschaft wie folgt definiert werden: für Betone

template <class T> 
struct mpi_type_traits { 
    typedef T element_type; 
    typedef T* element_addr_type; 

    static inline MPI_Datatype get_type(T&& raw); 
    static inline size_t get_size(T& raw); 
    static inline element_addr_type get_addr(T& raw); 
}; 

und bieten Spezialisierung, zum Beispiel ein std::vector<T> wie folgt:

template <class T> 
struct mpi_type_traits<std::vector<T>> { 

    typedef T element_type; 
    typedef T* element_addr_type; 

    static inline size_t get_size(std::vector<T>& vec) { 
     return vec.size(); 
    } 

    static inline MPI_Datatype get_type(std::vector<T>&& vec) { 
     return mpi_type_traits<T>::get_type(T{}); 
    } 

    static inline element_addr_type get_addr(std::vector<T>& vec) { 
     return mpi_type_traits<T>::get_addr(vec.front()); 
    } 
}; 

Das letzte, was Sie tun müssen, ist Ihre MPI-Methode zu implementieren und die Art Merkmale verwenden, z.B. wenn ein MPI_Send Aufruf:

template <class T> 
void send(T &&value, ...) { 
    MPI_Send(mpi_type_traits<T>::get_addr(value), 
      mpi_type_traits<T>::get_size(value), 
      mpi_type_traits<T>::get_type(value), ...); 
} 
+1

Große Antwort. Eine Sache, die Probleme aufzufordern scheint, besteht darin, das tatsächliche Objekt zu verwenden, um Typinformation zu erhalten (z.B. 'vec.size()'). Das heißt, wenn Sender und Empfänger unterschiedliche Objekte haben, müssen sie sicherstellen, dass kompatible Typen erzeugt werden. Zum Beispiel muss der Empfänger die Sendergröße kennen und die Größe vor dem Empfangen entsprechend ändern. Ich frage mich, wie gehen Sie in Ihrer Implementierung damit um? – Zulan

+0

Dies ist nicht viel anders als der typische Anwendungsfall von MPI. Sender und Empfänger müssen vorher die Länge und Art der gesendeten Objekte wissen. Sie können dies lösen, indem Sie ein Protokoll entwerfen, bei dem ein Deskriptor (mit Größe und möglicherweise Typinformationen) für das Objekt vor dem eigentlichen Objekt gesendet wird. – simpel01

+0

Ich stimme überhaupt nicht zu, aber 1) 'std :: vector' wird normalerweise verwendet, ohne die Größe explizit festzulegen/zu kennen (durch' begin', 'end',' push_back'). Das Aufnehmen der Größe ist für den Benutzer in Ihrer Lösung auch nicht sichtbar. 2) In Boost.MPI können Sie tatsächlich einen Verweis auf einen leeren Vektor übergeben, um darin zu empfangen - bei erheblichen Leistungskosten. 3) Sie könnten 'MPI_Probe' verwenden, um einen Vektor zu erhalten, ohne dessen Größe und ohne eine zusätzliche Nachricht/Serialisierung zu kennen. Ich frage mich, ob es C++ - Abstraktionen gibt, die Letzteres unterstützen. – Zulan

0

habe ich so etwas wie diese, es ist definitiv nicht eine vollständige Antwort, da es einige Arten frei läßt. aber es funktioniert für meinen Fall

template<typename T> 
MPI_Datatype get_type() 
{ 
    char name = typeid(T).name()[0]; 
    switch (name) { 
     case 'i': 
      return MPI_INT; 
      break; 
     case 'f': 
      return MPI_FLOAT; 
      break; 
     case 'j': 
      return MPI_UNSIGNED; 
      break; 
     case 'd': 
      return MPI_DOUBLE; 
      break; 
     case 'c': 
      return MPI_CHAR; 
      break; 
     case 's': 
      return MPI_SHORT; 
      break; 
     case 'l': 
      return MPI_LONG; 
      break; 
     case 'm': 
      return MPI_UNSIGNED_LONG; 
      break; 
     case 'b': 
      return MPI_BYTE; 
      break; 
    } 
}