1 #ifndef _MPI_OP_H 2 #define _MPI_OP_H 3 4 #include <iostream> 5 #include <typeinfo> 6 #include <map> 7 #include <functional> 8 #include <mpi.h> 9 #include <stdint.h> 10 #include "Operations.h" 11 #include "MPIType.h" // type_info_compare definition 12 13 namespace combblas { 14 15 class MPIOpCache 16 { 17 private: 18 typedef std::map<std::type_info const*, MPI_Op, type_info_compare> stored_map_type; 19 stored_map_type map; 20 21 public: clear()22 void clear() 23 { 24 int is_finalized=0; 25 MPI_Finalized(&is_finalized); 26 if (! is_finalized ) // do not free after call to MPI_FInalize 27 { 28 // ignore errors in the destructor 29 for (stored_map_type::iterator it=map.begin(); it != map.end(); ++it) 30 { 31 MPI_Op_free(&(it->second)); 32 } 33 } 34 } ~MPIOpCache()35 ~MPIOpCache() 36 { 37 clear(); 38 } get(const std::type_info * t)39 MPI_Op get(const std::type_info* t) 40 { 41 stored_map_type::iterator pos = map.find(t); 42 if (pos != map.end()) 43 return pos->second; 44 else 45 return MPI_OP_NULL; 46 } 47 set(const std::type_info * t,MPI_Op datatype)48 void set(const std::type_info* t, MPI_Op datatype) 49 { 50 #ifdef NOTGNU 51 if (map.find(t) != map.end()) map.erase(t); 52 map.insert(std::make_pair(t, datatype)); 53 #else 54 map[t] = datatype; 55 #endif 56 } 57 }; 58 59 extern MPIOpCache mpioc; // global variable 60 61 62 // MPIOp: A class that has a static op() function that takes no arguments and returns the corresponding MPI_Op 63 // if and only if the given Op has a mapping to a valid MPI_Op 64 // No concepts checking for the applicability of Op on the datatype T at the moment 65 // In the future, this can be implemented via metafunction forwarding using mpl::or_ and mpl::bool_ 66 67 template <typename Op, typename T, typename Enable = void> 68 struct MPIOp 69 { funcmpiMPIOp70 static void funcmpi(void * invec, void * inoutvec, int * len, MPI_Datatype *datatype) 71 { 72 Op myop; // you need to create the object instance 73 T * pinvec = static_cast<T*>(invec); 74 T * pinoutvec = static_cast<T*>(inoutvec); 75 for (int i = 0; i < *len; i++) 76 { 77 pinoutvec[i] = myop(pinvec[i], pinoutvec[i]); 78 } 79 } opMPIOp80 static MPI_Op op() 81 { 82 std::type_info const* t = &typeid(Op); 83 MPI_Op foundop = mpioc.get(t); 84 85 if (foundop == MPI_OP_NULL) 86 { 87 MPI_Op_create(funcmpi, false, &foundop); 88 89 int myrank; 90 MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 91 if(myrank == 0) 92 std::cout << "Creating a new MPI Op for " << t->name() << std::endl; 93 94 mpioc.set(t, foundop); 95 } 96 return foundop; 97 } 98 }; 99 100 template<typename T> struct MPIOp< maximum<T>,T,typename std::enable_if<std::is_pod<T>::value, void>::type > { static MPI_Op op() { return MPI_MAX; } }; 101 template<typename T> struct MPIOp< minimum<T>,T,typename std::enable_if<std::is_pod<T>::value, void>::type > { static MPI_Op op() { return MPI_MIN; } }; 102 template<typename T> struct MPIOp< std::plus<T>,T,typename std::enable_if<std::is_pod<T>::value, void>::type > { static MPI_Op op() { return MPI_SUM; } }; 103 template<typename T> struct MPIOp< std::multiplies<T>,T,typename std::enable_if<std::is_pod<T>::value, void>::type > { static MPI_Op op() { return MPI_PROD; } }; 104 template<typename T> struct MPIOp< std::logical_and<T>,T,typename std::enable_if<std::is_pod<T>::value, void>::type > { static MPI_Op op() { return MPI_LAND; } }; 105 template<typename T> struct MPIOp< std::logical_or<T>,T,typename std::enable_if<std::is_pod<T>::value, void>::type > { static MPI_Op op() { return MPI_LOR; } }; 106 template<typename T> struct MPIOp< logical_xor<T>,T,typename std::enable_if<std::is_pod<T>::value, void>::type > { static MPI_Op op() { return MPI_LXOR; } }; 107 template<typename T> struct MPIOp< bitwise_and<T>,T,typename std::enable_if<std::is_pod<T>::value, void>::type > { static MPI_Op op() { return MPI_BAND; } }; 108 template<typename T> struct MPIOp< bitwise_or<T>,T,typename std::enable_if<std::is_pod<T>::value, void>::type > { static MPI_Op op() { return MPI_BOR; } }; 109 template<typename T> struct MPIOp< bitwise_xor<T>,T,typename std::enable_if<std::is_pod<T>::value, void>::type > { static MPI_Op op() { return MPI_BXOR; } }; 110 111 } 112 113 #endif 114