JDFTx  1.2.0
MPIUtil.h
1 /*-------------------------------------------------------------------
2 Copyright 2013 Ravishankar Sundararaman
3 
4 This file is part of JDFTx.
5 
6 JDFTx is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 JDFTx is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with JDFTx. If not, see <http://www.gnu.org/licenses/>.
18 -------------------------------------------------------------------*/
19 
20 #ifndef JDFTX_CORE_MPIUTIL_H
21 #define JDFTX_CORE_MPIUTIL_H
22 
23 #include <core/string.h>
24 #include <cstdlib>
25 #include <cstdio>
26 #include <vector>
27 
28 #ifdef MPI_ENABLED
29 #include <mpi.h>
30 #endif
31 
33 class MPIUtil
34 {
35  int nProcs, iProc;
36 public:
37  int iProcess() const { return iProc; }
38  int nProcesses() const { return nProcs; }
39  bool isHead() const { return iProc==0; }
40 
41  MPIUtil(int argc, char** argv);
42  ~MPIUtil();
43  void exit(int errCode) const;
44 
45  void checkErrors(const ostringstream&) const;
46 
47  //Point-to-point functions:
48  template<typename T> void send(const T* data, size_t nData, int dest, int tag) const;
49  template<typename T> void recv(T* data, size_t nData, int src, int tag) const;
50  template<typename T> void send(const T& data, int dest, int tag) const;
51  template<typename T> void recv(T& data, int src, int tag) const;
52  void send(const bool* data, size_t nData, int dest, int tag) const;
53  void recv(bool* data, size_t nData, int src, int tag) const;
54  void send(const string& s, int dest, int tag) const;
55  void recv(string& s, int src, int tag) const;
56 
57  //Broadcast functions:
58  template<typename T> void bcast(T* data, size_t nData, int root=0) const;
59  template<typename T> void bcast(T& data, int root=0) const;
60  void bcast(bool* data, size_t nData, int root=0) const;
61  void bcast(string& s, int root=0) const;
62 
63  //Reduce functions (safe mode gaurantees identical results irrespective of round-off (but could be slower)):
64  enum ReduceOp { ReduceMin, ReduceMax, ReduceSum, ReduceProd, ReduceLAnd, ReduceBAnd, ReduceLOr, ReduceBOr, ReduceLXor, ReduceBXor };
65  template<typename T> void allReduce(T* data, size_t nData, ReduceOp op, bool safeMode=false) const;
66  template<typename T> void allReduce(T& data, ReduceOp op, bool safeMode=false) const;
67  void allReduce(bool* data, size_t nData, ReduceOp op, bool safeMode=false) const;
68  template<typename T> void allReduce(T& data, int& index, ReduceOp op) const;
69 
70  //File access (tiny subset of MPI-IO, using byte offsets alone, and made to closely resemble stdio):
71  #ifdef MPI_ENABLED
72  typedef MPI_File File;
73  #else
74  typedef FILE* File;
75  #endif
76  void fopenRead(File& fp, const char* fname, size_t fsizeExpected=0, const char* fsizeErrMsg=0) const;
77  void fopenWrite(File& fp, const char* fname) const;
78  void fopenAppend(File& fp, const char* fname) const;
79  void fclose(File& fp) const;
80  void fseek(File fp, long offset, int whence) const;
81  void fread(void *ptr, size_t size, size_t nmemb, File fp) const;
82  void fwrite(const void *ptr, size_t size, size_t nmemb, File fp) const;
83 };
84 
85 
86 //Helper for optimally dividing a specified number of (equal) tasks over MPI:
88 {
89 public:
90  TaskDivision(size_t nTasks=0, const MPIUtil* mpiUtil=0);
91  void init(size_t nTasks, const MPIUtil* mpiUtil);
92  inline size_t start() const { return startMine; }
93  inline size_t stop() const { return stopMine; }
94  inline size_t start(int iProc) const { return iProc ? stopArr[iProc-1] : 0; }
95  inline size_t stop(int iProc) const { return stopArr[iProc]; }
96  inline bool isMine(size_t task) const { return task>=startMine && task<stopMine; }
97  template<typename T> void myRange(T& start, T& stop) const { start=startMine; stop=stopMine; }
98  int whose(size_t task) const;
99 private:
100  size_t startMine, stopMine;
101  std::vector<size_t> stopArr;
102 };
103 
104 
105 //-------------------------- Template implementations ------------------------------------
107 namespace MPIUtilPrivate
108 {
109 #ifdef MPI_ENABLED
110  template<typename T> struct DataType;
111  #define DECLARE_DataType(cName, mpiName) template<> struct DataType<cName> { static MPI_Datatype get() { return MPI_##mpiName; } };
112  DECLARE_DataType(char, CHAR)
113  DECLARE_DataType(unsigned char, UNSIGNED_CHAR)
114  DECLARE_DataType(short, SHORT)
115  DECLARE_DataType(unsigned short, UNSIGNED_SHORT)
116  DECLARE_DataType(int, INT)
117  DECLARE_DataType(unsigned int, UNSIGNED)
118  DECLARE_DataType(long, LONG)
119  DECLARE_DataType(unsigned long, UNSIGNED_LONG)
120  DECLARE_DataType(long long, LONG_LONG)
121  DECLARE_DataType(unsigned long long, UNSIGNED_LONG_LONG)
122  DECLARE_DataType(float, FLOAT)
123  DECLARE_DataType(double, DOUBLE)
124  #undef DECLARE_DataType
125 
126  static inline MPI_Op mpiOp(MPIUtil::ReduceOp op)
127  { switch(op)
128  { case MPIUtil::ReduceMax: return MPI_MAX;
129  case MPIUtil::ReduceMin: return MPI_MIN;
130  case MPIUtil::ReduceSum: return MPI_SUM;
131  case MPIUtil::ReduceProd: return MPI_PROD;
132  case MPIUtil::ReduceLAnd: return MPI_LAND;
133  case MPIUtil::ReduceBAnd: return MPI_BAND;
134  case MPIUtil::ReduceLOr: return MPI_LOR;
135  case MPIUtil::ReduceBOr: return MPI_BOR;
136  case MPIUtil::ReduceLXor: return MPI_LXOR;
137  case MPIUtil::ReduceBXor: return MPI_BXOR;
138  default: return 0;
139  }
140  }
141 
142  template<typename T> struct DataTypeIntPair;
143  #define DECLARE_DataTypeIntPair(cName, mpiName) template<> struct DataTypeIntPair<cName> { static MPI_Datatype get() { return mpiName; } };
144  DECLARE_DataTypeIntPair(short, MPI_SHORT_INT)
145  DECLARE_DataTypeIntPair(int, MPI_2INT)
146  DECLARE_DataTypeIntPair(long, MPI_LONG_INT)
147  DECLARE_DataTypeIntPair(float, MPI_FLOAT_INT)
148  DECLARE_DataTypeIntPair(double, MPI_DOUBLE_INT)
149  #undef DECLARE_DataTypeIntPair
150 
151  static inline MPI_Op mpiLocOp(MPIUtil::ReduceOp op)
152  { switch(op)
153  { case MPIUtil::ReduceMax: return MPI_MAXLOC;
154  case MPIUtil::ReduceMin: return MPI_MINLOC;
155  default: return 0;
156  }
157  }
158 #endif
159 }
160 
161 template<typename T> void MPIUtil::send(const T* data, size_t nData, int dest, int tag) const
162 { using namespace MPIUtilPrivate;
163  #ifdef MPI_ENABLED
164  if(nProcs>1) MPI_Send((T*)data, nData, DataType<T>::get(), dest, tag, MPI_COMM_WORLD);
165  #endif
166 }
167 
168 template<typename T> void MPIUtil::recv(T* data, size_t nData, int src, int tag) const
169 { using namespace MPIUtilPrivate;
170  #ifdef MPI_ENABLED
171  if(nProcs>1) MPI_Recv(data, nData, DataType<T>::get(), src, tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
172  #endif
173 }
174 
175 template<typename T> void MPIUtil::send(const T& data, int dest, int tag) const
176 { send(&data, 1, dest, tag);
177 }
178 
179 template<typename T> void MPIUtil::recv(T& data, int src, int tag) const
180 { recv(&data, 1, src, tag);
181 }
182 
183 template<typename T> void MPIUtil::bcast(T* data, size_t nData, int root) const
184 { using namespace MPIUtilPrivate;
185  #ifdef MPI_ENABLED
186  if(nProcs>1) MPI_Bcast(data, nData, DataType<T>::get(), root, MPI_COMM_WORLD);
187  #endif
188 }
189 
190 template<typename T> void MPIUtil::bcast(T& data, int root) const
191 { bcast(&data, 1, root);
192 }
193 
194 template<typename T> void MPIUtil::allReduce(T* data, size_t nData, MPIUtil::ReduceOp op, bool safeMode) const
195 { using namespace MPIUtilPrivate;
196  #ifdef MPI_ENABLED
197  if(nProcs>1)
198  { if(safeMode) //Reduce to root node and then broadcast result (to ensure identical values)
199  { MPI_Reduce(isHead()?MPI_IN_PLACE:data, data, nData, DataType<T>::get(), mpiOp(op), 0, MPI_COMM_WORLD);
200  bcast(data, nData, 0);
201  }
202  else //standard Allreduce
203  MPI_Allreduce(MPI_IN_PLACE, data, nData, DataType<T>::get(), mpiOp(op), MPI_COMM_WORLD);
204  }
205  #endif
206 }
207 
208 template<typename T> void MPIUtil::allReduce(T& data, MPIUtil::ReduceOp op, bool safeMode) const
209 { allReduce(&data, 1, op, safeMode);
210 }
211 
212 template<typename T> void MPIUtil::allReduce(T& data, int& index, MPIUtil::ReduceOp op) const
213 { using namespace MPIUtilPrivate;
214  #ifdef MPI_ENABLED
215  if(nProcs>1)
216  { struct Pair { T data; int index; } pair;
217  pair.data = data; pair.index = index;
218  MPI_Allreduce(MPI_IN_PLACE, &pair, 1, DataTypeIntPair<T>::get(), mpiLocOp(op), MPI_COMM_WORLD);
219  data = pair.data; index = pair.index;
220  }
221  #endif
222 }
223 
225 #endif // JDFTX_CORE_MPIUTIL_H
int iProcess() const
rank of current process
Definition: MPIUtil.h:37
int nProcesses() const
number of processes
Definition: MPIUtil.h:38
size_t start() const
Task number that current process should start on.
Definition: MPIUtil.h:92
size_t stop(int iProc) const
Task number that the specified process should stop before (non-inclusive)
Definition: MPIUtil.h:95
size_t start(int iProc) const
Task number that the specified process should start on.
Definition: MPIUtil.h:94
STL strings and streams with case insensitive comparison.
void fopenRead(File &fp, const char *fname, size_t fsizeExpected=0, const char *fsizeErrMsg=0) const
open file for reading and optionally check file size
bool isHead() const
whether this is the root process (makes code more readable)
Definition: MPIUtil.h:39
void fopenAppend(File &fp, const char *fname) const
open file for appending to the end. Implied barrier on exit.
void fopenWrite(File &fp, const char *fname) const
open file for writing
void recv(T *data, size_t nData, int src, int tag) const
generic array receive
void send(const T *data, size_t nData, int dest, int tag) const
generic array send
void checkErrors(const ostringstream &) const
collect error messages from all processes; if any, display them and quit
void myRange(T &start, T &stop) const
retrieve range of processes for current task (templated to support other integer types for task range...
Definition: MPIUtil.h:97
void fseek(File fp, long offset, int whence) const
syntax consistent with fseek from stdio
Definition: string.h:82
void allReduce(T *data, size_t nData, ReduceOp op, bool safeMode=false) const
generic array reduction
void exit(int errCode) const
global exit (kill other MPI processes as well)
MPI wrapper class.
Definition: MPIUtil.h:33
void bcast(T *data, size_t nData, int root=0) const
generic array broadcast
size_t stop() const
Task number that current process should stop before (non-inclusive)
Definition: MPIUtil.h:93
bool isMine(size_t task) const
Whether current process handle this task number.
Definition: MPIUtil.h:96
Definition: MPIUtil.h:87