Loading...
Searching...
No Matches
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
104 public:
109 req_ = std::unique_ptr<MPI_Request>(new MPI_Request());
110 }
111
116 MPIRequest(const MPIRequest&) = delete;
117
121 MPIRequest(MPIRequest&&) = default;
122
126 MPIRequest& operator=(const MPIRequest&) = delete;
127
132
136 void wait() { MPI_Wait(req_.get(), MPI_STATUS_IGNORE); }
137
138 private:
139 std::unique_ptr<MPI_Request> req_;
140 friend class MPIComm;
141 };
142
152 inline void wait_all(std::vector<MPIRequest>& reqs) {
153 for (auto& r : reqs) r.wait();
154 reqs.clear();
155 }
156
157 inline void wait_all(std::vector<MPI_Request>& reqs) {
158 MPI_Waitall(reqs.size(), reqs.data(), MPI_STATUSES_IGNORE);
159 }
160
173 class MPIComm {
174 public:
180
188 MPIComm(MPI_Comm c) { duplicate(c); }
189
196 MPIComm(const MPIComm& c) { *this = c; }
197
204 MPIComm(MPIComm&& c) noexcept { *this = std::move(c); }
205
210 virtual ~MPIComm() {
211 if (comm_ != MPI_COMM_NULL && comm_ != MPI_COMM_WORLD)
212 MPI_Comm_free(&comm_);
213 }
214
221 if (this != &c) duplicate(c.comm());
222 return *this;
223 }
224
231 MPIComm& operator=(MPIComm&& c) noexcept {
232 comm_ = c.comm_;
233 c.comm_ = MPI_COMM_NULL;
234 return *this;
235 }
236
240 MPI_Comm comm() const { return comm_; }
241
245 bool is_null() const { return comm_ == MPI_COMM_NULL; }
246
250 int rank() const {
251 assert(comm_ != MPI_COMM_NULL);
252 int r;
253 MPI_Comm_rank(comm_, &r);
254 return r;
255 }
256
261 int size() const {
262 assert(comm_ != MPI_COMM_NULL);
263 int nprocs;
264 MPI_Comm_size(comm_, &nprocs);
265 return nprocs;
266 }
267
272 bool is_root() const { return rank() == 0; }
273
278 void barrier() const { MPI_Barrier(comm_); }
279
280 template<typename T> void
281 broadcast(std::vector<T>& sbuf) const {
282 MPI_Bcast(sbuf.data(), sbuf.size(), mpi_type<T>(), 0, comm_);
283 }
284
285 template<typename T> void
286 broadcast_from(std::vector<T>& sbuf, int src) const {
287 MPI_Bcast(sbuf.data(), sbuf.size(), mpi_type<T>(), src, comm_);
288 }
289
290 template<typename T, std::size_t N> void
291 broadcast(std::array<T,N>& sbuf) const {
292 MPI_Bcast(sbuf.data(), sbuf.size(), mpi_type<T>(), 0, comm_);
293 }
294
295 template<typename T> void broadcast(T& data) const {
296 MPI_Bcast(&data, 1, mpi_type<T>(), 0, comm_);
297 }
298 template<typename T> void broadcast_from(T& data, int src) const {
299 MPI_Bcast(&data, 1, mpi_type<T>(), src, comm_);
300 }
301 template<typename T> void
302 broadcast(T* sbuf, std::size_t ssize) const {
303 MPI_Bcast(sbuf, ssize, mpi_type<T>(), 0, comm_);
304 }
305 template<typename T> void
306 broadcast_from(T* sbuf, std::size_t ssize, int src) const {
307 MPI_Bcast(sbuf, ssize, mpi_type<T>(), src, comm_);
308 }
309
310 template<typename T>
311 void all_gather(T* buf, std::size_t rsize) const {
312 MPI_Allgather
313 (MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
314 buf, rsize, mpi_type<T>(), comm_);
315 }
316 void all_gather(std::pair<long int,long int>* buf,
317 std::size_t rsize) const {
318 MPI_Datatype l_l_mpi_type;
319 MPI_Type_contiguous(2, mpi_type<long int>(), &l_l_mpi_type);
320 MPI_Type_commit(&l_l_mpi_type);
321 MPI_Allgather
322 (MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
323 buf, rsize, l_l_mpi_type, comm_);
324 MPI_Type_free(&l_l_mpi_type);
325 }
326 void all_gather(std::pair<long long int,long long int>* buf,
327 std::size_t rsize) const {
328 MPI_Datatype ll_ll_mpi_type;
329 MPI_Type_contiguous(2, mpi_type<long long int>(), &ll_ll_mpi_type);
330 MPI_Type_commit(&ll_ll_mpi_type);
331 MPI_Allgather
332 (MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
333 buf, rsize, ll_ll_mpi_type, comm_);
334 MPI_Type_free(&ll_ll_mpi_type);
335 }
336
337 template<typename T>
338 void all_gather_v(T* buf, const int* rcnts, const int* displs) const {
339 MPI_Allgatherv
340 (MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, buf, rcnts, displs,
341 mpi_type<T>(), comm_);
342 }
343
344 template<typename T>
345 void gather(T* sbuf, int ssize, int* rbuf, int rsize, int root) const {
346 MPI_Gather
347 (sbuf, ssize, mpi_type<T>(), rbuf,
348 rsize, mpi_type<T>(), root, comm_);
349 }
350
351 template<typename T>
352 void gather_v(T* sbuf, int scnts, T* rbuf, const int* rcnts,
353 const int* displs, int root) const {
354 MPI_Gatherv
355 (sbuf, scnts, mpi_type<T>(), rbuf, rcnts, displs,
356 mpi_type<T>(), root, comm_);
357 }
358
359
373 template<typename T>
374 MPIRequest isend(const std::vector<T>& sbuf, int dest, int tag) const {
375 MPIRequest req;
376 // const_cast is necessary for ancient openmpi version used on Travis
377 MPI_Isend(const_cast<T*>(sbuf.data()), sbuf.size(), mpi_type<T>(),
378 dest, tag, comm_, req.req_.get());
379 return req;
380 }
381
394 template<typename T>
395 void isend(const std::vector<T>& sbuf, int dest, int tag,
396 MPI_Request* req) const {
397 // const_cast is necessary for ancient openmpi version used on Travis
398 MPI_Isend(const_cast<T*>(sbuf.data()), sbuf.size(), mpi_type<T>(),
399 dest, tag, comm_, req);
400 }
401
402 template<typename T>
403 void isend(const T* sbuf, std::size_t ssize, int dest,
404 int tag, MPI_Request* req) const {
405 // const_cast is necessary for ancient openmpi version used on Travis
406 MPI_Isend(const_cast<T*>(sbuf), ssize, mpi_type<T>(),
407 dest, tag, comm_, req);
408 }
409 template<typename T>
410 void send(const T* sbuf, std::size_t ssize, int dest, int tag) const {
411 // const_cast is necessary for ancient openmpi version used on Travis
412 MPI_Send(const_cast<T*>(sbuf), ssize, mpi_type<T>(), dest, tag, comm_);
413 }
414
415 template<typename T>
416 void isend(const T& buf, int dest, int tag, MPI_Request* req) const {
417 // const_cast is necessary for ancient openmpi version used on Travis
418 MPI_Isend(const_cast<T*>(&buf), 1, mpi_type<T>(),
419 dest, tag, comm_, req);
420 }
421
435 template<typename T>
436 void send(const std::vector<T>& sbuf, int dest, int tag) const {
437 // const_cast is necessary for ancient openmpi version used on Travis
438 MPI_Send(const_cast<T*>(sbuf.data()), sbuf.size(),
439 mpi_type<T>(), dest, tag, comm_);
440 }
441
454 template<typename T> std::vector<T> recv(int src, int tag) const {
455 MPI_Status stat;
456 MPI_Probe(src, tag, comm_, &stat);
457 int msgsize;
458 MPI_Get_count(&stat, mpi_type<T>(), &msgsize);
459 //std::vector<T,NoInit<T>> rbuf(msgsize);
460 std::vector<T> rbuf(msgsize);
461 MPI_Recv(rbuf.data(), msgsize, mpi_type<T>(), src, tag,
462 comm_, MPI_STATUS_IGNORE);
463 return rbuf;
464 }
465
466 template<typename T>
467 std::pair<int,std::vector<T>> recv_any_src(int tag) const {
468 MPI_Status stat;
469 MPI_Probe(MPI_ANY_SOURCE, tag, comm_, &stat);
470 int msgsize;
471 MPI_Get_count(&stat, mpi_type<T>(), &msgsize);
472 std::vector<T> rbuf(msgsize);
473 MPI_Recv(rbuf.data(), msgsize, mpi_type<T>(), stat.MPI_SOURCE,
474 tag, comm_, MPI_STATUS_IGNORE);
475 return {stat.MPI_SOURCE, std::move(rbuf)};
476 }
477
478 template<typename T> T recv_one(int src, int tag) const {
479 T t;
480 MPI_Recv(&t, 1, mpi_type<T>(), src, tag, comm_, MPI_STATUS_IGNORE);
481 return t;
482 }
483
484 template<typename T>
485 void irecv(const T* rbuf, std::size_t rsize, int src,
486 int tag, MPI_Request* req) const {
487 // const_cast is necessary for ancient openmpi version used on Travis
488 MPI_Irecv(const_cast<T*>(rbuf), rsize, mpi_type<T>(),
489 src, tag, comm_, req);
490 }
491
492 template<typename T>
493 void recv(const T* rbuf, std::size_t rsize, int src, int tag) const {
494 // const_cast is necessary for ancient openmpi version used on Travis
495 MPI_Status stat;
496 MPI_Recv(const_cast<T*>(rbuf), rsize, mpi_type<T>(),
497 src, tag, comm_, &stat);
498 }
499
514 template<typename T> T all_reduce(T t, MPI_Op op) const {
515 MPI_Allreduce(MPI_IN_PLACE, &t, 1, mpi_type<T>(), op, comm_);
516 return t;
517 }
518
533 template<typename T> T reduce(T t, MPI_Op op) const {
534 MPI_Reduce(is_root() ? MPI_IN_PLACE : &t, &t, 1,
535 mpi_type<T>(), op, 0, comm_);
536 return t;
537 }
538
554 template<typename T> void all_reduce(T* t, int ssize, MPI_Op op) const {
555 MPI_Allreduce(MPI_IN_PLACE, t, ssize, mpi_type<T>(), op, comm_);
556 }
557
558 template<typename T> void all_reduce(std::vector<T>& t, MPI_Op op) const {
559 all_reduce(t.data(), t.size(), op);
560 }
561
578 template<typename T> void
579 reduce(T* t, int ssize, MPI_Op op, int dest=0) const {
580 MPI_Reduce(rank() == dest ? MPI_IN_PLACE : t, t, ssize,
581 mpi_type<T>(), op, dest, comm_);
582 }
583
584 template<typename T>
585 void all_to_all(const T* sbuf, int scnt, T* rbuf) const {
586 MPI_Alltoall
587 (sbuf, scnt, mpi_type<T>(), rbuf, scnt, mpi_type<T>(), comm_);
588 }
589
590 template<typename T, typename A=std::allocator<T>> std::vector<T,A>
591 all_to_allv(const T* sbuf, int* scnts, int* sdispls,
592 int* rcnts, int* rdispls) const {
593 std::size_t rsize = 0;
594 for (int p=0; p<size(); p++)
595 rsize += rcnts[p];
596 std::vector<T,A> rbuf(rsize);
597 MPI_Alltoallv
598 (sbuf, scnts, sdispls, mpi_type<T>(),
599 rbuf.data(), rcnts, rdispls, mpi_type<T>(), comm_);
600 return rbuf;
601 }
602
603 template<typename T> void
604 all_to_allv(const T* sbuf, int* scnts, int* sdispls,
605 T* rbuf, int* rcnts, int* rdispls) const {
606 MPI_Alltoallv
607 (sbuf, scnts, sdispls, mpi_type<T>(),
608 rbuf, rcnts, rdispls, mpi_type<T>(), comm_);
609 }
610
628 template<typename T, typename A=std::allocator<T>> void
629 all_to_all_v(std::vector<std::vector<T>>& sbuf, std::vector<T,A>& rbuf,
630 std::vector<T*>& pbuf) const {
631 all_to_all_v(sbuf, rbuf, pbuf, mpi_type<T>());
632 }
633
647 template<typename T, typename A=std::allocator<T>> std::vector<T,A>
648 all_to_all_v(std::vector<std::vector<T>>& sbuf) const {
649 std::vector<T,A> rbuf;
650 std::vector<T*> pbuf;
651 all_to_all_v(sbuf, rbuf, pbuf, mpi_type<T>());
652 return rbuf;
653 }
654
672 template<typename T, typename A=std::allocator<T>> void
673 all_to_all_v(std::vector<std::vector<T>>& sbuf, std::vector<T,A>& rbuf,
674 std::vector<T*>& pbuf, const MPI_Datatype Ttype) const {
675 assert(sbuf.size() == std::size_t(size()));
676 auto P = size();
677 std::unique_ptr<int[]> iwork(new int[4*P]);
678 auto ssizes = iwork.get();
679 auto rsizes = ssizes + P;
680 auto sdispl = ssizes + 2*P;
681 auto rdispl = ssizes + 3*P;
682 for (int p=0; p<P; p++) {
683 if (sbuf[p].size() >
684 static_cast<std::size_t>(std::numeric_limits<int>::max())) {
685 std::cerr << "# ERROR: 32bit integer overflow in all_to_all_v!!"
686 << std::endl;
687 MPI_Abort(comm_, 1);
688 }
689 ssizes[p] = sbuf[p].size();
690 }
691 MPI_Alltoall
692 (ssizes, 1, mpi_type<int>(), rsizes, 1, mpi_type<int>(), comm_);
693 std::size_t totssize = std::accumulate(ssizes, ssizes+P, std::size_t(0)),
694 totrsize = std::accumulate(rsizes, rsizes+P, std::size_t(0));
695#if 1
696 if (true) {
697 // Always implement the all_to_all_v with Irecv/Isend loops.
698 // We noticed (on NERSC Cori) that MPI_Alltoallv gave wrong
699 // results for large problems (using double complex), likely
700 // due to some overflow, even tho the totssize/totrsize was <
701 // MAX_INT. Also, using Irecv/Isend directly avoids to copies
702 // from the separate send buffers to the single send buffer.
703#else
704 if (totrsize >
705 static_cast<std::size_t>(std::numeric_limits<int>::max()) ||
706 totssize >
707 static_cast<std::size_t>(std::numeric_limits<int>::max())) {
708#endif
709 // This case will probably cause an overflow in the
710 // rdispl/sdispl elements. Here we do the all_to_all_v
711 // manually by just using Isend/Irecv. This might be slower
712 // than splitting into multiple calls to MPI_Alltoallv
713 // (although it avoids a copy from the sbuf).
714 rbuf.resize(totrsize);
715 std::unique_ptr<MPI_Request[]> reqs(new MPI_Request[2*P]);
716 std::size_t displ = 0;
717 pbuf.resize(P);
718 int r = rank();
719 for (int p=0; p<P; p++) {
720 auto dst = (r + p) % P;
721 pbuf[dst] = rbuf.data() + displ;
722 MPI_Irecv(pbuf[dst], rsizes[dst], Ttype, dst, 0, comm_, reqs.get()+dst);
723 displ += rsizes[dst];
724 }
725 for (int p=0; p<P; p++) {
726 auto dst = (r + p) % P;
727 MPI_Isend
728 (sbuf[dst].data(), ssizes[dst], Ttype, dst, 0, comm_, reqs.get()+P+dst);
729 }
730 MPI_Waitall(2*P, reqs.get(), MPI_STATUSES_IGNORE);
731 std::vector<std::vector<T>>().swap(sbuf);
732 } else {
733 std::unique_ptr<T[]> sendbuf_(new T[totssize]);
734 auto sendbuf = sendbuf_.get();
735 sdispl[0] = rdispl[0] = 0;
736 for (int p=1; p<P; p++) {
737 sdispl[p] = sdispl[p-1] + ssizes[p-1];
738 rdispl[p] = rdispl[p-1] + rsizes[p-1];
739 }
740 for (int p=0; p<P; p++)
741 std::copy(sbuf[p].begin(), sbuf[p].end(), sendbuf+sdispl[p]);
742 std::vector<std::vector<T>>().swap(sbuf);
743 rbuf.resize(totrsize);
744 MPI_Alltoallv(sendbuf, ssizes, sdispl, Ttype,
745 rbuf.data(), rsizes, rdispl, Ttype, comm_);
746 pbuf.resize(P);
747 for (int p=0; p<P; p++)
748 pbuf[p] = rbuf.data() + rdispl[p];
749 }
750 }
751
767 MPIComm sub(int P0, int P, int stride=1) const {
768 if (is_null()) return MPIComm(MPI_COMM_NULL);
769 assert(P0 + P <= size());
770 MPIComm sub_comm;
771 std::vector<int> sub_ranks(P);
772 for (int i=0; i<P; i++)
773 sub_ranks[i] = P0 + i*stride;
774 MPI_Group group, sub_group;
775 MPI_Comm_group(comm_, &group); // get group from comm
776 MPI_Group_incl(group, P, sub_ranks.data(), &sub_group); // group ranks [P0,P0+P) into sub_group
777 MPI_Comm_create(comm_, sub_group, &sub_comm.comm_); // create new sub_comm
778 MPI_Group_free(&group);
779 MPI_Group_free(&sub_group);
780 return sub_comm;
781 }
782
792 // return MPI_COMM_SELF??? or MPI_COMM_NULL if not rank??
793 MPIComm sub_self(int p) const {
794 if (is_null()) return MPIComm(MPI_COMM_NULL);
795 MPIComm c0;
796 MPI_Group group, sub_group;
797 MPI_Comm_group(comm_, &group);
798 MPI_Group_incl(group, 1, &p, &sub_group);
799 MPI_Comm_create(comm_, sub_group, &c0.comm_);
800 MPI_Group_free(&group);
801 MPI_Group_free(&sub_group);
802 return c0;
803 }
804
808 static void control_start(const std::string& name) {
809 MPI_Pcontrol(1, name.c_str());
810 }
814 static void control_stop(const std::string& name) {
815 MPI_Pcontrol(-1, name.c_str());
816 }
817
818 static bool initialized() {
819 int flag;
820 MPI_Initialized(&flag);
821 return static_cast<bool>(flag);
822 }
823
824 private:
825 MPI_Comm comm_ = MPI_COMM_WORLD;
826
827 void duplicate(MPI_Comm c) {
828 if (c == MPI_COMM_NULL) comm_ = c;
829 else MPI_Comm_dup(c, &comm_);
830 }
831 };
832
833
841 inline int mpi_rank(MPI_Comm c=MPI_COMM_WORLD) {
842 assert(c != MPI_COMM_NULL);
843 int rank;
844 MPI_Comm_rank(c, &rank);
845 return rank;
846 }
847
855 inline int mpi_nprocs(MPI_Comm c=MPI_COMM_WORLD) {
856 assert(c != MPI_COMM_NULL);
857 int nprocs;
858 MPI_Comm_size(c, &nprocs);
859 return nprocs;
860 }
861
862} // end namespace strumpack
863
864#endif // STRUMPACK_MPI_WRAPPER_HPP
Contains the definition of some useful (global) variables.
Wrapper class around an MPI_Comm object.
Definition MPIWrapper.hpp:173
virtual ~MPIComm()
Definition MPIWrapper.hpp:210
std::vector< T, A > all_to_all_v(std::vector< std::vector< T > > &sbuf) const
Definition MPIWrapper.hpp:648
MPIComm sub(int P0, int P, int stride=1) const
Definition MPIWrapper.hpp:767
bool is_root() const
Definition MPIWrapper.hpp:272
static void control_stop(const std::string &name)
Definition MPIWrapper.hpp:814
T all_reduce(T t, MPI_Op op) const
Definition MPIWrapper.hpp:514
MPIComm & operator=(const MPIComm &c)
Definition MPIWrapper.hpp:220
void reduce(T *t, int ssize, MPI_Op op, int dest=0) const
Definition MPIWrapper.hpp:579
MPIComm()
Definition MPIWrapper.hpp:179
void barrier() const
Definition MPIWrapper.hpp:278
MPIComm(const MPIComm &c)
Definition MPIWrapper.hpp:196
void send(const std::vector< T > &sbuf, int dest, int tag) const
Definition MPIWrapper.hpp:436
bool is_null() const
Definition MPIWrapper.hpp:245
MPI_Comm comm() const
Definition MPIWrapper.hpp:240
std::vector< T > recv(int src, int tag) const
Definition MPIWrapper.hpp:454
T reduce(T t, MPI_Op op) const
Definition MPIWrapper.hpp:533
void isend(const std::vector< T > &sbuf, int dest, int tag, MPI_Request *req) const
Definition MPIWrapper.hpp:395
MPIComm(MPIComm &&c) noexcept
Definition MPIWrapper.hpp:204
int size() const
Definition MPIWrapper.hpp:261
int rank() const
Definition MPIWrapper.hpp:250
MPIComm sub_self(int p) const
Definition MPIWrapper.hpp:793
void all_to_all_v(std::vector< std::vector< T > > &sbuf, std::vector< T, A > &rbuf, std::vector< T * > &pbuf) const
Definition MPIWrapper.hpp:629
static void control_start(const std::string &name)
Definition MPIWrapper.hpp:808
MPIComm(MPI_Comm c)
Definition MPIWrapper.hpp:188
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:673
MPIRequest isend(const std::vector< T > &sbuf, int dest, int tag) const
Definition MPIWrapper.hpp:374
MPIComm & operator=(MPIComm &&c) noexcept
Definition MPIWrapper.hpp:231
void all_reduce(T *t, int ssize, MPI_Op op) const
Definition MPIWrapper.hpp:554
Wrapper around an MPI_Request object.
Definition MPIWrapper.hpp:103
MPIRequest(const MPIRequest &)=delete
void wait()
Definition MPIWrapper.hpp:136
MPIRequest(MPIRequest &&)=default
MPIRequest & operator=(const MPIRequest &)=delete
MPIRequest()
Definition MPIWrapper.hpp:108
MPIRequest & operator=(MPIRequest &&)=default
Definition StrumpackOptions.hpp:44
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:152
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:841
MPI_Datatype mpi_type< long long int >()
Definition MPIWrapper.hpp:73
MPI_Datatype mpi_type< bool >()
Definition MPIWrapper.hpp:65
MPI_Datatype mpi_type< double >()
Definition MPIWrapper.hpp:77
int mpi_nprocs(MPI_Comm c=MPI_COMM_WORLD)
Definition MPIWrapper.hpp:855
MPI_Datatype mpi_type< unsigned long >()
Definition MPIWrapper.hpp:71
MPI_Datatype mpi_type< char >()
Definition MPIWrapper.hpp:62