mpicollectivecommunication.hh

Go to the documentation of this file.
00001 // vi: set et ts=4 sw=2 sts=2:
00002 #ifndef DUNE_MPICOLLECTIVECOMMUNICATION_HH
00003 #define DUNE_MPICOLLECTIVECOMMUNICATION_HH
00004 
00010 #include<iostream>
00011 #include<complex>
00012 #include<algorithm>
00013 #include<functional>
00014 
00015 #include "deprecated.hh"
00016 #include"exceptions.hh"
00017 #include"collectivecommunication.hh"
00018 #include"binaryfunctions.hh"
00019 #include"shared_ptr.hh"
00020 #include"mpitraits.hh"
00021 
00022 #if HAVE_MPI
00023 // MPI header
00024 #include<mpi.h>
00025 
00026 namespace Dune
00027 {
00028 
00029   //=======================================================
00030   // use singleton pattern and template specialization to 
00031   // generate MPI data types
00032   //=======================================================
00033 
00034   // any type is interpreted as contiguous piece of memory
00035   // i.e. only value types are allowed !
00036   template<typename T>
00037   class Generic_MPI_Datatype
00038   {
00039   public:
00040         static MPI_Datatype get()  DUNE_DEPRECATED
00041         {
00042           if (!type)
00043                 {
00044                   type = shared_ptr<MPI_Datatype>(new MPI_Datatype);
00045                   MPI_Type_contiguous(sizeof(T),MPI_BYTE,type.get());
00046                   MPI_Type_commit(type.get());
00047                 }
00048           return *type;
00049         }
00050   private:
00051         Generic_MPI_Datatype () {}
00052         Generic_MPI_Datatype (const Generic_MPI_Datatype& ) {}  
00053         static shared_ptr<MPI_Datatype> type;
00054   };
00055 
00056   template<typename T>
00057   shared_ptr<MPI_Datatype> Generic_MPI_Datatype<T>::type = shared_ptr<MPI_Datatype>(static_cast<MPI_Datatype*>(0)); 
00058 
00059   // A Macro for defining traits for the primitive data types
00060 #define ComposeMPITraits(p,m) \
00061   template<> \
00062   class Generic_MPI_Datatype<p>{ \
00063   public: \
00064     static inline MPI_Datatype get() DUNE_DEPRECATED{ \
00065       return m; \
00066     } \
00067   }
00068 
00069     
00070   ComposeMPITraits(char, MPI_CHAR);
00071   ComposeMPITraits(unsigned char,MPI_UNSIGNED_CHAR);
00072   ComposeMPITraits(short,MPI_SHORT);
00073   ComposeMPITraits(unsigned short,MPI_UNSIGNED_SHORT);
00074   ComposeMPITraits(int,MPI_INT);
00075   ComposeMPITraits(unsigned int,MPI_UNSIGNED);
00076   ComposeMPITraits(long,MPI_LONG);
00077   ComposeMPITraits(unsigned long,MPI_UNSIGNED_LONG);
00078   ComposeMPITraits(float,MPI_FLOAT);
00079   ComposeMPITraits(double,MPI_DOUBLE);
00080   ComposeMPITraits(long double,MPI_LONG_DOUBLE);
00081 
00082 #undef ComposeMPITraits
00083 
00084   //=======================================================
00085   // use singleton pattern and template specialization to 
00086   // generate MPI operations
00087   //=======================================================
00088 
00089   template<typename Type, typename BinaryFunction>
00090   class Generic_MPI_Op
00091   {
00092     
00093   public:
00094         static MPI_Op get ()
00095         {
00096           if (!op)
00097                 {
00098                   op = shared_ptr<MPI_Op>(new MPI_Op);
00099                   MPI_Op_create((void (*)(void*, void*, int*, MPI_Datatype*))&operation,true,op.get());
00100                 }
00101           return *op;
00102         }
00103   private:
00104         static void operation (Type *in, Type *inout, int *len, MPI_Datatype *dptr)
00105         {
00106           BinaryFunction func;
00107           
00108           for (int i=0; i< *len; ++i, ++in, ++inout){
00109             Type temp;
00110             temp = func(*in, *inout);
00111             *inout = temp;
00112           }
00113         }
00114         Generic_MPI_Op () {}
00115         Generic_MPI_Op (const Generic_MPI_Op& ) {}
00116         static shared_ptr<MPI_Op> op;
00117   };
00118 
00119   
00120   template<typename Type, typename BinaryFunction>
00121   shared_ptr<MPI_Op> Generic_MPI_Op<Type,BinaryFunction>::op = shared_ptr<MPI_Op>(static_cast<MPI_Op*>(0));
00122   
00123 #define ComposeMPIOp(type,func,op) \
00124   template<> \
00125   class Generic_MPI_Op<type, func<type> >{ \
00126   public:\
00127     static MPI_Op get(){ \
00128       return op; \
00129     } \
00130   private:\
00131     Generic_MPI_Op () {}\
00132     Generic_MPI_Op (const Generic_MPI_Op& ) {}\
00133   }
00134 
00135     
00136   ComposeMPIOp(char, std::plus, MPI_SUM);
00137   ComposeMPIOp(unsigned char, std::plus, MPI_SUM);
00138   ComposeMPIOp(short, std::plus, MPI_SUM);
00139   ComposeMPIOp(unsigned short, std::plus, MPI_SUM);
00140   ComposeMPIOp(int, std::plus, MPI_SUM);
00141   ComposeMPIOp(unsigned int, std::plus, MPI_SUM);
00142   ComposeMPIOp(long, std::plus, MPI_SUM);
00143   ComposeMPIOp(unsigned long, std::plus, MPI_SUM);
00144   ComposeMPIOp(float, std::plus, MPI_SUM);
00145   ComposeMPIOp(double, std::plus, MPI_SUM);
00146   ComposeMPIOp(long double, std::plus, MPI_SUM);
00147 
00148   ComposeMPIOp(char, std::multiplies, MPI_PROD);
00149   ComposeMPIOp(unsigned char, std::multiplies, MPI_PROD);
00150   ComposeMPIOp(short, std::multiplies, MPI_PROD);
00151   ComposeMPIOp(unsigned short, std::multiplies, MPI_PROD);
00152   ComposeMPIOp(int, std::multiplies, MPI_PROD);
00153   ComposeMPIOp(unsigned int, std::multiplies, MPI_PROD);
00154   ComposeMPIOp(long, std::multiplies, MPI_PROD);
00155   ComposeMPIOp(unsigned long, std::multiplies, MPI_PROD);
00156   ComposeMPIOp(float, std::multiplies, MPI_PROD);
00157   ComposeMPIOp(double, std::multiplies, MPI_PROD);
00158   ComposeMPIOp(long double, std::multiplies, MPI_PROD);
00159 
00160   ComposeMPIOp(char, Min, MPI_MIN);
00161   ComposeMPIOp(unsigned char, Min, MPI_MIN);
00162   ComposeMPIOp(short, Min, MPI_MIN);
00163   ComposeMPIOp(unsigned short, Min, MPI_MIN);
00164   ComposeMPIOp(int, Min, MPI_MIN);
00165   ComposeMPIOp(unsigned int, Min, MPI_MIN);
00166   ComposeMPIOp(long, Min, MPI_MIN);
00167   ComposeMPIOp(unsigned long, Min, MPI_MIN);
00168   ComposeMPIOp(float, Min, MPI_MIN);
00169   ComposeMPIOp(double, Min, MPI_MIN);
00170   ComposeMPIOp(long double, Min, MPI_MIN);
00171 
00172   ComposeMPIOp(char, Max, MPI_MAX);
00173   ComposeMPIOp(unsigned char, Max, MPI_MAX);
00174   ComposeMPIOp(short, Max, MPI_MAX);
00175   ComposeMPIOp(unsigned short, Max, MPI_MAX);
00176   ComposeMPIOp(int, Max, MPI_MAX);
00177   ComposeMPIOp(unsigned int, Max, MPI_MAX);
00178   ComposeMPIOp(long, Max, MPI_MAX);
00179   ComposeMPIOp(unsigned long, Max, MPI_MAX);
00180   ComposeMPIOp(float, Max, MPI_MAX);
00181   ComposeMPIOp(double, Max, MPI_MAX);
00182   ComposeMPIOp(long double, Max, MPI_MAX);
00183 
00184 #undef ComposeMPIOp
00185 
00186 
00187   //=======================================================
00188   // use singleton pattern and template specialization to 
00189   // generate MPI operations
00190   //=======================================================
00191 
00195   template<>
00196   class CollectiveCommunication<MPI_Comm>
00197   {
00198   public:
00200         CollectiveCommunication (const MPI_Comm& c)
00201           : communicator(c)
00202         {
00203           if(communicator!=MPI_COMM_NULL){
00204             MPI_Comm_rank(communicator,&me);
00205             MPI_Comm_size(communicator,&procs);
00206           }else{
00207             procs=0;
00208             me=-1;
00209           }
00210         }
00211 
00213         int rank () const
00214         {
00215           return me;
00216         }
00217 
00219         int size () const
00220         {
00221           return procs;
00222         }
00223 
00225         template<typename T>
00226         T sum (T& in) const // MPI does not know about const :-(
00227         {
00228           T out;
00229           allreduce<std::plus<T> >(&in,&out,1);
00230           return out;
00231         }
00232 
00234         template<typename T>
00235         int sum (T* inout, int len) const
00236         {
00237           return allreduce<std::plus<T> >(inout,len);
00238         }
00239 
00241         template<typename T>
00242         T prod (T& in) const // MPI does not know about const :-(
00243         {
00244           T out;
00245           allreduce<std::multiplies<T> >(&in,&out,1);
00246           return out;
00247         }
00248 
00250         template<typename T>
00251         int prod (T* inout, int len) const
00252         {
00253           return allreduce<std::plus<T> >(inout,len);
00254         }
00255 
00257         template<typename T>
00258         T min (T& in) const // MPI does not know about const :-(
00259         {
00260           T out;
00261           allreduce<Min<T> >(&in,&out,1);
00262           return out;
00263         }
00264 
00266         template<typename T>
00267         int min (T* inout, int len) const
00268         {
00269           return allreduce<Min<T> >(inout,len);
00270         }
00271 
00272     
00274         template<typename T>
00275         T max (T& in) const // MPI does not know about const :-(
00276         {
00277           T out;
00278           allreduce<Max<T> >(&in,&out,1);
00279           return out;
00280         }
00281 
00283         template<typename T>
00284         int max (T* inout, int len) const
00285         {
00286           return allreduce<Max<T> >(inout,len);
00287         }
00288 
00290         int barrier () const
00291         {
00292           return MPI_Barrier(communicator);
00293         }
00294 
00296         template<typename T>
00297         int broadcast (T* inout, int len, int root) const
00298         {
00299           return MPI_Bcast(inout,len,MPITraits<T>::getType(),root,communicator);
00300         }
00301         
00303         template<typename T>
00304         int gather (T* in, T* out, int len, int root) const // note out must have space for P*len elements
00305         {
00306           return MPI_Gather(in,len,MPITraits<T>::getType(),
00307                                                 out,len,MPITraits<T>::getType(),
00308                                                 root,communicator);
00309         }
00310 
00311         operator MPI_Comm () const
00312         {
00313           return communicator;
00314         }
00315 
00316     template<typename BinaryFunction, typename Type>
00317     int allreduce(Type* inout, int len) const
00318     {
00319       Type* out = new Type[len];
00320       int ret = allreduce<BinaryFunction>(inout,out,len);
00321       std::copy(out, out+len, inout);
00322       delete[] out;
00323       return ret;
00324     }
00325     
00326     template<typename BinaryFunction, typename Type>
00327     int allreduce(Type* in, Type* out, int len) const
00328     {
00329       return MPI_Allreduce(in, out, len, MPITraits<Type>::getType(),
00330                     Generic_MPI_Op<Type, BinaryFunction>::get(),communicator);
00331     }
00332     
00333   private:
00334         MPI_Comm communicator;
00335         int me;
00336         int procs;
00337   };
00338 } // namespace dune
00339 
00340 #endif
00341 #endif

Generated on Fri Apr 29 2011 with Doxygen (ver 1.7.1) [doxygen-log,error-log].