HOPS
HOPS class reference
MHO_MPIInterface.hh
Go to the documentation of this file.
1 #ifndef MHO_MPIInterface_HH__
2 #define MHO_MPIInterface_HH__
3 
4 #include "mpi.h"
5 
6 #include "MHO_Message.hh"
7 #include <string>
8 #include <vector>
9 
10 #define LOCAL_RANK_MPI
11 
12 namespace hops
13 {
14 
15 //helper template for mapping basic types to MPI type codes
16 template< typename T > MPI_Datatype mpi_type_for();
17 
18 template<> inline MPI_Datatype mpi_type_for< int >()
19 {
20  return MPI_INT;
21 }
22 
23 template<> inline MPI_Datatype mpi_type_for< double >()
24 {
25  return MPI_DOUBLE;
26 }
27 
28 template<> inline MPI_Datatype mpi_type_for< float >()
29 {
30  return MPI_FLOAT;
31 }
32 
42 {
43  public:
44  //singleton interface
51  static MHO_MPIInterface* GetInstance();
52 
60  void Initialize(int* argc, char*** argv, bool split_mode = true);
64  void Finalize();
65 
71  bool Check() const { return (fGlobalProcessID >= 0) && (fNProcesses > 0); }
72 
78  int GetGlobalProcessID() const { return fGlobalProcessID; }
79 
85  int GetNProcesses() const { return fNProcesses; }
86 
92  int GetLocalProcessID() const { return fLocalProcessID; }
93 
99  std::string GetHostName() const { return fHostName; };
100 
101  //use to isolate a section of code, so each process completes it
102  //one at a time
106  void BeginSequentialProcess();
110  void EndSequentialProcess();
111 
115  void GlobalBarrier() const { MPI_Barrier(MPI_COMM_WORLD); }
116 
125  void PrintMessage(std::string msg);
126 
127  //broadcast a string message to all processes
133  void BroadcastString(std::string& msg);
134 
135  //routines to be used by programs which split the processes into two
136  //groups bases on even/odd local process rank
142  bool SplitMode() { return fSplitMode; };
143 
149  bool IsSplitValid() { return fValidSplit; };
150 
157 
164 
170  int GetSubGroupRank() { return fSubGroupRank; };
171 
178 
184  MPI_Group* GetSubGroup()
185  {
187  {
188  return &fEvenGroup;
189  }
190  else
191  {
192  return &fOddGroup;
193  };
194  }
195 
197  {
199  {
200  return &fEvenCommunicator;
201  }
202  else
203  {
204  return &fOddCommunicator;
205  };
206  }
207 
208  MPI_Group* GetEvenGroup() { return &fEvenGroup; };
209 
210  MPI_Group* GetOddGroup() { return &fOddGroup; };
211 
212  MPI_Comm* GetEvenCommunicator() { return &fEvenCommunicator; };
213 
214  MPI_Comm* GetOddCommunicator() { return &fOddCommunicator; };
215 
221  template< typename T > std::map< std::string, T > MergeMap(const std::map< std::string, T >& local_map)
222  {
223  //serialize the local map into primitive types
224  std::vector< int > key_lengths;
225  std::string concatenated_keys;
226  std::vector< T > values;
227 
228  for(const auto& kv : local_map)
229  {
230  key_lengths.push_back(static_cast< int >(kv.first.size()));
231  concatenated_keys += kv.first;
232  values.push_back(kv.second);
233  }
234 
235  int local_entry_count = static_cast< int >(local_map.size());
236  int local_char_count = static_cast< int >(concatenated_keys.size());
237  // gather map entry counts
238  std::vector< int > entry_counts(fNProcesses);
239  MPI_Gather(&local_entry_count, 1, MPI_INT, entry_counts.data(), 1, MPI_INT, 0, MPI_COMM_WORLD);
240 
241  //gather key character counts
242  std::vector< int > char_counts(fNProcesses);
243  MPI_Gather(&local_char_count, 1, MPI_INT, char_counts.data(), 1, MPI_INT, 0, MPI_COMM_WORLD);
244 
245  std::map< std::string, T > merged;
246 
247  //only rank 0 reconstructs ---
248  if(fGlobalProcessID == 0)
249  {
250  // Compute displacements
251  std::vector< int > entry_displs(fNProcesses, 0);
252  std::vector< int > char_displs(fNProcesses, 0);
253 
254  for(int i = 1; i < fNProcesses; ++i)
255  {
256  entry_displs[i] = entry_displs[i - 1] + entry_counts[i - 1];
257  char_displs[i] = char_displs[i - 1] + char_counts[i - 1];
258  }
259 
260  int total_entries = entry_displs[fNProcesses - 1] + entry_counts[fNProcesses - 1];
261  int total_chars = char_displs[fNProcesses - 1] + char_counts[fNProcesses - 1];
262 
263  // allocate receive buffers
264  std::vector< int > all_key_lengths(total_entries);
265  std::vector< char > all_chars(total_chars);
266  std::vector< T > all_values(total_entries);
267 
268  // gather key lengths
269  MPI_Gatherv(key_lengths.data(), local_entry_count, MPI_INT, all_key_lengths.data(), entry_counts.data(),
270  entry_displs.data(), MPI_INT, 0, MPI_COMM_WORLD);
271 
272  // gather keys
273  MPI_Gatherv(concatenated_keys.data(), local_char_count, MPI_CHAR, all_chars.data(), char_counts.data(),
274  char_displs.data(), MPI_CHAR, 0, MPI_COMM_WORLD);
275 
276  // gather values
277  MPI_Gatherv(values.data(), local_entry_count, mpi_type_for< T >(), all_values.data(), entry_counts.data(),
278  entry_displs.data(), mpi_type_for< T >(), 0, MPI_COMM_WORLD);
279 
280  // Reconstruct merged map
281  size_t pos = 0;
282  for(int i = 0; i < total_entries; ++i)
283  {
284  int len = all_key_lengths[i];
285  std::string key(all_chars.begin() + pos, all_chars.begin() + pos + len);
286  pos += len;
287  merged[key] = all_values[i];
288  }
289  }
290  else
291  {
292  //non-root ranks just need to participate in gathers
293  MPI_Gatherv(key_lengths.data(), local_entry_count, MPI_INT, nullptr, nullptr, nullptr, MPI_INT, 0,
294  MPI_COMM_WORLD);
295 
296  MPI_Gatherv(concatenated_keys.data(), local_char_count, MPI_CHAR, nullptr, nullptr, nullptr, MPI_CHAR, 0,
297  MPI_COMM_WORLD);
298 
299  MPI_Gatherv(values.data(), local_entry_count, mpi_type_for< T >(), nullptr, nullptr, nullptr,
300  mpi_type_for< T >(), 0, MPI_COMM_WORLD);
301  }
302 
303  return merged;
304  }
305 
311  std::set< std::string > MergeStringSet(const std::set< std::string >& local_set);
312 
313  protected:
315  virtual ~MHO_MPIInterface();
316 
320  std::string fHostName;
321  std::vector< int > fCoHostedProcessIDs;
322 
323  //groups and communicators for splitting processes into
324  //two sets, based on whether they have even/odd (local) ranks
326  MPI_Group fEvenGroup; //even process subgroup
327  MPI_Group fOddGroup; //odd process subgroup
328  MPI_Comm fEvenCommunicator; //comm for even group
329  MPI_Comm fOddCommunicator; //comm for odd group
330  bool fValidSplit; //true if the size of the subgroups is equal
331  bool fIsEvenGroupMember; //true if this process is a member of the even subgroup
332  int fSubGroupRank; //rank of this process in its subgroup
333  int fNSubGroupProcesses; //number of processes in the subgroup this process belongs to
334  int fPartnerProcessID; //global rank of partner process in other subgroup
335 
336  void DetermineLocalRank();
337  void SetupSubGroups();
338 
339  MPI_Status fStatus;
340 };
341 
342 } //end of namespace hops
343 
344 #endif
interface functions for initialization of a MPI environment
Definition: MHO_MPIInterface.hh:42
MPI_Group fEvenGroup
Definition: MHO_MPIInterface.hh:326
bool fValidSplit
Definition: MHO_MPIInterface.hh:330
MPI_Group fOddGroup
Definition: MHO_MPIInterface.hh:327
int fNProcesses
Definition: MHO_MPIInterface.hh:318
MPI_Comm * GetSubGroupCommunicator()
Definition: MHO_MPIInterface.hh:196
bool fIsEvenGroupMember
Definition: MHO_MPIInterface.hh:331
std::string GetHostName() const
Getter for host name.
Definition: MHO_MPIInterface.hh:99
MPI_Group * GetEvenGroup()
Definition: MHO_MPIInterface.hh:208
void PrintMessage(std::string msg)
Collects and prints messages from all processes in a MPI parallel environment. when called,...
Definition: MHO_MPIInterface.cc:130
int GetNSubGroupProcesses()
Getter for nsub group processes.
Definition: MHO_MPIInterface.hh:163
MPI_Comm * GetEvenCommunicator()
Definition: MHO_MPIInterface.hh:212
int fPartnerProcessID
Definition: MHO_MPIInterface.hh:334
std::string fHostName
Definition: MHO_MPIInterface.hh:320
MPI_Status fStatus
Definition: MHO_MPIInterface.hh:339
bool IsEvenGroupMember()
Checks if the current process is a member of the even subgroup.
Definition: MHO_MPIInterface.hh:156
MPI_Group * GetSubGroup()
Getter for sub group.
Definition: MHO_MPIInterface.hh:184
void EndSequentialProcess()
Sends a flag to the next process and waits for all processes to finish.
Definition: MHO_MPIInterface.cc:120
int GetNProcesses() const
Getter for N processes.
Definition: MHO_MPIInterface.hh:85
MPI_Comm * GetOddCommunicator()
Definition: MHO_MPIInterface.hh:214
void BeginSequentialProcess()
Isolates a section of code for sequential processing by each process one at a time.
Definition: MHO_MPIInterface.cc:110
std::set< std::string > MergeStringSet(const std::set< std::string > &local_set)
merge a set of strings across all processes (collected on the root process 0)
Definition: MHO_MPIInterface.cc:484
int GetGlobalProcessID() const
Getter for global process id.
Definition: MHO_MPIInterface.hh:78
int fLocalProcessID
Definition: MHO_MPIInterface.hh:319
static MHO_MPIInterface * GetInstance()
Getter for instance.
Definition: MHO_MPIInterface.cc:104
int GetLocalProcessID() const
Getter for local process id.
Definition: MHO_MPIInterface.hh:92
bool IsSplitValid()
Checks if even/odd split is valid.
Definition: MHO_MPIInterface.hh:149
bool SplitMode()
Checks if processes are split into two groups based on even/odd ranks.
Definition: MHO_MPIInterface.hh:142
void BroadcastString(std::string &msg)
Broadcasts a string message to all processes from root/master process.
Definition: MHO_MPIInterface.cc:225
std::map< std::string, T > MergeMap(const std::map< std::string, T > &local_map)
merge a collection of maps across all processes, so that it is available for the root (0) process
Definition: MHO_MPIInterface.hh:221
int fSubGroupRank
Definition: MHO_MPIInterface.hh:332
MPI_Comm fEvenCommunicator
Definition: MHO_MPIInterface.hh:328
void GlobalBarrier() const
Waits for all processes in MPI_COMM_WORLD to reach this barrier.
Definition: MHO_MPIInterface.hh:115
void Finalize()
Finalizes MPI by calling MPI_Finalize if not already finalized.
Definition: MHO_MPIInterface.cc:93
bool Check() const
Checks if global process ID is non-negative and number of processes is greater than zero.
Definition: MHO_MPIInterface.hh:71
int GetSubGroupRank()
Getter for sub group rank.
Definition: MHO_MPIInterface.hh:170
MHO_MPIInterface()
Definition: MHO_MPIInterface.cc:34
void Initialize(int *argc, char ***argv, bool split_mode=true)
Initializes MPI environment and sets up process groups/communicators.
Definition: MHO_MPIInterface.cc:47
MPI_Group * GetOddGroup()
Definition: MHO_MPIInterface.hh:210
std::vector< int > fCoHostedProcessIDs
Definition: MHO_MPIInterface.hh:321
bool fSplitMode
Definition: MHO_MPIInterface.hh:325
int fGlobalProcessID
Definition: MHO_MPIInterface.hh:317
int GetPartnerProcessID()
Getter for partner process id.
Definition: MHO_MPIInterface.hh:177
void SetupSubGroups()
Definition: MHO_MPIInterface.cc:368
MPI_Comm fOddCommunicator
Definition: MHO_MPIInterface.hh:329
void DetermineLocalRank()
Definition: MHO_MPIInterface.cc:248
int fNSubGroupProcesses
Definition: MHO_MPIInterface.hh:333
void msg(const char *string, int level,...)
Definition: msg.c:25
Definition: MHO_AdhocFlagging.hh:18
MPI_Datatype mpi_type_for()
MPI_Datatype mpi_type_for< float >()
Definition: MHO_MPIInterface.hh:28
MPI_Datatype mpi_type_for< int >()
Definition: MHO_MPIInterface.hh:18
MPI_Datatype mpi_type_for< double >()
Definition: MHO_MPIInterface.hh:23