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