• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2004 The Trustees of Indiana University.
2 // Copyright (C) 2005-2006 Douglas Gregor <doug.gregor -at- gmail.com>
3 
4 // Use, modification and distribution is subject to the Boost Software
5 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 
8 //  Authors: Douglas Gregor
9 //           Andrew Lumsdaine
10 
11 /** @file operations.hpp
12  *
13  *  This header provides a mapping from function objects to @c MPI_Op
14  *  constants used in MPI collective operations. It also provides
15  *  several new function object types not present in the standard @c
16  *  <functional> header that have direct mappings to @c MPI_Op.
17  */
18 #ifndef BOOST_MPI_IS_MPI_OP_HPP
19 #define BOOST_MPI_IS_MPI_OP_HPP
20 
21 #include <boost/mpi/config.hpp>
22 #include <boost/mpl/bool.hpp>
23 #include <boost/mpl/if.hpp>
24 #include <boost/mpl/and.hpp>
25 #include <boost/mpi/datatype.hpp>
26 #include <boost/core/enable_if.hpp>
27 #include <boost/core/uncaught_exceptions.hpp>
28 #include <functional>
29 
30 namespace boost { namespace mpi {
31 
32 template<typename Op, typename T> struct is_mpi_op;
33 
34 /**
35  * @brief Determine if a function object type is commutative.
36  *
37  * This trait determines if an operation @c Op is commutative when
38  * applied to values of type @c T. Parallel operations such as @c
39  * reduce and @c prefix_sum can be implemented more efficiently with
40  * commutative operations. To mark an operation as commutative, users
41  * should specialize @c is_commutative and derive from the class @c
42  * mpl::true_.
43  */
44 template<typename Op, typename T>
45 struct is_commutative : public mpl::false_ { };
46 
47 /**************************************************************************
48  * Function objects for MPI operations not in <functional> header         *
49  **************************************************************************/
50 
51 /**
52  *  @brief Compute the maximum of two values.
53  *
54  *  This binary function object computes the maximum of the two values
55  *  it is given. When used with MPI and a type @c T that has an
56  *  associated, built-in MPI data type, translates to @c MPI_MAX.
57  */
58 template<typename T>
59 struct maximum
60 {
61   typedef T first_argument_type;
62   typedef T second_argument_type;
63   typedef T result_type;
64   /** @returns the maximum of x and y. */
operator ()boost::mpi::maximum65   const T& operator()(const T& x, const T& y) const
66   {
67     return x < y? y : x;
68   }
69 };
70 
71 /**
72  *  @brief Compute the minimum of two values.
73  *
74  *  This binary function object computes the minimum of the two values
75  *  it is given. When used with MPI and a type @c T that has an
76  *  associated, built-in MPI data type, translates to @c MPI_MIN.
77  */
78 template<typename T>
79 struct minimum
80 {
81   typedef T first_argument_type;
82   typedef T second_argument_type;
83   typedef T result_type;
84   /** @returns the minimum of x and y. */
operator ()boost::mpi::minimum85   const T& operator()(const T& x, const T& y) const
86   {
87     return x < y? x : y;
88   }
89 };
90 
91 
92 /**
93  *  @brief Compute the bitwise AND of two integral values.
94  *
95  *  This binary function object computes the bitwise AND of the two
96  *  values it is given. When used with MPI and a type @c T that has an
97  *  associated, built-in MPI data type, translates to @c MPI_BAND.
98  */
99 template<typename T>
100 struct bitwise_and
101 {
102   typedef T first_argument_type;
103   typedef T second_argument_type;
104   typedef T result_type;
105   /** @returns @c x & y. */
operator ()boost::mpi::bitwise_and106   T operator()(const T& x, const T& y) const
107   {
108     return x & y;
109   }
110 };
111 
112 /**
113  *  @brief Compute the bitwise OR of two integral values.
114  *
115  *  This binary function object computes the bitwise OR of the two
116  *  values it is given. When used with MPI and a type @c T that has an
117  *  associated, built-in MPI data type, translates to @c MPI_BOR.
118  */
119 template<typename T>
120 struct bitwise_or
121 {
122   typedef T first_argument_type;
123   typedef T second_argument_type;
124   typedef T result_type;
125   /** @returns the @c x | y. */
operator ()boost::mpi::bitwise_or126   T operator()(const T& x, const T& y) const
127   {
128     return x | y;
129   }
130 };
131 
132 /**
133  *  @brief Compute the logical exclusive OR of two integral values.
134  *
135  *  This binary function object computes the logical exclusive of the
136  *  two values it is given. When used with MPI and a type @c T that has
137  *  an associated, built-in MPI data type, translates to @c MPI_LXOR.
138  */
139 template<typename T>
140 struct logical_xor
141 {
142   typedef T first_argument_type;
143   typedef T second_argument_type;
144   typedef T result_type;
145   /** @returns the logical exclusive OR of x and y. */
operator ()boost::mpi::logical_xor146   T operator()(const T& x, const T& y) const
147   {
148     return (x || y) && !(x && y);
149   }
150 };
151 
152 /**
153  *  @brief Compute the bitwise exclusive OR of two integral values.
154  *
155  *  This binary function object computes the bitwise exclusive OR of
156  *  the two values it is given. When used with MPI and a type @c T that
157  *  has an associated, built-in MPI data type, translates to @c
158  *  MPI_BXOR.
159  */
160 template<typename T>
161 struct bitwise_xor
162 {
163   typedef T first_argument_type;
164   typedef T second_argument_type;
165   typedef T result_type;
166   /** @returns @c x ^ y. */
operator ()boost::mpi::bitwise_xor167   T operator()(const T& x, const T& y) const
168   {
169     return x ^ y;
170   }
171 };
172 
173 /**************************************************************************
174  * MPI_Op queries                                                         *
175  **************************************************************************/
176 
177 /**
178  *  @brief Determine if a function object has an associated @c MPI_Op.
179  *
180  *  This trait determines if a function object type @c Op, when used
181  *  with argument type @c T, has an associated @c MPI_Op. If so, @c
182  *  is_mpi_op<Op,T> will derive from @c mpl::false_ and will
183  *  contain a static member function @c op that takes no arguments but
184  *  returns the associated @c MPI_Op value. For instance, @c
185  *  is_mpi_op<std::plus<int>,int>::op() returns @c MPI_SUM.
186  *
187  *  Users may specialize @c is_mpi_op for any other class templates
188  *  that map onto operations that have @c MPI_Op equivalences, such as
189  *  bitwise OR, logical and, or maximum. However, users are encouraged
190  *  to use the standard function objects in the @c functional and @c
191  *  boost/mpi/operations.hpp headers whenever possible. For
192  *  function objects that are class templates with a single template
193  *  parameter, it may be easier to specialize @c is_builtin_mpi_op.
194  */
195 template<typename Op, typename T>
196 struct is_mpi_op : public mpl::false_ { };
197 
198 /// INTERNAL ONLY
199 template<typename T>
200 struct is_mpi_op<maximum<T>, T>
201   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
202                            is_mpi_floating_point_datatype<T> >
203 {
opboost::mpi::is_mpi_op204   static MPI_Op op() { return MPI_MAX; }
205 };
206 
207 /// INTERNAL ONLY
208 template<typename T>
209 struct is_mpi_op<minimum<T>, T>
210   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
211                            is_mpi_floating_point_datatype<T> >
212 {
opboost::mpi::is_mpi_op213   static MPI_Op op() { return MPI_MIN; }
214 };
215 
216 /// INTERNAL ONLY
217 template<typename T>
218  struct is_mpi_op<std::plus<T>, T>
219   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
220                            is_mpi_floating_point_datatype<T>,
221                            is_mpi_complex_datatype<T> >
222 {
opboost::mpi::is_mpi_op223   static MPI_Op op() { return MPI_SUM; }
224 };
225 
226 /// INTERNAL ONLY
227 template<typename T>
228  struct is_mpi_op<std::multiplies<T>, T>
229   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
230                            is_mpi_floating_point_datatype<T>,
231                            is_mpi_complex_datatype<T> >
232 {
opboost::mpi::is_mpi_op233   static MPI_Op op() { return MPI_PROD; }
234 };
235 
236 /// INTERNAL ONLY
237 template<typename T>
238  struct is_mpi_op<std::logical_and<T>, T>
239   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
240                            is_mpi_logical_datatype<T> >
241 {
opboost::mpi::is_mpi_op242   static MPI_Op op() { return MPI_LAND; }
243 };
244 
245 /// INTERNAL ONLY
246 template<typename T>
247  struct is_mpi_op<std::logical_or<T>, T>
248   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
249                            is_mpi_logical_datatype<T> >
250 {
opboost::mpi::is_mpi_op251   static MPI_Op op() { return MPI_LOR; }
252 };
253 
254 /// INTERNAL ONLY
255 template<typename T>
256  struct is_mpi_op<logical_xor<T>, T>
257   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
258                            is_mpi_logical_datatype<T> >
259 {
opboost::mpi::is_mpi_op260   static MPI_Op op() { return MPI_LXOR; }
261 };
262 
263 /// INTERNAL ONLY
264 template<typename T>
265  struct is_mpi_op<bitwise_and<T>, T>
266   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
267                            is_mpi_byte_datatype<T> >
268 {
opboost::mpi::is_mpi_op269   static MPI_Op op() { return MPI_BAND; }
270 };
271 
272 /// INTERNAL ONLY
273 template<typename T>
274  struct is_mpi_op<bitwise_or<T>, T>
275   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
276                            is_mpi_byte_datatype<T> >
277 {
opboost::mpi::is_mpi_op278   static MPI_Op op() { return MPI_BOR; }
279 };
280 
281 /// INTERNAL ONLY
282 template<typename T>
283  struct is_mpi_op<bitwise_xor<T>, T>
284   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
285                            is_mpi_byte_datatype<T> >
286 {
opboost::mpi::is_mpi_op287   static MPI_Op op() { return MPI_BXOR; }
288 };
289 
290 namespace detail {
291   // A helper class used to create user-defined MPI_Ops
292   template<typename Op, typename T>
293   class user_op
294   {
295   public:
user_op()296     user_op()
297     {
298       BOOST_MPI_CHECK_RESULT(MPI_Op_create,
299                              (&user_op<Op, T>::perform,
300                               is_commutative<Op, T>::value,
301                               &mpi_op));
302     }
303 
~user_op()304     ~user_op()
305     {
306       if (boost::core::uncaught_exceptions() > 0) {
307         // Ignore failure cases: there are obviously other problems
308         // already, and we don't want to cause program termination if
309         // MPI_Op_free fails.
310         MPI_Op_free(&mpi_op);
311       } else {
312         BOOST_MPI_CHECK_RESULT(MPI_Op_free, (&mpi_op));
313       }
314     }
315 
get_mpi_op()316     MPI_Op& get_mpi_op()
317     {
318       return mpi_op;
319     }
320 
321   private:
322     MPI_Op mpi_op;
323 
perform(void * vinvec,void * voutvec,int * plen,MPI_Datatype *)324     static void BOOST_MPI_CALLING_CONVENTION perform(void* vinvec, void* voutvec, int* plen, MPI_Datatype*)
325     {
326       T* invec = static_cast<T*>(vinvec);
327       T* outvec = static_cast<T*>(voutvec);
328       Op op;
329       std::transform(invec, invec + *plen, outvec, outvec, op);
330     }
331   };
332 
333 } // end namespace detail
334 
335 } } // end namespace boost::mpi
336 
337 #endif // BOOST_MPI_GET_MPI_OP_HPP
338