HavoqGT
mpi.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013, Lawrence Livermore National Security, LLC.
3  * Produced at the Lawrence Livermore National Laboratory.
4  * Written by Roger Pearce <rpearce@llnl.gov>.
5  * LLNL-CODE-644630.
6  * All rights reserved.
7  *
8  * This file is part of HavoqGT, Version 0.1.
9  * For details, see https://computation.llnl.gov/casc/dcca-pub/dcca/Downloads.html
10  *
11  * Please also read this link – Our Notice and GNU Lesser General Public License.
12  * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
13  *
14  * This program is free software; you can redistribute it and/or modify it under
15  * the terms of the GNU Lesser General Public License (as published by the Free
16  * Software Foundation) version 2.1 dated February 1999.
17  *
18  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
19  * WARRANTY; without even the IMPLIED WARRANTY OF MERCHANTABILITY or FITNESS FOR A
20  * PARTICULAR PURPOSE. See the terms and conditions of the GNU General Public
21  * License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public License along
24  * with this program; if not, write to the Free Software Foundation, Inc.,
25  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26  *
27  * OUR NOTICE AND TERMS AND CONDITIONS OF THE GNU GENERAL PUBLIC LICENSE
28  *
29  * Our Preamble Notice
30  *
31  * A. This notice is required to be provided under our contract with the
32  * U.S. Department of Energy (DOE). This work was produced at the Lawrence
33  * Livermore National Laboratory under Contract No. DE-AC52-07NA27344 with the DOE.
34  *
35  * B. Neither the United States Government nor Lawrence Livermore National
36  * Security, LLC nor any of their employees, makes any warranty, express or
37  * implied, or assumes any liability or responsibility for the accuracy,
38  * completeness, or usefulness of any information, apparatus, product, or process
39  * disclosed, or represents that its use would not infringe privately-owned rights.
40  *
41  * C. Also, reference herein to any specific commercial products, process, or
42  * services by trade name, trademark, manufacturer or otherwise does not
43  * necessarily constitute or imply its endorsement, recommendation, or favoring by
44  * the United States Government or Lawrence Livermore National Security, LLC. The
45  * views and opinions of authors expressed herein do not necessarily state or
46  * reflect those of the United States Government or Lawrence Livermore National
47  * Security, LLC, and shall not be used for advertising or product endorsement
48  * purposes.
49  *
50  */
51 
52 #ifndef _HAVOQGT_MPI_HPP_
53 #define _HAVOQGT_MPI_HPP_
54 
56 #include <sched.h>
57 #include <vector>
58 #include <mpi.h>
59 #include <assert.h>
60 #include <stdlib.h>
61 #include <functional>
62 #include <iostream>
63 #include <algorithm>
64 #include <numeric>
65 #include <stdint.h>
66 
67 
68 #define CHK_MPI(a) { if (a != MPI_SUCCESS) {\
69  char* error_string = NULL; \
70  int len = 0; \
71  MPI_Error_string(a, error_string, &len); \
72  std::cerr << __FILE__ << ", line " << __LINE__ \
73  <<" MPI ERROR = " << error_string << std::endl; \
74  exit(-1); \
75  } }
76 
77 
78 namespace havoqgt { namespace mpi {
79 
80 inline MPI_Datatype mpi_typeof(char) {return MPI_CHAR;}
81 inline MPI_Datatype mpi_typeof(signed short) {return MPI_SHORT;}
82 inline MPI_Datatype mpi_typeof(signed int) {return MPI_INT;}
83 inline MPI_Datatype mpi_typeof(signed long) {return MPI_LONG;}
84 inline MPI_Datatype mpi_typeof(unsigned char) {return MPI_UNSIGNED_CHAR;}
85 inline MPI_Datatype mpi_typeof(unsigned short) {return MPI_UNSIGNED_SHORT;}
86 inline MPI_Datatype mpi_typeof(unsigned) {return MPI_UNSIGNED;}
87 inline MPI_Datatype mpi_typeof(unsigned long) {return MPI_UNSIGNED_LONG;}
88 inline MPI_Datatype mpi_typeof(unsigned long long) {return MPI_UNSIGNED_LONG_LONG; }
89 inline MPI_Datatype mpi_typeof(signed long long) {return MPI_LONG_LONG_INT;}
90 inline MPI_Datatype mpi_typeof(double) {return MPI_DOUBLE;}
91 inline MPI_Datatype mpi_typeof(long double) {return MPI_LONG_DOUBLE;}
92 inline MPI_Datatype mpi_typeof(std::pair<int,int>) {return MPI_2INT;}
93 inline MPI_Datatype mpi_typeof(std::pair<float,int>) {return MPI_FLOAT_INT;}
94 inline MPI_Datatype mpi_typeof(std::pair<double,int>) {return MPI_DOUBLE_INT;}
95 inline MPI_Datatype mpi_typeof(std::pair<long double,int>) {return MPI_LONG_DOUBLE_INT;}
96 inline MPI_Datatype mpi_typeof(std::pair<short,int>) {return MPI_SHORT_INT;}
97 
98 template <typename T>
99 MPI_Op mpi_typeof(std::greater<T>) { return MPI_MAX; }
100 
101 template <typename T>
102 MPI_Op mpi_typeof(std::less<T>) { return MPI_MIN; }
103 
104 template <typename T>
105 MPI_Op mpi_typeof(std::plus<T>) { return MPI_SUM; }
106 
107 template <typename T>
108 MPI_Op mpi_typeof(std::multiplies<T>) { return MPI_PROD; }
109 
110 template <typename T>
111 MPI_Op mpi_typeof(std::logical_and<T>) { return MPI_LAND; }
112 
113 template <typename T>
114 MPI_Op mpi_typeof(std::logical_or<T>) { return MPI_LOR; }
115 
117 public:
118  mpi_communicator(int argc, char** argv)
119  : init(true) {
120  check_mpi( MPI_Init(&argc, &argv) );
121  m_comm = MPI_COMM_WORLD;
122  }
123  mpi_communicator(MPI_Comm comm)
124  : m_comm(MPI_COMM_WORLD),
125  init(false) { }
126 
128  if(init) {
129  check_mpi( MPI_Finalize() );
130  }
131  }
132 
133 private:
136 
138  void check_mpi(int ret) {
139  if(ret != MPI_SUCCESS) {
140  char estring[MPI_MAX_ERROR_STRING];
141  int len(0);
142  MPI_Error_string(ret, estring, &len);
143  if(m_rank==0) {
144  std::cerr << "MPI ERROR = " << estring << std::endl;
145  }
146  MPI_Abort(m_comm, -1);
147  }
148  }
149 
150  MPI_Comm m_comm;
151  uint32_t m_size;
152  uint32_t m_rank;
153  bool init;
154 };
155 
156 void mpi_yield_barrier(MPI_Comm mpi_comm) {
157  MPI_Request request;
158  CHK_MPI(MPI_Ibarrier(mpi_comm, &request));
159 
160  for(; ;) {
161  MPI_Status status;
162  int is_done = false;
163  MPI_Test(&request, &is_done, &status);
164  if (is_done) {
165  return;
166  } else {
167  sched_yield();
168  }
169  }
170 }
171 
172 
173 //no std:: equivalent for MPI_BAND, MPI_BOR, MPI_LXOR, MPI_BXOR, MPI_MAXLOC, MPI_MINLOC
174 
175 template <typename T, typename Op>
176 T mpi_all_reduce(T in_d, Op in_op, MPI_Comm mpi_comm) {
177  T to_return;
178  CHK_MPI(
179  MPI_Allreduce( &in_d, &to_return, 1, mpi_typeof(T()), mpi_typeof(in_op),
180  mpi_comm)
181  );
182  return to_return;
183 }
184 
185 template <typename Vec, typename Op>
186 void mpi_all_reduce_inplace(Vec &vec, Op in_op, MPI_Comm mpi_comm) {
187  CHK_MPI(
188  MPI_Allreduce(MPI_IN_PLACE, &(vec[0]), vec.size(),
189  mpi_typeof(typename Vec::value_type()), mpi_typeof(in_op), mpi_comm)
190  );
191 }
192 
193 template <typename T, typename Op>
194 void mpi_all_reduce(std::vector<T>& in_vec, std::vector<T>& out_vec, Op in_op,
195  MPI_Comm mpi_comm) {
196  out_vec.resize(in_vec.size());
197  CHK_MPI(
198  MPI_Allreduce( &(in_vec[0]), &(out_vec[0]), in_vec.size(),
199  mpi_typeof(in_vec[0]), mpi_typeof(in_op), mpi_comm)
200  );
201 }
202 
203 
204 template<typename T, typename Partitioner>
205 class owner_sort {
206 public:
207  owner_sort(Partitioner _owner):owner(_owner) { }
208 
209  inline bool operator()(const T& a, const T& b) const {
210  return owner(a) < owner(b);
211  }
212 
213 private:
214  Partitioner owner;
215 };
216 
217 template <typename T>
218 void mpi_all_to_all(std::vector<T>& in_vec, std::vector<int>& in_sendcnts,
219  std::vector<T>& out_vec, std::vector<int>& out_recvcnts,
220  MPI_Comm mpi_comm) {
221  int mpi_size(0), mpi_rank(0);
222  CHK_MPI( MPI_Comm_size( mpi_comm, &mpi_size) );
223  CHK_MPI( MPI_Comm_rank( mpi_comm, &mpi_rank) );
224 
225  void* send_vec = in_vec.size() > 0 ? (void*) &in_vec[0] : NULL;
226  int* send_cnts = in_sendcnts.size() > 0 ? &in_sendcnts[0] : NULL;
227 
228  //
229  // Exchange send counts
230  out_recvcnts.resize(mpi_size);
231  CHK_MPI( MPI_Alltoall( (void*) send_cnts, sizeof(int), MPI_BYTE,
232  (void*) &(out_recvcnts[0]), sizeof(int), MPI_BYTE,
233  mpi_comm ) );
234 
235  //
236  // Calc send & recv disps
237  std::vector<int> sdispls(mpi_size,0), rdispls(mpi_size,0);
238  std::partial_sum(in_sendcnts.begin(), in_sendcnts.end(), sdispls.begin());
239  for(size_t i=0; i<sdispls.size(); ++i) {
240  sdispls[i] -= in_sendcnts[i]; //set to 0 offset
241  }
242  std::partial_sum(out_recvcnts.begin(), out_recvcnts.end(), rdispls.begin());
243  for(size_t i=0; i<rdispls.size(); ++i) {
244  rdispls[i] -= out_recvcnts[i]; //set to 0 offset
245  }
246 
247  out_vec.resize(std::accumulate(out_recvcnts.begin(), out_recvcnts.end(), 0));
248 
249  int* send_displs = sdispls.size() > 0 ? &sdispls[0] : NULL;
250  CHK_MPI( MPI_Alltoallv(send_vec, send_cnts, send_displs,
251  mpi_typeof(T()), &(out_vec[0]), &(out_recvcnts[0]),
252  &(rdispls[0]), mpi_typeof(T()), mpi_comm) );
253 
254 }
255 
256 
257 template <typename T, typename Partitioner>
258 void mpi_all_to_all(std::vector<T>& inout_vec, std::vector<T>& temp_vec,
259  Partitioner &owner, MPI_Comm mpi_comm) {
260  int mpi_size(0), mpi_rank(0);
261  CHK_MPI( MPI_Comm_size( mpi_comm, &mpi_size) );
262  CHK_MPI( MPI_Comm_rank( mpi_comm, &mpi_rank) );
263 
264  std::vector<int> send_counts(mpi_size,0);
265  std::vector<int> send_disps(mpi_size,0);
266 
267  std::vector<int> recv_counts(mpi_size,0);
268  std::vector<int> recv_disps(mpi_size,0);
269 
270  //sort send vector by owner
271  //std::sort(inout_vec.begin(), inout_vec.end(), owner_sort<T,Partitioner>(owner));
272 
273  //calc send counts
274  for(size_t i=0; i<inout_vec.size(); ++i) {
275  send_counts[owner(inout_vec[i])] += sizeof(T); //sizeof(t) lets us use PODS
276  //if(i>0) {
277  // assert(owner(inout_vec[i-1]) <= owner(inout_vec[i]));
278  //}
279  }
280 
281  //cacl send disps
282  std::partial_sum(send_counts.begin(), send_counts.end(), send_disps.begin());
283  for(size_t i=0; i<send_disps.size(); ++i) {
284  send_disps[i] -= send_counts[i]; //set to 0 offset
285  }
286 
287  temp_vec.resize(inout_vec.size());
288  for(size_t i=0; i<inout_vec.size(); ++i) {
289  std::vector<int> temp_arrange(mpi_size,0);
290  int dest_rank = owner(inout_vec[i]);
291  size_t dest_offset = send_disps[dest_rank] + temp_arrange[dest_rank];
292  temp_arrange[dest_rank] += sizeof(T);
293  dest_offset /= sizeof(T);
294  temp_vec[dest_offset] = inout_vec[i];
295  }
296 
297 
298  //exchange send counts
299  CHK_MPI( MPI_Alltoall( (void*) &(send_counts[0]), sizeof(int), MPI_BYTE,
300  (void*) &(recv_counts[0]), sizeof(int), MPI_BYTE,
301  mpi_comm ) );
302 
303  //Allocate recv vector
304  int total_recv = std::accumulate(recv_counts.begin(), recv_counts.end(), 0);
305  inout_vec.resize(total_recv/sizeof(T));
306 
307  //cacl recv disps
308  std::partial_sum(recv_counts.begin(), recv_counts.end(), recv_disps.begin());
309  for(size_t i=0; i<recv_disps.size(); ++i) {
310  recv_disps[i] -= recv_counts[i]; //set to 0 offset
311  }
312 
313  //perform actual a3lloallv
314  CHK_MPI( MPI_Alltoallv( (void*) &(temp_vec[0]), &(send_counts[0]), &(send_disps[0]), MPI_BYTE,
315  (void*) &(inout_vec[0]),&(recv_counts[0]), &(recv_disps[0]), MPI_BYTE,
316  mpi_comm) );
317 }
318 
319 template <typename T, typename Partitioner>
320 void mpi_all_to_all_better(std::vector<T>& in_vec, std::vector<T>& out_vec,
321  Partitioner &owner, MPI_Comm mpi_comm) {
322  int mpi_size(0), mpi_rank(0);
323  CHK_MPI( MPI_Comm_size( mpi_comm, &mpi_size) );
324  CHK_MPI( MPI_Comm_rank( mpi_comm, &mpi_rank) );
325 
326  std::vector<int> send_counts(mpi_size,0);
327  std::vector<int> send_disps(mpi_size,0);
328  std::vector<int> recv_counts(mpi_size,0);
329  std::vector<int> recv_disps(mpi_size,0);
330 
331  //sort send vector by owner
332  //std::sort(in_vec.begin(), in_vec.end(), owner_sort<T,Partitioner>(owner));
333 
334  //calc send counts
335  for(size_t i=0; i<in_vec.size(); ++i) {
336  send_counts[owner(in_vec[i], true)] += sizeof(T); //sizeof(t) lets us use PODS
337  //if(i>0) {
338  // assert(owner(inout_vec[i-1]) <= owner(inout_vec[i]));
339  //
340  }
341 
342 
343  //cacl send disps
344  std::partial_sum(send_counts.begin(), send_counts.end(), send_disps.begin());
345  for(size_t i=0; i<send_disps.size(); ++i) {
346  send_disps[i] -= send_counts[i]; //set to 0 offset
347  }
348 
349 
350  { //rearrange instead of sorting
351  std::vector<T> order_vec(in_vec.size());
352  std::vector<int> temp_arrange(mpi_size,0);
353  for(size_t i=0; i<in_vec.size(); ++i) {
354  int dest_rank = owner(in_vec[i], false);
355  assert (dest_rank >=0 && dest_rank < mpi_size);
356 
357  size_t dest_offset = send_disps[dest_rank] + temp_arrange[dest_rank];
358  temp_arrange[dest_rank] += sizeof(T);
359  dest_offset /= sizeof(T);
360  order_vec[dest_offset] = in_vec[i];
361  }
362  in_vec.swap(order_vec);
363  }
364 
365 
366  //exchange send counts
367  CHK_MPI( MPI_Alltoall( (void*) &(send_counts[0]), sizeof(int), MPI_BYTE,
368  (void*) &(recv_counts[0]), sizeof(int), MPI_BYTE,
369  mpi_comm ) );
370 
371 
372  //Allocate recv vector
373  int total_recv = std::accumulate(recv_counts.begin(), recv_counts.end(), 0);
374  out_vec.resize(total_recv/sizeof(T));
375 
376  //cacl recv disps
377  std::partial_sum(recv_counts.begin(), recv_counts.end(), recv_disps.begin());
378  for(size_t i=0; i<recv_disps.size(); ++i) {
379  recv_disps[i] -= recv_counts[i]; //set to 0 offset
380  }
381 
382  //perform actual alltoallv
383  void* send_ptr = in_vec.empty() ? NULL :(void*) &(in_vec[0]);
384  void* recv_ptr = out_vec.empty() ? NULL :(void*) &(out_vec[0]);
385  CHK_MPI( MPI_Alltoallv( send_ptr, &(send_counts[0]), &(send_disps[0]), MPI_BYTE,
386  recv_ptr, &(recv_counts[0]), &(recv_disps[0]), MPI_BYTE,
387  mpi_comm) );
388 }
389 
390 
391 //This code is very similar to that of:
392 //http://trac.mcs.anl.gov/projects/mpich2/browser/mpich2/trunk/src/mpi/coll/alltoall.c
393 //
394 // It is re-implemted here because <cough> BG/P doesn't support mpi-2.2 which
395 // added MPI_IN_PLACE for Alltoall.
396 template <typename T>
397 void mpi_all_to_all_in_place(std::vector<T>& in_out_vec, size_t count,
398  MPI_Comm mpi_comm) {
399  const int HAVOQGT_TAG=42;
400  int mpi_size(0), mpi_rank(0);
401  CHK_MPI( MPI_Comm_size( mpi_comm, &mpi_size) );
402  CHK_MPI( MPI_Comm_rank( mpi_comm, &mpi_rank) );
403  assert( in_out_vec.size() == count * mpi_size );
404 
405  for(int i=0; i<mpi_size; ++i) {
406  //start inner loop at i to avoid re-exchanging data
407  for(int j=i; j<mpi_size; ++j) {
408  if( mpi_rank == i) {
409  MPI_Status status;
410  CHK_MPI( MPI_Sendrecv_replace(&(in_out_vec[j*count]), count,
411  mpi_typeof(T()),
412  j, HAVOQGT_TAG,
413  j, HAVOQGT_TAG,
414  mpi_comm, &status) );
415 
416  } else if(mpi_rank == j) {
417  MPI_Status status;
418  CHK_MPI( MPI_Sendrecv_replace(&(in_out_vec[i*count]), count,
419  mpi_typeof(T()),
420  i, HAVOQGT_TAG,
421  i, HAVOQGT_TAG,
422  mpi_comm, &status) );
423 
424 
425  }
426  }
427  }
428 }
429 
431 template <typename T>
432 void mpi_all_gather(T _t, std::vector<T>& out_p_vec, MPI_Comm mpi_comm) {
433  int mpi_size(0);
434  CHK_MPI( MPI_Comm_size( mpi_comm, &mpi_size) );
435 
436  out_p_vec.resize(mpi_size);
437  CHK_MPI( MPI_Allgather(&_t, sizeof(_t), MPI_BYTE,
438  &(out_p_vec[0]), sizeof(_t), MPI_BYTE, mpi_comm) );
439 }
440 
442 template <typename T>
443 void mpi_all_gather(std::vector<T>& in_send,
444  std::vector<T>& out_recv_gather, MPI_Comm mpi_comm) {
445 
446  int mpi_size(0), mpi_rank(0);
447  CHK_MPI( MPI_Comm_size( mpi_comm, &mpi_size) );
448  CHK_MPI( MPI_Comm_rank( mpi_comm, &mpi_rank) );
449 
450  int my_size = in_send.size();
451  std::vector<int> recv_counts(mpi_size,0);
452  std::vector<int> recv_disps(mpi_size,0);
453 
454  //Gather recv counts for all ranks
455  mpi_all_gather(my_size, recv_counts, mpi_comm);
456 
457  //Allocate recv vector
458  int total_recv = std::accumulate(recv_counts.begin(), recv_counts.end(), 0);
459  if(total_recv > 0) {
460  out_recv_gather.resize(total_recv);
461 
462  //cacl recv disps
463  std::partial_sum(recv_counts.begin(), recv_counts.end(), recv_disps.begin());
464  for(size_t i=0; i<recv_disps.size(); ++i) {
465  recv_disps[i] -= recv_counts[i]; //set to 0 offset
466  }
467 
468  void* send_buff = in_send.size() == 0 ? NULL : &(in_send[0]);
469  CHK_MPI( MPI_Allgatherv( send_buff, my_size, mpi_typeof(T()),
470  &(out_recv_gather[0]), &(recv_counts[0]), &(recv_disps[0]),
471  mpi_typeof(T()), mpi_comm));
472  }
473 }
474 
475 
486 template <typename T>
487 void mpi_all_to_all(std::vector< std::vector<T> >& in_p_vec,
488  std::vector< std::vector<T> >& out_p_vec,
489  MPI_Comm mpi_comm) {
490  int mpi_size(0), mpi_rank(0);
491  CHK_MPI( MPI_Comm_size( mpi_comm, &mpi_size) );
492  CHK_MPI( MPI_Comm_rank( mpi_comm, &mpi_rank) );
493  assert( mpi_size == (int) in_p_vec.size() );
494 
495  std::vector<size_t> per_rank_send_counts(mpi_size);
496  std::vector<size_t> per_rank_recv_counts(mpi_size);
497 
498  for(int i=0; i<mpi_size; ++i) {
499  per_rank_send_counts[i] = in_p_vec[i].size();
500  }
501 
502  CHK_MPI( MPI_Alltoall( &(per_rank_send_counts[0]), 1, mpi_typeof(size_t()),
503  &(per_rank_recv_counts[0]), 1, mpi_typeof(size_t()),
504  mpi_comm ) );
505  //Allocate recv memory
506  out_p_vec.resize(mpi_size);
507  for(int i=0; i<mpi_size; ++i) {
508  out_p_vec[i].resize(per_rank_recv_counts[i]);
509  }
510 
511 /*
512  * //Aggregisive method, good for small-med p?
513  * std::vector<MPI_Request> vec_req;
514  * for(int i=0; i<mpi_size; ++i) {
515  * int send_to_rank = (mpi_rank + i) % mpi_size;
516  * int recv_from_rank = (mpi_rank - i + mpi_size) % mpi_size;
517  * //Post Irecvs
518  * if(out_p_vec[recv_from_rank].size() > 0) {
519  * MPI_Request req;
520  * CHK_MPI( MPI_Irecv( &(out_p_vec[recv_from_rank][0]),
521  * (out_p_vec[recv_from_rank].size() * sizeof(T)),
522  * MPI_BYTE,
523  * recv_from_rank, 0, mpi_comm, &req ) );
524  * vec_req.push_back(req);
525  * }
526  *
527  * //Post Isends
528  * if(in_p_vec[send_to_rank].size() > 0) {
529  * MPI_Request req;
530  * CHK_MPI( MPI_Isend( &(in_p_vec[send_to_rank][0]),
531  * (in_p_vec[send_to_rank].size() * sizeof(T)),
532  * MPI_BYTE,
533  * send_to_rank, 0, mpi_comm, &req) );
534  * vec_req.push_back(req);
535  * }
536  * }
537  * CHK_MPI( MPI_Waitall(vec_req.size(), &(vec_req[0]), MPI_STATUSES_IGNORE) );
538  */
539 
540  //Basic method -- good for large p?
541  //For each rank, in parallel do:
542  for(int i=0; i<mpi_size; ++i) {
543  MPI_Request request[2];
544  int send_to_rank = (mpi_rank + i) % mpi_size;
545  int recv_from_rank = (mpi_rank - i + mpi_size) % mpi_size;
546  CHK_MPI( MPI_Isend( &(in_p_vec[send_to_rank][0]),
547  (in_p_vec[send_to_rank].size() * sizeof(T)),
548  MPI_BYTE,
549  send_to_rank, 0, mpi_comm, &(request[0]) ) );
550  CHK_MPI( MPI_Irecv( &(out_p_vec[recv_from_rank][0]),
551  (out_p_vec[recv_from_rank].size() * sizeof(T)),
552  MPI_BYTE,
553  recv_from_rank, 0, mpi_comm, &(request[1]) ) );
554  CHK_MPI( MPI_Waitall(2, request, MPI_STATUSES_IGNORE) );
555  }
556 }
557 
558 template <typename T>
559 void mpi_bcast(T& data, int root, MPI_Comm comm)
560 {
561  CHK_MPI( MPI_Bcast(&data, sizeof(data), MPI_BYTE, root, comm));
562 }
563 
564 
565 inline std::ostream& cout_rank0() {
566  int mpi_rank(0);
567  CHK_MPI( MPI_Comm_rank( MPI_COMM_WORLD, &mpi_rank) );
568 
569  if(mpi_rank == 0) {
570  return std::cout;
571  }
573 }
574 
575 inline std::ostream& cout_rank0_barrier() {
576  CHK_MPI( MPI_Barrier( MPI_COMM_WORLD ));
577  int mpi_rank(0);
578  CHK_MPI( MPI_Comm_rank( MPI_COMM_WORLD, &mpi_rank) );
579 
580  if(mpi_rank == 0) {
581  return std::cout;
582  }
584 }
585 
586 
587 inline int mpi_comm_rank() {
588  int rank;
589  CHK_MPI( MPI_Comm_rank(MPI_COMM_WORLD, &rank) );
590  return rank;
591 }
592 
593 inline int mpi_comm_size() {
594  int size;
595  CHK_MPI( MPI_Comm_size(MPI_COMM_WORLD, &size) );
596  return size;
597 }
598 
599 
600 } //end namespace mpi
601 
605 
607 public:
608  communicator(MPI_Comm in_comm)
609  : m_comm( in_comm )
610  {
611  CHK_MPI( MPI_Comm_rank(m_comm, &m_rank) );
612  CHK_MPI( MPI_Comm_size(m_comm, &m_size) );
613  }
614 
616 
617  MPI_Comm comm() const { return m_comm; }
618  int size() const { return m_size; }
619  int rank() const { return m_rank; }
620 
621  void barrier() const {
622  MPI_Barrier(m_comm);
623  }
624 private:
625  MPI_Comm m_comm;
626  int m_size;
627  int m_rank;
628 
629 };
630 
631 
632 } // end namespace havoqgt
633 
634 #endif //_HAVOQGT_MPI_HPP_
635 
MPI_Comm m_comm
Definition: mpi.hpp:625
void barrier() const
Definition: mpi.hpp:621
Partitioner owner
Definition: mpi.hpp:214
int mpi_comm_size()
Definition: mpi.hpp:593
communicator(MPI_Comm in_comm)
Definition: mpi.hpp:608
std::ostream & cout_rank0()
Definition: mpi.hpp:565
mpi_communicator(int argc, char **argv)
Definition: mpi.hpp:118
owner_sort(Partitioner _owner)
Definition: mpi.hpp:207
void mpi_all_to_all_better(std::vector< T > &in_vec, std::vector< T > &out_vec, Partitioner &owner, MPI_Comm mpi_comm)
Definition: mpi.hpp:320
void mpi_all_reduce_inplace(Vec &vec, Op in_op, MPI_Comm mpi_comm)
Definition: mpi.hpp:186
int size() const
Definition: mpi.hpp:618
int mpi_comm_rank()
Definition: mpi.hpp:587
MPI_Comm comm() const
Definition: mpi.hpp:617
T mpi_all_reduce(T in_d, Op in_op, MPI_Comm mpi_comm)
Definition: mpi.hpp:176
std::ostream & get_null_ostream()
int rank() const
Definition: mpi.hpp:619
void mpi_all_gather(T _t, std::vector< T > &out_p_vec, MPI_Comm mpi_comm)
TODO: Add tests.
Definition: mpi.hpp:432
std::ostream & cout_rank0_barrier()
Definition: mpi.hpp:575
MPI_Datatype mpi_typeof(char)
Definition: mpi.hpp:80
void mpi_yield_barrier(MPI_Comm mpi_comm)
Definition: mpi.hpp:156
void mpi_all_to_all_in_place(std::vector< T > &in_out_vec, size_t count, MPI_Comm mpi_comm)
Definition: mpi.hpp:397
void check_mpi(int ret)
Checks MPI return codes.
Definition: mpi.hpp:138
#define CHK_MPI(a)
Definition: mpi.hpp:68
void mpi_bcast(T &data, int root, MPI_Comm comm)
Definition: mpi.hpp:559
bool operator()(const T &a, const T &b) const
Definition: mpi.hpp:209
void mpi_all_to_all(std::vector< T > &in_vec, std::vector< int > &in_sendcnts, std::vector< T > &out_vec, std::vector< int > &out_recvcnts, MPI_Comm mpi_comm)
Definition: mpi.hpp:218
mpi_communicator(MPI_Comm comm)
Definition: mpi.hpp:123