MPIWrapper.hpp
Go to the documentation of this file.
1 /*
2  * STRUMPACK -- STRUctured Matrices PACKage, Copyright (c) 2014, The
3  * Regents of the University of California, through Lawrence Berkeley
4  * National Laboratory (subject to receipt of any required approvals
5  * from the U.S. Dept. of Energy). All rights reserved.
6  *
7  * If you have questions about your rights to use or distribute this
8  * software, please contact Berkeley Lab's Technology Transfer
9  * Department at TTD@lbl.gov.
10  *
11  * NOTICE. This software is owned by the U.S. Department of Energy. As
12  * such, the U.S. Government has been granted for itself and others
13  * acting on its behalf a paid-up, nonexclusive, irrevocable,
14  * worldwide license in the Software to reproduce, prepare derivative
15  * works, and perform publicly and display publicly. Beginning five
16  * (5) years after the date permission to assert copyright is obtained
17  * from the U.S. Department of Energy, and subject to any subsequent
18  * five (5) year renewals, the U.S. Government is granted for itself
19  * and others acting on its behalf a paid-up, nonexclusive,
20  * irrevocable, worldwide license in the Software to reproduce,
21  * prepare derivative works, distribute copies to the public, perform
22  * publicly and display publicly, and to permit others to do so.
23  *
24  * Developers: Pieter Ghysels, Francois-Henry Rouet, Xiaoye S. Li.
25  * (Lawrence Berkeley National Lab, Computational Research
26  * Division).
27  *
28  */
33 #ifndef STRUMPACK_MPI_WRAPPER_HPP
34 #define STRUMPACK_MPI_WRAPPER_HPP
35 
36 #include <list>
37 #include <vector>
38 #include <complex>
39 #include <cassert>
40 #include <numeric>
41 #include <limits>
42 #include <memory>
43 #include <utility>
44 #include "StrumpackConfig.hpp"
45 
46 #define OMPI_SKIP_MPICXX 1
47 #include <mpi.h>
48 
49 #include "StrumpackParameters.hpp"
50 #include "Triplet.hpp"
51 
52 namespace strumpack {
53 
60  template<typename T> MPI_Datatype mpi_type() { return T::mpi_type(); }
62  template<> inline MPI_Datatype mpi_type<char>() { return MPI_CHAR; }
64  //template<> inline MPI_Datatype mpi_type<bool>() { return MPI_CXX_BOOL; }
65  template<> inline MPI_Datatype mpi_type<bool>() { return MPI_CHAR; }
67  template<> inline MPI_Datatype mpi_type<int>() { return MPI_INT; }
69  template<> inline MPI_Datatype mpi_type<long>() { return MPI_LONG; }
71  template<> inline MPI_Datatype mpi_type<unsigned long>() { return MPI_UNSIGNED_LONG; }
73  template<> inline MPI_Datatype mpi_type<long long int>() { return MPI_LONG_LONG_INT; }
75  template<> inline MPI_Datatype mpi_type<float>() { return MPI_FLOAT; }
77  template<> inline MPI_Datatype mpi_type<double>() { return MPI_DOUBLE; }
79  //template<> inline MPI_Datatype mpi_type<std::complex<float>>() { return MPI_CXX_FLOAT_COMPLEX; }
80  template<> inline MPI_Datatype mpi_type<std::complex<float>>() { return MPI_C_FLOAT_COMPLEX; }
82  //template<> inline MPI_Datatype mpi_type<std::complex<double>>() { return MPI_CXX_DOUBLE_COMPLEX; }
83  template<> inline MPI_Datatype mpi_type<std::complex<double>>() { return MPI_C_DOUBLE_COMPLEX; }
85  template<> inline MPI_Datatype mpi_type<std::pair<int,int>>() { return MPI_2INT; }
86 
88  template<> inline MPI_Datatype mpi_type<std::pair<long int,long int>>() {
89  static MPI_Datatype l_l_mpi_type = MPI_DATATYPE_NULL;
90  if (l_l_mpi_type == MPI_DATATYPE_NULL) {
91  MPI_Type_contiguous
92  (2, strumpack::mpi_type<long int>(), &l_l_mpi_type);
93  MPI_Type_commit(&l_l_mpi_type);
94  }
95  return l_l_mpi_type;
96  }
98  template<> inline MPI_Datatype mpi_type<std::pair<long long int,long long int>>() {
99  static MPI_Datatype ll_ll_mpi_type = MPI_DATATYPE_NULL;
100  if (ll_ll_mpi_type == MPI_DATATYPE_NULL) {
101  MPI_Type_contiguous
102  (2, strumpack::mpi_type<long long int>(), &ll_ll_mpi_type);
103  MPI_Type_commit(&ll_ll_mpi_type);
104  }
105  return ll_ll_mpi_type;
106  }
107 
124  class MPIRequest {
125  public:
130  req_ = std::unique_ptr<MPI_Request>(new MPI_Request());
131  }
132 
137  MPIRequest(const MPIRequest&) = delete;
138 
142  MPIRequest(MPIRequest&&) = default;
143 
147  MPIRequest& operator=(const MPIRequest&) = delete;
148 
153 
157  void wait() { MPI_Wait(req_.get(), MPI_STATUS_IGNORE); }
158 
159  private:
160  std::unique_ptr<MPI_Request> req_;
161  friend class MPIComm;
162  };
163 
173  inline void wait_all(std::vector<MPIRequest>& reqs) {
174  for (auto& r : reqs) r.wait();
175  reqs.clear();
176  }
177 
178  inline void wait_all(std::vector<MPI_Request>& reqs) {
179  MPI_Waitall(reqs.size(), reqs.data(), MPI_STATUSES_IGNORE);
180  }
181 
194  class MPIComm {
195  public:
200  MPIComm() {}
201 
209  MPIComm(MPI_Comm c) { duplicate(c); }
210 
217  MPIComm(const MPIComm& c) { *this = c; }
218 
225  MPIComm(MPIComm&& c) noexcept { *this = std::move(c); }
226 
231  virtual ~MPIComm() {
232  if (comm_ != MPI_COMM_NULL && comm_ != MPI_COMM_WORLD)
233  MPI_Comm_free(&comm_);
234  }
235 
241  MPIComm& operator=(const MPIComm& c) {
242  if (this != &c) duplicate(c.comm());
243  return *this;
244  }
245 
252  MPIComm& operator=(MPIComm&& c) noexcept {
253  comm_ = c.comm_;
254  c.comm_ = MPI_COMM_NULL;
255  return *this;
256  }
257 
261  MPI_Comm comm() const { return comm_; }
262 
266  bool is_null() const { return comm_ == MPI_COMM_NULL; }
267 
271  int rank() const {
272  assert(comm_ != MPI_COMM_NULL);
273  int r;
274  MPI_Comm_rank(comm_, &r);
275  return r;
276  }
277 
282  int size() const {
283  assert(comm_ != MPI_COMM_NULL);
284  int nprocs;
285  MPI_Comm_size(comm_, &nprocs);
286  return nprocs;
287  }
288 
293  bool is_root() const { return rank() == 0; }
294 
299  void barrier() const { MPI_Barrier(comm_); }
300 
301  template<typename T> void
302  broadcast(std::vector<T>& sbuf) const {
303  MPI_Bcast(sbuf.data(), sbuf.size(), mpi_type<T>(), 0, comm_);
304  }
305 
306  template<typename T> void
307  broadcast_from(std::vector<T>& sbuf, int src) const {
308  MPI_Bcast(sbuf.data(), sbuf.size(), mpi_type<T>(), src, comm_);
309  }
310 
311  template<typename T, std::size_t N> void
312  broadcast(std::array<T,N>& sbuf) const {
313  MPI_Bcast(sbuf.data(), sbuf.size(), mpi_type<T>(), 0, comm_);
314  }
315 
316  template<typename T> void broadcast(T& data) const {
317  MPI_Bcast(&data, 1, mpi_type<T>(), 0, comm_);
318  }
319  template<typename T> void broadcast_from(T& data, int src) const {
320  MPI_Bcast(&data, 1, mpi_type<T>(), src, comm_);
321  }
322  template<typename T> void
323  broadcast(T* sbuf, std::size_t ssize) const {
324  MPI_Bcast(sbuf, ssize, mpi_type<T>(), 0, comm_);
325  }
326  template<typename T> void
327  broadcast_from(T* sbuf, std::size_t ssize, int src) const {
328  MPI_Bcast(sbuf, ssize, mpi_type<T>(), src, comm_);
329  }
330 
331  template<typename T>
332  void all_gather(T* buf, std::size_t rsize) const {
333  MPI_Allgather
334  (MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
335  buf, rsize, mpi_type<T>(), comm_);
336  }
337 
338  template<typename T>
339  void all_gather_v(T* buf, const int* rcnts, const int* displs) const {
340  MPI_Allgatherv
341  (MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, buf, rcnts, displs,
342  mpi_type<T>(), comm_);
343  }
344 
345  template<typename T>
346  void gather(T* sbuf, int ssize, int* rbuf, int rsize, int root) const {
347  MPI_Gather
348  (sbuf, ssize, mpi_type<T>(), rbuf,
349  rsize, mpi_type<T>(), root, comm_);
350  }
351 
352  template<typename T>
353  void gather_v(T* sbuf, int scnts, T* rbuf, const int* rcnts,
354  const int* displs, int root) const {
355  MPI_Gatherv
356  (sbuf, scnts, mpi_type<T>(), rbuf, rcnts, displs,
357  mpi_type<T>(), root, comm_);
358  }
359 
360 
374  template<typename T>
375  MPIRequest isend(const std::vector<T>& sbuf, int dest, int tag) const {
376  MPIRequest req;
377  // const_cast is necessary for ancient openmpi version used on Travis
378  MPI_Isend(const_cast<T*>(sbuf.data()), sbuf.size(), mpi_type<T>(),
379  dest, tag, comm_, req.req_.get());
380  return req;
381  }
382 
395  template<typename T>
396  void isend(const std::vector<T>& sbuf, int dest, int tag,
397  MPI_Request* req) const {
398  // const_cast is necessary for ancient openmpi version used on Travis
399  MPI_Isend(const_cast<T*>(sbuf.data()), sbuf.size(), mpi_type<T>(),
400  dest, tag, comm_, req);
401  }
402 
403  template<typename T>
404  void isend(const T* sbuf, std::size_t ssize, int dest,
405  int tag, MPI_Request* req) const {
406  // const_cast is necessary for ancient openmpi version used on Travis
407  MPI_Isend(const_cast<T*>(sbuf), ssize, mpi_type<T>(),
408  dest, tag, comm_, req);
409  }
410  template<typename T>
411  void send(const T* sbuf, std::size_t ssize, int dest, int tag) const {
412  // const_cast is necessary for ancient openmpi version used on Travis
413  MPI_Send(const_cast<T*>(sbuf), ssize, mpi_type<T>(), dest, tag, comm_);
414  }
415 
416  template<typename T>
417  void isend(const T& buf, int dest, int tag, MPI_Request* req) const {
418  // const_cast is necessary for ancient openmpi version used on Travis
419  MPI_Isend(const_cast<T*>(&buf), 1, mpi_type<T>(),
420  dest, tag, comm_, req);
421  }
422 
436  template<typename T>
437  void send(const std::vector<T>& sbuf, int dest, int tag) const {
438  // const_cast is necessary for ancient openmpi version used on Travis
439  MPI_Send(const_cast<T*>(sbuf.data()), sbuf.size(),
440  mpi_type<T>(), dest, tag, comm_);
441  }
442 
455  template<typename T> std::vector<T> recv(int src, int tag) const {
456  MPI_Status stat;
457  MPI_Probe(src, tag, comm_, &stat);
458  int msgsize;
459  MPI_Get_count(&stat, mpi_type<T>(), &msgsize);
460  //std::vector<T,NoInit<T>> rbuf(msgsize);
461  std::vector<T> rbuf(msgsize);
462  MPI_Recv(rbuf.data(), msgsize, mpi_type<T>(), src, tag,
463  comm_, MPI_STATUS_IGNORE);
464  return rbuf;
465  }
466 
467  template<typename T>
468  std::pair<int,std::vector<T>> recv_any_src(int tag) const {
469  MPI_Status stat;
470  MPI_Probe(MPI_ANY_SOURCE, tag, comm_, &stat);
471  int msgsize;
472  MPI_Get_count(&stat, mpi_type<T>(), &msgsize);
473  std::vector<T> rbuf(msgsize);
474  MPI_Recv(rbuf.data(), msgsize, mpi_type<T>(), stat.MPI_SOURCE,
475  tag, comm_, MPI_STATUS_IGNORE);
476  return {stat.MPI_SOURCE, std::move(rbuf)};
477  }
478 
479  template<typename T> T recv_one(int src, int tag) const {
480  T t;
481  MPI_Recv(&t, 1, mpi_type<T>(), src, tag, comm_, MPI_STATUS_IGNORE);
482  return t;
483  }
484 
485  template<typename T>
486  void irecv(const T* rbuf, std::size_t rsize, int src,
487  int tag, MPI_Request* req) const {
488  // const_cast is necessary for ancient openmpi version used on Travis
489  MPI_Irecv(const_cast<T*>(rbuf), rsize, mpi_type<T>(),
490  src, tag, comm_, req);
491  }
492 
493  template<typename T>
494  void recv(const T* rbuf, std::size_t rsize, int src, int tag) const {
495  // const_cast is necessary for ancient openmpi version used on Travis
496  MPI_Status stat;
497  MPI_Recv(const_cast<T*>(rbuf), rsize, mpi_type<T>(),
498  src, tag, comm_, &stat);
499  }
500 
515  template<typename T> T all_reduce(T t, MPI_Op op) const {
516  MPI_Allreduce(MPI_IN_PLACE, &t, 1, mpi_type<T>(), op, comm_);
517  return t;
518  }
519 
534  template<typename T> T reduce(T t, MPI_Op op) const {
535  if (is_root())
536  MPI_Reduce(MPI_IN_PLACE, &t, 1, mpi_type<T>(), op, 0, comm_);
537  else MPI_Reduce(&t, &t, 1, mpi_type<T>(), op, 0, comm_);
538  return t;
539  }
540 
556  template<typename T> void all_reduce(T* t, int ssize, MPI_Op op) const {
557  MPI_Allreduce(MPI_IN_PLACE, t, ssize, mpi_type<T>(), op, comm_);
558  }
559 
560  template<typename T> void all_reduce(std::vector<T>& t, MPI_Op op) const {
561  all_reduce(t.data(), t.size(), op);
562  }
563 
580  template<typename T> void
581  reduce(T* t, int ssize, MPI_Op op, int dest=0) const {
582  if (rank() == dest)
583  MPI_Reduce(MPI_IN_PLACE, t, ssize, mpi_type<T>(), op, dest, comm_);
584  else MPI_Reduce(t, t, ssize, mpi_type<T>(), op, dest, comm_);
585  }
586 
587  template<typename T>
588  void all_to_all(const T* sbuf, int scnt, T* rbuf) const {
589  MPI_Alltoall
590  (sbuf, scnt, mpi_type<T>(), rbuf, scnt, mpi_type<T>(), comm_);
591  }
592 
593  template<typename T, typename A=std::allocator<T>> std::vector<T,A>
594  all_to_allv(const T* sbuf, int* scnts, int* sdispls,
595  int* rcnts, int* rdispls) const {
596  std::size_t rsize = 0;
597  for (int p=0; p<size(); p++)
598  rsize += rcnts[p];
599  std::vector<T,A> rbuf(rsize);
600  MPI_Alltoallv
601  (sbuf, scnts, sdispls, mpi_type<T>(),
602  rbuf.data(), rcnts, rdispls, mpi_type<T>(), comm_);
603  return rbuf;
604  }
605 
606  template<typename T> void
607  all_to_allv(const T* sbuf, int* scnts, int* sdispls,
608  T* rbuf, int* rcnts, int* rdispls) const {
609  MPI_Alltoallv
610  (sbuf, scnts, sdispls, mpi_type<T>(),
611  rbuf, rcnts, rdispls, mpi_type<T>(), comm_);
612  }
613 
631  template<typename T, typename A=std::allocator<T>> void
632  all_to_all_v(std::vector<std::vector<T>>& sbuf, std::vector<T,A>& rbuf,
633  std::vector<T*>& pbuf) const {
634  all_to_all_v(sbuf, rbuf, pbuf, mpi_type<T>());
635  }
636 
650  template<typename T, typename A=std::allocator<T>> std::vector<T,A>
651  all_to_all_v(std::vector<std::vector<T>>& sbuf) const {
652  std::vector<T,A> rbuf;
653  std::vector<T*> pbuf;
654  all_to_all_v(sbuf, rbuf, pbuf, mpi_type<T>());
655  return rbuf;
656  }
657 
675  template<typename T, typename A=std::allocator<T>> void
676  all_to_all_v(std::vector<std::vector<T>>& sbuf, std::vector<T,A>& rbuf,
677  std::vector<T*>& pbuf, const MPI_Datatype Ttype) const {
678  assert(sbuf.size() == std::size_t(size()));
679  auto P = size();
680  std::unique_ptr<int[]> iwork(new int[4*P]);
681  auto ssizes = iwork.get();
682  auto rsizes = ssizes + P;
683  auto sdispl = ssizes + 2*P;
684  auto rdispl = ssizes + 3*P;
685  for (int p=0; p<P; p++) {
686  if (sbuf[p].size() >
687  static_cast<std::size_t>(std::numeric_limits<int>::max())) {
688  std::cerr << "# ERROR: 32bit integer overflow in all_to_all_v!!"
689  << std::endl;
690  MPI_Abort(comm_, 1);
691  }
692  ssizes[p] = sbuf[p].size();
693  }
694  MPI_Alltoall
695  (ssizes, 1, mpi_type<int>(), rsizes, 1, mpi_type<int>(), comm_);
696  std::size_t totssize = std::accumulate(ssizes, ssizes+P, std::size_t(0)),
697  totrsize = std::accumulate(rsizes, rsizes+P, std::size_t(0));
698  if (totrsize >
699  static_cast<std::size_t>(std::numeric_limits<int>::max()) ||
700  totssize >
701  static_cast<std::size_t>(std::numeric_limits<int>::max())) {
702  // This case will probably cause an overflow in the
703  // rdispl/sdispl elements. Here we do the all_to_all_v
704  // manually by just using Isend/Irecv. This might be slower
705  // than splitting into multiple calls to MPI_Alltoallv
706  // (although it avoids a copy from the sbuf).
707  rbuf.resize(totrsize);
708  std::unique_ptr<MPI_Request[]> reqs(new MPI_Request[2*P]);
709  std::size_t displ = 0;
710  pbuf.resize(P);
711  for (int p=0; p<P; p++) {
712  pbuf[p] = rbuf.data() + displ;
713  MPI_Irecv(pbuf[p], rsizes[p], Ttype, p, 0, comm_, reqs.get()+p);
714  displ += rsizes[p];
715  }
716  for (int p=0; p<P; p++)
717  MPI_Isend
718  (sbuf[p].data(), ssizes[p], Ttype, p, 0, comm_, reqs.get()+P+p);
719  MPI_Waitall(2*P, reqs.get(), MPI_STATUSES_IGNORE);
720  std::vector<std::vector<T>>().swap(sbuf);
721  } else {
722  std::unique_ptr<T[]> sendbuf_(new T[totssize]);
723  auto sendbuf = sendbuf_.get();
724  sdispl[0] = rdispl[0] = 0;
725  for (int p=1; p<P; p++) {
726  sdispl[p] = sdispl[p-1] + ssizes[p-1];
727  rdispl[p] = rdispl[p-1] + rsizes[p-1];
728  }
729  for (int p=0; p<P; p++)
730  std::copy(sbuf[p].begin(), sbuf[p].end(), sendbuf+sdispl[p]);
731  std::vector<std::vector<T>>().swap(sbuf);
732  rbuf.resize(totrsize);
733  MPI_Alltoallv(sendbuf, ssizes, sdispl, Ttype,
734  rbuf.data(), rsizes, rdispl, Ttype, comm_);
735  pbuf.resize(P);
736  for (int p=0; p<P; p++)
737  pbuf[p] = rbuf.data() + rdispl[p];
738  }
739  }
740 
756  MPIComm sub(int P0, int P, int stride=1) const {
757  if (is_null()) return MPIComm(MPI_COMM_NULL);
758  assert(P0 + P <= size());
759  MPIComm sub_comm;
760  std::vector<int> sub_ranks(P);
761  for (int i=0; i<P; i++)
762  sub_ranks[i] = P0 + i*stride;
763  MPI_Group group, sub_group;
764  MPI_Comm_group(comm_, &group); // get group from comm
765  MPI_Group_incl(group, P, sub_ranks.data(), &sub_group); // group ranks [P0,P0+P) into sub_group
766  MPI_Comm_create(comm_, sub_group, &sub_comm.comm_); // create new sub_comm
767  MPI_Group_free(&group);
768  MPI_Group_free(&sub_group);
769  return sub_comm;
770  }
771 
781  // return MPI_COMM_SELF??? or MPI_COMM_NULL if not rank??
782  MPIComm sub_self(int p) const {
783  if (is_null()) return MPIComm(MPI_COMM_NULL);
784  MPIComm c0;
785  MPI_Group group, sub_group;
786  MPI_Comm_group(comm_, &group);
787  MPI_Group_incl(group, 1, &p, &sub_group);
788  MPI_Comm_create(comm_, sub_group, &c0.comm_);
789  MPI_Group_free(&group);
790  MPI_Group_free(&sub_group);
791  return c0;
792  }
793 
797  static void control_start(const std::string& name) {
798  MPI_Pcontrol(1, name.c_str());
799  }
803  static void control_stop(const std::string& name) {
804  MPI_Pcontrol(-1, name.c_str());
805  }
806 
807  static bool initialized() {
808  int flag;
809  MPI_Initialized(&flag);
810  return static_cast<bool>(flag);
811  }
812 
813  private:
814  MPI_Comm comm_ = MPI_COMM_WORLD;
815 
816  void duplicate(MPI_Comm c) {
817  if (c == MPI_COMM_NULL) comm_ = c;
818  else MPI_Comm_dup(c, &comm_);
819  }
820  };
821 
822 
830  inline int mpi_rank(MPI_Comm c=MPI_COMM_WORLD) {
831  assert(c != MPI_COMM_NULL);
832  int rank;
833  MPI_Comm_rank(c, &rank);
834  return rank;
835  }
836 
844  inline int mpi_nprocs(MPI_Comm c=MPI_COMM_WORLD) {
845  assert(c != MPI_COMM_NULL);
846  int nprocs;
847  MPI_Comm_size(c, &nprocs);
848  return nprocs;
849  }
850 
851 } // end namespace strumpack
852 
853 #endif // STRUMPACK_MPI_WRAPPER_HPP
Contains the definition of some useful (global) variables.
Wrapper class around an MPI_Comm object.
Definition: MPIWrapper.hpp:194
virtual ~MPIComm()
Definition: MPIWrapper.hpp:231
MPIComm sub(int P0, int P, int stride=1) const
Definition: MPIWrapper.hpp:756
bool is_root() const
Definition: MPIWrapper.hpp:293
static void control_stop(const std::string &name)
Definition: MPIWrapper.hpp:803
T all_reduce(T t, MPI_Op op) const
Definition: MPIWrapper.hpp:515
void reduce(T *t, int ssize, MPI_Op op, int dest=0) const
Definition: MPIWrapper.hpp:581
MPIComm()
Definition: MPIWrapper.hpp:200
void barrier() const
Definition: MPIWrapper.hpp:299
MPIComm(const MPIComm &c)
Definition: MPIWrapper.hpp:217
std::vector< T, A > all_to_all_v(std::vector< std::vector< T >> &sbuf) const
Definition: MPIWrapper.hpp:651
void send(const std::vector< T > &sbuf, int dest, int tag) const
Definition: MPIWrapper.hpp:437
bool is_null() const
Definition: MPIWrapper.hpp:266
MPI_Comm comm() const
Definition: MPIWrapper.hpp:261
MPIComm & operator=(MPIComm &&c) noexcept
Definition: MPIWrapper.hpp:252
T reduce(T t, MPI_Op op) const
Definition: MPIWrapper.hpp:534
void isend(const std::vector< T > &sbuf, int dest, int tag, MPI_Request *req) const
Definition: MPIWrapper.hpp:396
void all_to_all_v(std::vector< std::vector< T >> &sbuf, std::vector< T, A > &rbuf, std::vector< T * > &pbuf, const MPI_Datatype Ttype) const
Definition: MPIWrapper.hpp:676
MPIComm(MPIComm &&c) noexcept
Definition: MPIWrapper.hpp:225
int size() const
Definition: MPIWrapper.hpp:282
int rank() const
Definition: MPIWrapper.hpp:271
MPIComm & operator=(const MPIComm &c)
Definition: MPIWrapper.hpp:241
void all_to_all_v(std::vector< std::vector< T >> &sbuf, std::vector< T, A > &rbuf, std::vector< T * > &pbuf) const
Definition: MPIWrapper.hpp:632
MPIComm sub_self(int p) const
Definition: MPIWrapper.hpp:782
static void control_start(const std::string &name)
Definition: MPIWrapper.hpp:797
MPIComm(MPI_Comm c)
Definition: MPIWrapper.hpp:209
std::vector< T > recv(int src, int tag) const
Definition: MPIWrapper.hpp:455
MPIRequest isend(const std::vector< T > &sbuf, int dest, int tag) const
Definition: MPIWrapper.hpp:375
void all_reduce(T *t, int ssize, MPI_Op op) const
Definition: MPIWrapper.hpp:556
Wrapper around an MPI_Request object.
Definition: MPIWrapper.hpp:124
MPIRequest(const MPIRequest &)=delete
void wait()
Definition: MPIWrapper.hpp:157
MPIRequest(MPIRequest &&)=default
MPIRequest()
Definition: MPIWrapper.hpp:129
MPIRequest & operator=(const MPIRequest &)=delete
MPIRequest & operator=(MPIRequest &&)=default
Definition: StrumpackOptions.hpp:42
MPI_Datatype mpi_type()
Definition: MPIWrapper.hpp:60
MPI_Datatype mpi_type< int >()
Definition: MPIWrapper.hpp:67
void wait_all(std::vector< MPIRequest > &reqs)
Definition: MPIWrapper.hpp:173
MPI_Datatype mpi_type< long >()
Definition: MPIWrapper.hpp:69
MPI_Datatype mpi_type< float >()
Definition: MPIWrapper.hpp:75
int mpi_rank(MPI_Comm c=MPI_COMM_WORLD)
Definition: MPIWrapper.hpp:830
MPI_Datatype mpi_type< long long int >()
Definition: MPIWrapper.hpp:73
MPI_Datatype mpi_type< bool >()
Definition: MPIWrapper.hpp:65
void copy(std::size_t m, std::size_t n, const DenseMatrix< scalar_from_t > &a, std::size_t ia, std::size_t ja, DenseMatrix< scalar_to_t > &b, std::size_t ib, std::size_t jb)
Definition: DenseMatrix.hpp:1231
MPI_Datatype mpi_type< double >()
Definition: MPIWrapper.hpp:77
int mpi_nprocs(MPI_Comm c=MPI_COMM_WORLD)
Definition: MPIWrapper.hpp:844
MPI_Datatype mpi_type< unsigned long >()
Definition: MPIWrapper.hpp:71
MPI_Datatype mpi_type< char >()
Definition: MPIWrapper.hpp:62