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