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
50#include "Triplet.hpp"
51
52namespace 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
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:
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
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 MPI_Reduce(is_root() ? MPI_IN_PLACE : &t, &t, 1,
536 mpi_type<T>(), op, 0, comm_);
537 return t;
538 }
539
555 template<typename T> void all_reduce(T* t, int ssize, MPI_Op op) const {
556 MPI_Allreduce(MPI_IN_PLACE, t, ssize, mpi_type<T>(), op, comm_);
557 }
558
559 template<typename T> void all_reduce(std::vector<T>& t, MPI_Op op) const {
560 all_reduce(t.data(), t.size(), op);
561 }
562
579 template<typename T> void
580 reduce(T* t, int ssize, MPI_Op op, int dest=0) const {
581 MPI_Reduce(rank() == dest ? MPI_IN_PLACE : t, t, ssize,
582 mpi_type<T>(), op, dest, comm_);
583 }
584
585 template<typename T>
586 void all_to_all(const T* sbuf, int scnt, T* rbuf) const {
587 MPI_Alltoall
588 (sbuf, scnt, mpi_type<T>(), rbuf, scnt, mpi_type<T>(), comm_);
589 }
590
591 template<typename T, typename A=std::allocator<T>> std::vector<T,A>
592 all_to_allv(const T* sbuf, int* scnts, int* sdispls,
593 int* rcnts, int* rdispls) const {
594 std::size_t rsize = 0;
595 for (int p=0; p<size(); p++)
596 rsize += rcnts[p];
597 std::vector<T,A> rbuf(rsize);
598 MPI_Alltoallv
599 (sbuf, scnts, sdispls, mpi_type<T>(),
600 rbuf.data(), rcnts, rdispls, mpi_type<T>(), comm_);
601 return rbuf;
602 }
603
604 template<typename T> void
605 all_to_allv(const T* sbuf, int* scnts, int* sdispls,
606 T* rbuf, int* rcnts, int* rdispls) const {
607 MPI_Alltoallv
608 (sbuf, scnts, sdispls, mpi_type<T>(),
609 rbuf, rcnts, rdispls, mpi_type<T>(), comm_);
610 }
611
629 template<typename T, typename A=std::allocator<T>> void
630 all_to_all_v(std::vector<std::vector<T>>& sbuf, std::vector<T,A>& rbuf,
631 std::vector<T*>& pbuf) const {
632 all_to_all_v(sbuf, rbuf, pbuf, mpi_type<T>());
633 }
634
648 template<typename T, typename A=std::allocator<T>> std::vector<T,A>
649 all_to_all_v(std::vector<std::vector<T>>& sbuf) const {
650 std::vector<T,A> rbuf;
651 std::vector<T*> pbuf;
652 all_to_all_v(sbuf, rbuf, pbuf, mpi_type<T>());
653 return rbuf;
654 }
655
673 template<typename T, typename A=std::allocator<T>> void
674 all_to_all_v(std::vector<std::vector<T>>& sbuf, std::vector<T,A>& rbuf,
675 std::vector<T*>& pbuf, const MPI_Datatype Ttype) const {
676 assert(sbuf.size() == std::size_t(size()));
677 auto P = size();
678 std::unique_ptr<int[]> iwork(new int[4*P]);
679 auto ssizes = iwork.get();
680 auto rsizes = ssizes + P;
681 auto sdispl = ssizes + 2*P;
682 auto rdispl = ssizes + 3*P;
683 for (int p=0; p<P; p++) {
684 if (sbuf[p].size() >
685 static_cast<std::size_t>(std::numeric_limits<int>::max())) {
686 std::cerr << "# ERROR: 32bit integer overflow in all_to_all_v!!"
687 << std::endl;
688 MPI_Abort(comm_, 1);
689 }
690 ssizes[p] = sbuf[p].size();
691 }
692 MPI_Alltoall
693 (ssizes, 1, mpi_type<int>(), rsizes, 1, mpi_type<int>(), comm_);
694 std::size_t totssize = std::accumulate(ssizes, ssizes+P, std::size_t(0)),
695 totrsize = std::accumulate(rsizes, rsizes+P, std::size_t(0));
696#if 1
697 if (true) {
698 // Always implement the all_to_all_v with Irecv/Isend loops.
699 // We noticed (on NERSC Cori) that MPI_Alltoallv gave wrong
700 // results for large problems (using double complex), likely
701 // due to some overflow, even tho the totssize/totrsize was <
702 // MAX_INT. Also, using Irecv/Isend directly avoids to copies
703 // from the separate send buffers to the single send buffer.
704#else
705 if (totrsize >
706 static_cast<std::size_t>(std::numeric_limits<int>::max()) ||
707 totssize >
708 static_cast<std::size_t>(std::numeric_limits<int>::max())) {
709#endif
710 // This case will probably cause an overflow in the
711 // rdispl/sdispl elements. Here we do the all_to_all_v
712 // manually by just using Isend/Irecv. This might be slower
713 // than splitting into multiple calls to MPI_Alltoallv
714 // (although it avoids a copy from the sbuf).
715 rbuf.resize(totrsize);
716 std::unique_ptr<MPI_Request[]> reqs(new MPI_Request[2*P]);
717 std::size_t displ = 0;
718 pbuf.resize(P);
719 int r = rank();
720 for (int p=0; p<P; p++) {
721 auto dst = (r + p) % P;
722 pbuf[dst] = rbuf.data() + displ;
723 MPI_Irecv(pbuf[dst], rsizes[dst], Ttype, dst, 0, comm_, reqs.get()+dst);
724 displ += rsizes[dst];
725 }
726 for (int p=0; p<P; p++) {
727 auto dst = (r + p) % P;
728 MPI_Isend
729 (sbuf[dst].data(), ssizes[dst], Ttype, dst, 0, comm_, reqs.get()+P+dst);
730 }
731 MPI_Waitall(2*P, reqs.get(), MPI_STATUSES_IGNORE);
732 std::vector<std::vector<T>>().swap(sbuf);
733 } else {
734 std::unique_ptr<T[]> sendbuf_(new T[totssize]);
735 auto sendbuf = sendbuf_.get();
736 sdispl[0] = rdispl[0] = 0;
737 for (int p=1; p<P; p++) {
738 sdispl[p] = sdispl[p-1] + ssizes[p-1];
739 rdispl[p] = rdispl[p-1] + rsizes[p-1];
740 }
741 for (int p=0; p<P; p++)
742 std::copy(sbuf[p].begin(), sbuf[p].end(), sendbuf+sdispl[p]);
743 std::vector<std::vector<T>>().swap(sbuf);
744 rbuf.resize(totrsize);
745 MPI_Alltoallv(sendbuf, ssizes, sdispl, Ttype,
746 rbuf.data(), rsizes, rdispl, Ttype, comm_);
747 pbuf.resize(P);
748 for (int p=0; p<P; p++)
749 pbuf[p] = rbuf.data() + rdispl[p];
750 }
751 }
752
768 MPIComm sub(int P0, int P, int stride=1) const {
769 if (is_null()) return MPIComm(MPI_COMM_NULL);
770 assert(P0 + P <= size());
771 MPIComm sub_comm;
772 std::vector<int> sub_ranks(P);
773 for (int i=0; i<P; i++)
774 sub_ranks[i] = P0 + i*stride;
775 MPI_Group group, sub_group;
776 MPI_Comm_group(comm_, &group); // get group from comm
777 MPI_Group_incl(group, P, sub_ranks.data(), &sub_group); // group ranks [P0,P0+P) into sub_group
778 MPI_Comm_create(comm_, sub_group, &sub_comm.comm_); // create new sub_comm
779 MPI_Group_free(&group);
780 MPI_Group_free(&sub_group);
781 return sub_comm;
782 }
783
793 // return MPI_COMM_SELF??? or MPI_COMM_NULL if not rank??
794 MPIComm sub_self(int p) const {
795 if (is_null()) return MPIComm(MPI_COMM_NULL);
796 MPIComm c0;
797 MPI_Group group, sub_group;
798 MPI_Comm_group(comm_, &group);
799 MPI_Group_incl(group, 1, &p, &sub_group);
800 MPI_Comm_create(comm_, sub_group, &c0.comm_);
801 MPI_Group_free(&group);
802 MPI_Group_free(&sub_group);
803 return c0;
804 }
805
809 static void control_start(const std::string& name) {
810 MPI_Pcontrol(1, name.c_str());
811 }
815 static void control_stop(const std::string& name) {
816 MPI_Pcontrol(-1, name.c_str());
817 }
818
819 static bool initialized() {
820 int flag;
821 MPI_Initialized(&flag);
822 return static_cast<bool>(flag);
823 }
824
825 private:
826 MPI_Comm comm_ = MPI_COMM_WORLD;
827
828 void duplicate(MPI_Comm c) {
829 if (c == MPI_COMM_NULL) comm_ = c;
830 else MPI_Comm_dup(c, &comm_);
831 }
832 };
833
834
842 inline int mpi_rank(MPI_Comm c=MPI_COMM_WORLD) {
843 assert(c != MPI_COMM_NULL);
844 int rank;
845 MPI_Comm_rank(c, &rank);
846 return rank;
847 }
848
856 inline int mpi_nprocs(MPI_Comm c=MPI_COMM_WORLD) {
857 assert(c != MPI_COMM_NULL);
858 int nprocs;
859 MPI_Comm_size(c, &nprocs);
860 return nprocs;
861 }
862
863} // end namespace strumpack
864
865#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
std::vector< T, A > all_to_all_v(std::vector< std::vector< T > > &sbuf) const
Definition: MPIWrapper.hpp:649
MPIComm sub(int P0, int P, int stride=1) const
Definition: MPIWrapper.hpp:768
bool is_root() const
Definition: MPIWrapper.hpp:293
static void control_stop(const std::string &name)
Definition: MPIWrapper.hpp:815
T all_reduce(T t, MPI_Op op) const
Definition: MPIWrapper.hpp:515
MPIComm & operator=(const MPIComm &c)
Definition: MPIWrapper.hpp:241
void reduce(T *t, int ssize, MPI_Op op, int dest=0) const
Definition: MPIWrapper.hpp:580
MPIComm()
Definition: MPIWrapper.hpp:200
void barrier() const
Definition: MPIWrapper.hpp:299
MPIComm(const MPIComm &c)
Definition: MPIWrapper.hpp:217
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
std::vector< T > recv(int src, int tag) const
Definition: MPIWrapper.hpp:455
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
MPIComm(MPIComm &&c) noexcept
Definition: MPIWrapper.hpp:225
int size() const
Definition: MPIWrapper.hpp:282
int rank() const
Definition: MPIWrapper.hpp:271
MPIComm sub_self(int p) const
Definition: MPIWrapper.hpp:794
void all_to_all_v(std::vector< std::vector< T > > &sbuf, std::vector< T, A > &rbuf, std::vector< T * > &pbuf) const
Definition: MPIWrapper.hpp:630
static void control_start(const std::string &name)
Definition: MPIWrapper.hpp:809
MPIComm(MPI_Comm c)
Definition: MPIWrapper.hpp:209
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:674
MPIRequest isend(const std::vector< T > &sbuf, int dest, int tag) const
Definition: MPIWrapper.hpp:375
MPIComm & operator=(MPIComm &&c) noexcept
Definition: MPIWrapper.hpp:252
void all_reduce(T *t, int ssize, MPI_Op op) const
Definition: MPIWrapper.hpp:555
Wrapper around an MPI_Request object.
Definition: MPIWrapper.hpp:124
MPIRequest(const MPIRequest &)=delete
void wait()
Definition: MPIWrapper.hpp:157
MPIRequest(MPIRequest &&)=default
MPIRequest & operator=(const MPIRequest &)=delete
MPIRequest()
Definition: MPIWrapper.hpp:129
MPIRequest & operator=(MPIRequest &&)=default
Definition: StrumpackOptions.hpp:43
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:842
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:856
MPI_Datatype mpi_type< unsigned long >()
Definition: MPIWrapper.hpp:71
MPI_Datatype mpi_type< char >()
Definition: MPIWrapper.hpp:62