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 #include <map>
10 
11 #define LOCAL_RANK_MPI
12 
13 namespace hops
14 {
15 
16 //helper template for mapping basic types to MPI type codes
17 template< typename T > MPI_Datatype mpi_type_for();
18 
19 template<> inline MPI_Datatype mpi_type_for< int >()
20 {
21  return MPI_INT;
22 }
23 
24 template<> inline MPI_Datatype mpi_type_for< double >()
25 {
26  return MPI_DOUBLE;
27 }
28 
29 template<> inline MPI_Datatype mpi_type_for< float >()
30 {
31  return MPI_FLOAT;
32 }
33 
43 {
44  public:
45  //singleton interface
52  static MHO_MPIInterface* GetInstance();
53 
61  void Initialize(int* argc, char*** argv, bool split_mode = true);
65  void Finalize();
66 
72  bool Check() const { return (fGlobalProcessID >= 0) && (fNProcesses > 0); }
73 
79  int GetGlobalProcessID() const { return fGlobalProcessID; }
80 
86  int GetNProcesses() const { return fNProcesses; }
87 
93  int GetLocalProcessID() const { return fLocalProcessID; }
94 
100  std::string GetHostName() const { return fHostName; };
101 
102  //use to isolate a section of code, so each process completes it
103  //one at a time
107  void BeginSequentialProcess();
111  void EndSequentialProcess();
112 
116  void GlobalBarrier() const { MPI_Barrier(MPI_COMM_WORLD); }
117 
126  void PrintMessage(std::string msg);
127 
128  //broadcast a string message to all processes
134  void BroadcastString(std::string& msg);
135 
136  //routines to be used by programs which split the processes into two
137  //groups bases on even/odd local process rank
143  bool SplitMode() { return fSplitMode; };
144 
150  bool IsSplitValid() { return fValidSplit; };
151 
158 
165 
171  int GetSubGroupRank() { return fSubGroupRank; };
172 
179 
185  MPI_Group* GetSubGroup()
186  {
188  {
189  return &fEvenGroup;
190  }
191  else
192  {
193  return &fOddGroup;
194  };
195  }
196 
198  {
200  {
201  return &fEvenCommunicator;
202  }
203  else
204  {
205  return &fOddCommunicator;
206  };
207  }
208 
209  MPI_Group* GetEvenGroup() { return &fEvenGroup; };
210 
211  MPI_Group* GetOddGroup() { return &fOddGroup; };
212 
213  MPI_Comm* GetEvenCommunicator() { return &fEvenCommunicator; };
214 
215  MPI_Comm* GetOddCommunicator() { return &fOddCommunicator; };
216 
222  template< typename T > std::map< std::string, T > MergeMap(const std::map< std::string, T >& local_map)
223  {
224  //serialize the local map into primitive types
225  std::vector< int > key_lengths;
226  std::string concatenated_keys;
227  std::vector< T > values;
228 
229  for(const auto& kv : local_map)
230  {
231  key_lengths.push_back(static_cast< int >(kv.first.size()));
232  concatenated_keys += kv.first;
233  values.push_back(kv.second);
234  }
235 
236  int local_entry_count = static_cast< int >(local_map.size());
237  int local_char_count = static_cast< int >(concatenated_keys.size());
238  // gather map entry counts
239  std::vector< int > entry_counts(fNProcesses);
240  MPI_Gather(&local_entry_count, 1, MPI_INT, entry_counts.data(), 1, MPI_INT, 0, MPI_COMM_WORLD);
241 
242  //gather key character counts
243  std::vector< int > char_counts(fNProcesses);
244  MPI_Gather(&local_char_count, 1, MPI_INT, char_counts.data(), 1, MPI_INT, 0, MPI_COMM_WORLD);
245 
246  std::map< std::string, T > merged;
247 
248  //only rank 0 reconstructs ---
249  if(fGlobalProcessID == 0)
250  {
251  // Compute displacements
252  std::vector< int > entry_displs(fNProcesses, 0);
253  std::vector< int > char_displs(fNProcesses, 0);
254 
255  for(int i = 1; i < fNProcesses; ++i)
256  {
257  entry_displs[i] = entry_displs[i - 1] + entry_counts[i - 1];
258  char_displs[i] = char_displs[i - 1] + char_counts[i - 1];
259  }
260 
261  int total_entries = entry_displs[fNProcesses - 1] + entry_counts[fNProcesses - 1];
262  int total_chars = char_displs[fNProcesses - 1] + char_counts[fNProcesses - 1];
263 
264  // allocate receive buffers
265  std::vector< int > all_key_lengths(total_entries);
266  std::vector< char > all_chars(total_chars);
267  std::vector< T > all_values(total_entries);
268 
269  // gather key lengths
270  MPI_Gatherv(key_lengths.data(), local_entry_count, MPI_INT, all_key_lengths.data(), entry_counts.data(),
271  entry_displs.data(), MPI_INT, 0, MPI_COMM_WORLD);
272 
273  // gather keys
274  MPI_Gatherv(concatenated_keys.data(), local_char_count, MPI_CHAR, all_chars.data(), char_counts.data(),
275  char_displs.data(), MPI_CHAR, 0, MPI_COMM_WORLD);
276 
277  // gather values
278  MPI_Gatherv(values.data(), local_entry_count, mpi_type_for< T >(), all_values.data(), entry_counts.data(),
279  entry_displs.data(), mpi_type_for< T >(), 0, MPI_COMM_WORLD);
280 
281  // Reconstruct merged map
282  size_t pos = 0;
283  for(int i = 0; i < total_entries; ++i)
284  {
285  int len = all_key_lengths[i];
286  std::string key(all_chars.begin() + pos, all_chars.begin() + pos + len);
287  pos += len;
288  merged[key] = all_values[i];
289  }
290  }
291  else
292  {
293  //non-root ranks just need to participate in gathers
294  MPI_Gatherv(key_lengths.data(), local_entry_count, MPI_INT, nullptr, nullptr, nullptr, MPI_INT, 0,
295  MPI_COMM_WORLD);
296 
297  MPI_Gatherv(concatenated_keys.data(), local_char_count, MPI_CHAR, nullptr, nullptr, nullptr, MPI_CHAR, 0,
298  MPI_COMM_WORLD);
299 
300  MPI_Gatherv(values.data(), local_entry_count, mpi_type_for< T >(), nullptr, nullptr, nullptr,
301  mpi_type_for< T >(), 0, MPI_COMM_WORLD);
302  }
303 
304  return merged;
305  }
306 
312  std::set< std::string > MergeStringSet(const std::set< std::string >& local_set);
313 
314  protected:
316  virtual ~MHO_MPIInterface();
317 
321  std::string fHostName;
322  std::vector< int > fCoHostedProcessIDs;
323 
324  //groups and communicators for splitting processes into
325  //two sets, based on whether they have even/odd (local) ranks
327  MPI_Group fEvenGroup; //even process subgroup
328  MPI_Group fOddGroup; //odd process subgroup
329  MPI_Comm fEvenCommunicator; //comm for even group
330  MPI_Comm fOddCommunicator; //comm for odd group
331  bool fValidSplit; //true if the size of the subgroups is equal
332  bool fIsEvenGroupMember; //true if this process is a member of the even subgroup
333  int fSubGroupRank; //rank of this process in its subgroup
334  int fNSubGroupProcesses; //number of processes in the subgroup this process belongs to
335  int fPartnerProcessID; //global rank of partner process in other subgroup
336 
337  void DetermineLocalRank();
338  void SetupSubGroups();
339 
340  MPI_Status fStatus;
341 };
342 
343 } //end of namespace hops
344 
345 #endif
interface functions for initialization of a MPI environment
Definition: MHO_MPIInterface.hh:43
MPI_Group fEvenGroup
Definition: MHO_MPIInterface.hh:327
bool fValidSplit
Definition: MHO_MPIInterface.hh:331
MPI_Group fOddGroup
Definition: MHO_MPIInterface.hh:328
int fNProcesses
Definition: MHO_MPIInterface.hh:319
MPI_Comm * GetSubGroupCommunicator()
Definition: MHO_MPIInterface.hh:197
bool fIsEvenGroupMember
Definition: MHO_MPIInterface.hh:332
std::string GetHostName() const
Getter for host name.
Definition: MHO_MPIInterface.hh:100
MPI_Group * GetEvenGroup()
Definition: MHO_MPIInterface.hh:209
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:164
MPI_Comm * GetEvenCommunicator()
Definition: MHO_MPIInterface.hh:213
int fPartnerProcessID
Definition: MHO_MPIInterface.hh:335
std::string fHostName
Definition: MHO_MPIInterface.hh:321
MPI_Status fStatus
Definition: MHO_MPIInterface.hh:340
bool IsEvenGroupMember()
Checks if the current process is a member of the even subgroup.
Definition: MHO_MPIInterface.hh:157
MPI_Group * GetSubGroup()
Getter for sub group.
Definition: MHO_MPIInterface.hh:185
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:86
MPI_Comm * GetOddCommunicator()
Definition: MHO_MPIInterface.hh:215
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:79
int fLocalProcessID
Definition: MHO_MPIInterface.hh:320
static MHO_MPIInterface * GetInstance()
Getter for instance.
Definition: MHO_MPIInterface.cc:104
int GetLocalProcessID() const
Getter for local process id.
Definition: MHO_MPIInterface.hh:93
bool IsSplitValid()
Checks if even/odd split is valid.
Definition: MHO_MPIInterface.hh:150
bool SplitMode()
Checks if processes are split into two groups based on even/odd ranks.
Definition: MHO_MPIInterface.hh:143
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:222
int fSubGroupRank
Definition: MHO_MPIInterface.hh:333
MPI_Comm fEvenCommunicator
Definition: MHO_MPIInterface.hh:329
void GlobalBarrier() const
Waits for all processes in MPI_COMM_WORLD to reach this barrier.
Definition: MHO_MPIInterface.hh:116
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:72
int GetSubGroupRank()
Getter for sub group rank.
Definition: MHO_MPIInterface.hh:171
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:211
std::vector< int > fCoHostedProcessIDs
Definition: MHO_MPIInterface.hh:322
bool fSplitMode
Definition: MHO_MPIInterface.hh:326
int fGlobalProcessID
Definition: MHO_MPIInterface.hh:318
int GetPartnerProcessID()
Getter for partner process id.
Definition: MHO_MPIInterface.hh:178
void SetupSubGroups()
Definition: MHO_MPIInterface.cc:368
MPI_Comm fOddCommunicator
Definition: MHO_MPIInterface.hh:330
void DetermineLocalRank()
Definition: MHO_MPIInterface.cc:248
int fNSubGroupProcesses
Definition: MHO_MPIInterface.hh:334
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:29
MPI_Datatype mpi_type_for< int >()
Definition: MHO_MPIInterface.hh:19
MPI_Datatype mpi_type_for< double >()
Definition: MHO_MPIInterface.hh:24