MADNESS 0.10.1
safempi.h
Go to the documentation of this file.
1/*
2 This file is part of MADNESS.
3
4 Copyright (C) 2007,2010 Oak Ridge National Laboratory
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 For more information please contact:
21
22 Robert J. Harrison
23 Oak Ridge National Laboratory
24 One Bethel Valley Road
25 P.O. Box 2008, MS-6367
26
27 email: harrisonrj@ornl.gov
28 tel: 865-241-3937
29 fax: 865-572-0680
30
31 $Id$
32*/
33#ifndef MADNESS_WORLD_SAFEMPI_H__INCLUDED
34#define MADNESS_WORLD_SAFEMPI_H__INCLUDED
35
36/// \file safempi.h
37/// \brief Serializes calls to MPI in case it does not support THREAD_MULTIPLE
38
40
41#ifdef STUBOUTMPI
43#else
44
45//#ifdef SEEK_SET
46//#undef SEEK_SET
47//#endif
48//#ifdef SEEK_CUR
49//#undef SEEK_CUR
50//#endif
51//#ifdef SEEK_END
52//#undef SEEK_END
53//#endif
54
55#ifdef MADNESS_MPI_HEADER
56# include MADNESS_MPI_HEADER
57#else
58# include <mpi.h>
59#endif
60
61#endif
62
63
64#if MADNESS_MPI_THREAD_LEVEL == MPI_THREAD_SERIALIZED
65# define MADNESS_SERIALIZES_MPI
66#endif
67
68
69
72#include <iostream>
73#include <csignal>
74#include <cstdlib>
75#include <cstring>
76#include <memory>
77#include <sstream>
78
79#define MADNESS_MPI_TEST(condition) \
80 { \
81 int mpi_error_code = condition; \
82 if(mpi_error_code != MPI_SUCCESS) { \
83 char s[MPI_MAX_ERROR_STRING]; \
84 s[0] = '\0'; \
85 int len = 0; \
86 MPI_Error_string(mpi_error_code, s, &len); \
87 std::cout<< "MPI ERROR in " << __FUNCTION__ << " in " << __FILE__ << " at line " << __LINE__ << " code " << mpi_error_code << " err string " << s << "\n"; \
88 throw ::SafeMPI::Exception(mpi_error_code); \
89 } \
90 }
91
92namespace SafeMPI {
93
94 extern madness::SCALABLE_MUTEX_TYPE charon; // Inside safempi.cc
95#ifdef MADNESS_SERIALIZES_MPI
96#define SAFE_MPI_GLOBAL_MUTEX madness::ScopedMutex<madness::SCALABLE_MUTEX_TYPE> obolus(SafeMPI::charon);
97#else
98#define SAFE_MPI_GLOBAL_MUTEX
99#endif
100
101 /// tags in [1,999] ... allocated once by unique_reserved_tag
102 ///
103 /// tags in [1000,1023] ... statically assigned here
104 ///
105 /// tags in [1024,4095] ... allocated round-robin by unique_tag
106 ///
107 /// tags in [4096,8191] ... reserved for huge msg exchange by RMI
108 ///
109 /// tags in [8192,MPI::TAG_UB] ... not used/managed by madness
110
111 static const int RMI_TAG = 1023;
112 static const int MPIAR_TAG = 1001;
113 static const int DEFAULT_SEND_RECV_TAG = 1000;
114
115 // Forward declarations
116 class Intracomm;
117 extern Intracomm COMM_WORLD;
118 inline int Finalize();
119
120 /// Check MPI initialization status
121
122 /// \return \c true if MPI has been initialized, \c false otherwise.
123 inline bool Is_initialized() {
124 int initialized = 0;
125 MPI_Initialized(&initialized);
126 return (initialized != 0);
127 }
128
129 /// Check MPI finalization status
130
131 /// \return \c true if MPI has been finalized, \c false otherwise.
132 inline bool Is_finalized() {
133 int flag = 0;
134 MPI_Finalized(&flag);
135 return flag != 0;
136 }
137
138 namespace detail {
139 /// Initialize SafeMPI::COMM_WORLD
140 inline void init_comm_world();
141
142 inline void print_mpi_error(const int rc, const char* function,
143 const int line, const char* file)
144 {
145 int len = 0;
146 char error_string[MPI_MAX_ERROR_STRING];
147 MPI_Error_string(rc, error_string, &len);
148 std::cerr << "!!! MPI ERROR (" << rc << ") in " << function <<
149 " at " << file << "(" << line << "): " << error_string << "\n";
150 }
151
152 } // namespace detail
153
154 /// SafeMPI exception object
155
156 /// This exception is thrown whenever an MPI error occurs.
157 class Exception : public std::exception {
158 private:
161 public:
162
163 Exception(const int mpi_error) throw() {
164 int len = 0;
165 if(MPI_Error_string(mpi_error, mpi_error_string_, &len) != MPI_SUCCESS)
166 std::strncpy(mpi_error_string_, "UNKNOWN MPI ERROR!", MPI_MAX_ERROR_STRING);
167 }
168
169 Exception(const int mpi_error, const int nstatuses,
170 const int* indices,
171 MPI_Status* const statuses) noexcept {
172 try {
173 if (mpi_error == MPI_ERR_IN_STATUS) {
174 std::ostringstream oss;
175 for(auto s=0; s!=nstatuses; ++s) {
176 int len = 0;
177 auto status_error = statuses[s].MPI_ERROR;
178 if (status_error != MPI_SUCCESS) {
179 oss << "request " << indices[s] << ":";
180 if (MPI_Error_string(status_error, mpi_error_string_, &len) != MPI_SUCCESS)
181 oss << " unknown error!" << std::endl;
182 else
183 oss << mpi_error_string_ << std::endl;
184 }
185 }
186 mpi_statuses_error_string_ = oss.str();
187 }
188 }
189 catch (...) {}
190
191 int len = 0;
192 if(MPI_Error_string(mpi_error, mpi_error_string_, &len) != MPI_SUCCESS)
193 std::strncpy(mpi_error_string_, "UNKNOWN MPI ERROR!", MPI_MAX_ERROR_STRING);
194 }
195
196 Exception(const Exception& other) throw() {
197 std::strncpy(mpi_error_string_, other.mpi_error_string_, MPI_MAX_ERROR_STRING);
198 try {
199 mpi_statuses_error_string_ = other.mpi_statuses_error_string_;
200 } catch(...) { mpi_statuses_error_string_.clear(); }
201 }
202
205 try {
207 } catch(...) { mpi_statuses_error_string_.clear(); }
208 return *this;
209 }
210
211 virtual ~Exception() throw() { }
212
213 virtual const char* what() const throw() { return mpi_error_string_; }
214 bool can_elaborate() const noexcept {
215 return !mpi_statuses_error_string_.empty();
216 }
217 const char* elaborate() const noexcept {
218 return mpi_statuses_error_string_.c_str();
219 }
220
221 friend std::ostream& operator<<(std::ostream& os, const Exception& e) {
222 os << e.what();
223 if (e.can_elaborate()) {
224 os << e.elaborate();
225 }
226 return os;
227 }
228 }; // class Exception
229
230
231 class Status {
232 private:
234
235 public:
236 // Constructors
237 Status(void) : status_() { }
238 Status(const Status &other) : status_(other.status_) { }
239 Status(MPI_Status other) : status_(other) { }
240
241 // Assignment operators
242 Status& operator=(const Status &other) {
243 status_ = other.status_;
244 return *this;
245 }
246
248 status_ = other;
249 return *this;
250 }
251
252 // C/C++ cast and assignment
253 operator MPI_Status*() { return &status_; }
254
255 operator MPI_Status() const { return status_; }
256
257// bool Is_cancelled() const {
258// int flag = 0;
259// MADNESS_MPI_TEST(MPI_Test_cancelled(const_cast<MPI_Status*>(&status_), &flag));
260// return flag != 0;
261// }
262//
263// int Get_elements(const MPI_Datatype datatype) const {
264// int elements = 0;
265// MADNESS_MPI_TEST(MPI_Get_elements(const_cast<MPI_Status*>(&status_), datatype, &elements));
266// return elements;
267// }
268
269 int Get_count(const MPI_Datatype datatype) const {
270 int count = 0;
271 MADNESS_MPI_TEST(MPI_Get_count(const_cast<MPI_Status*>(&status_), datatype, &count));
272 return count;
273 }
274
275// void Set_cancelled(bool flag) {
276// MADNESS_MPI_TEST(MPI_Status_set_cancelled(&status_, flag));
277// }
278//
279// void Set_elements( const MPI_Datatype &v2, int v3 ) {
280// MADNESS_MPI_TEST(MPI_Status_set_elements(&status_, v2, v3 ));
281// }
282
283 int Get_source() const { return status_.MPI_SOURCE; }
284
285 int Get_tag() const { return status_.MPI_TAG; }
286
287 int Get_error() const { return status_.MPI_ERROR; }
288
290
291 void Set_tag(int tag) { status_.MPI_TAG = tag; }
292
294 }; // class Status
295
296 class Request {
297 // Note: This class was previously derived from MPI::Request, but this
298 // was changed with the removal of the MPI C++ bindings. Now this class
299 // only implements the minimum functionality required by MADNESS. Feel
300 // free to add more functionality as needed.
301
302 private:
304
305 public:
306
307 // Constructors
309 Request(MPI_Request other) : request_(other) { }
310 Request(const Request& other) : request_(other.request_) { }
311
312 // Assignment operators
313 Request& operator=(const Request &other) {
314 request_ = other.request_;
315 return *this;
316 }
317
319 request_ = other;
320 return *this;
321 }
322
323 // logical
324 bool operator==(const Request &other) { return (request_ == other.request_); }
325 bool operator!=(const Request &other) { return (request_ != other.request_); }
326
327 // C/C++ cast and assignment
328 operator MPI_Request*() { return &request_; }
329 operator MPI_Request() const { return request_; }
330
331 static bool Testany(int count, Request* requests, int& index, Status& status) {
332 MADNESS_ASSERT(requests != nullptr);
333 int flag;
334 std::unique_ptr<MPI_Request[]> mpi_requests(new MPI_Request[count]);
335
336 // Copy requests to an array that can be used by MPI
337 for(int i = 0; i < count; ++i)
338 mpi_requests[i] = requests[i].request_;
339 {
341 MADNESS_MPI_TEST(MPI_Testany(count, mpi_requests.get(), &index, &flag, status));
342 }
343 // Copy results from MPI back to the original array
344 for(int i = 0; i < count; ++i)
345 requests[i].request_ = mpi_requests[i];
346 return flag != 0;
347 }
348
349 static bool Testany(int count, Request* requests, int& index) {
350 MADNESS_ASSERT(requests != nullptr);
351 int flag;
352 std::unique_ptr<MPI_Request[]> mpi_requests(new MPI_Request[count]);
353
354 // Copy requests to an array that can be used by MPI
355 for(int i = 0; i < count; ++i)
356 mpi_requests[i] = requests[i].request_;
357 {
359 MADNESS_MPI_TEST(MPI_Testany(count, mpi_requests.get(), &index, &flag, MPI_STATUS_IGNORE));
360 }
361 // Copy results from MPI back to the original array
362 for(int i = 0; i < count; ++i)
363 requests[i] = mpi_requests[i];
364 return flag != 0;
365 }
366
367 static int Testsome(int incount, Request* requests, int* indices, Status* statuses) {
368 MADNESS_ASSERT(requests != nullptr);
369 MADNESS_ASSERT(indices != nullptr);
370 MADNESS_ASSERT(statuses != nullptr);
371
372 int outcount = 0;
373 std::unique_ptr<MPI_Request[]> mpi_requests(new MPI_Request[incount]);
374 std::unique_ptr<MPI_Status[]> mpi_statuses(new MPI_Status[incount]);
375 for(int i = 0; i < incount; ++i)
376 mpi_requests[i] = requests[i].request_;
377 {
379 { // print out the status vars for the failed requests
380 auto mpi_error_code =
381 MPI_Testsome(incount, mpi_requests.get(), &outcount,
382 indices, mpi_statuses.get());
383 if (mpi_error_code != MPI_SUCCESS) {
384 throw ::SafeMPI::Exception(mpi_error_code, outcount, indices, mpi_statuses.get());
385 }
386 }
387 }
388 for(int i = 0; i < incount; ++i) {
389 requests[i] = mpi_requests[i];
390 statuses[i] = mpi_statuses[i];
391 }
392 return outcount;
393 }
394
395 static int Testsome(int incount, Request* requests, int* indices) {
396 int outcount = 0;
397 std::unique_ptr<MPI_Request[]> mpi_requests(new MPI_Request[incount]);
398 for(int i = 0; i < incount; ++i)
399 mpi_requests[i] = requests[i].request_;
400 {
402 MADNESS_MPI_TEST( MPI_Testsome( incount, mpi_requests.get(), &outcount, indices, MPI_STATUSES_IGNORE));
403 }
404 for(int i = 0; i < incount; ++i)
405 requests[i] = mpi_requests[i];
406 return outcount;
407 }
408
409
411 int flag;
413 return flag != 0;
414 }
415
420
422 int flag;
424 return flag != 0;
425 }
426
427 bool Test() {
429 return Test_got_lock_already();
430 }
431 }; // class Request
432
433 /// Wrapper around MPI_Group. Has a shallow copy constructor. Usually deep copy is not needed, but can be created
434 /// via Group::Incl().
435 class Group {
436 public:
437 Group Incl(int n, const int* ranks) const {
438 // MPI <3 interface lacks explicit const sanitation
439 Group result(std::shared_ptr<Impl>(new Impl(*pimpl, n, const_cast<int*>(ranks))));
440 return result;
441 }
442
443 void Translate_ranks(int nproc, const int* ranks1, const Group& grp2, int* ranks2) const {
444 // MPI <3 interface lacks explicit const sanitation
447 const_cast<int*>(ranks1), grp2.pimpl->group, ranks2));
448 }
449
450 MPI_Group group() const {
452 return pimpl->group;
453 }
454
455 Group(const Group& other) : pimpl(other.pimpl) { }
456
457 private:
458
459 struct Impl {
461
464 }
465
466 Impl(const Impl& other, int n, const int* ranks) {
467 // MPI <3 interface lacks explicit const sanitation
469 const_cast<int*>(ranks), & group));
470 }
471
473 if(Is_initialized()) {
474 const int mpi_error_code = MPI_Group_free(&group);
475 if(mpi_error_code != MPI_SUCCESS)
477 "SafeMPI::Group::Impl::~Impl()", __LINE__, __FILE__);
478 }
479 }
480
481 }; // struct Impl
482
483 friend class Intracomm;
484
485 Group() : pimpl() { }
486
487 // only Intracomm will use this
488 Group(MPI_Comm comm) : pimpl(new Impl(comm)) { }
489
490 // only myself will use this
491 Group(const std::shared_ptr<Impl>& p) : pimpl(p) { }
492
493 std::shared_ptr<Impl> pimpl;
494 }; // class Group
495
496 /// Wrapper around MPI_Comm. Has a shallow copy constructor; use Create(Get_group()) for deep copy
497 class Intracomm {
498
499 static bool Comm_compare(const MPI_Comm& comm1, const MPI_Comm& comm2) {
500 int compare_result;
501 const int result = MPI_Comm_compare(comm1, comm2, &compare_result);
502 return ((result == MPI_SUCCESS) && (compare_result == MPI_IDENT));
503 }
504
505 struct Impl {
507 int me;
509 bool owner;
510
511 int utag; // Only used by main thread so no volatile or mutex needed
512 int urtag;// Ditto
513
514 Impl(const MPI_Comm& c, int m, int n, bool o) :
515 comm(c), me(m), numproc(n), owner(o), utag(1024), urtag(1)
517
523
524 /// Returns a unique tag for temporary use (1023<tag<=4095)
525
526 /// These tags are intended for one time use to avoid tag
527 /// collisions with other messages around the same time period.
528 /// It simply increments/wraps a counter and returns the next
529 /// legal value.
530 ///
531 /// So that send and receiver agree on the tag all processes
532 /// need to call this routine in the same sequence.
534 // RJH removed mutex since ordering requirement across processes means
535 // there can never be any thread contention.
536 // Cannot use MPI mutex for anything else!
537 // It will preprocess to nothing for MPI_THREAD_MULTIPLE!
538 //madness::ScopedMutex<madness::SCALABLE_MUTEX_TYPE> obolus(SafeMPI::charon);
539 int result = utag++;
540 if (utag >= 4095) utag = 1024;
541 return result;
542 }
543
544 /// \return the period of repeat of unique tags produces by unique_tag()
545 static int unique_tag_period() {
546 const auto min_tag_value = 1024;
547 const auto max_tag_value = 4094;
548 return max_tag_value - min_tag_value + 1;
549 }
550
551 /// Returns a unique tag reserved for long-term use (0<tag<1000)
552
553 /// Get a tag from this routine for long-term/repeated use.
554 ///
555 /// Tags in [1000,1023] are statically assigned.
557 // RJH removed mutex since ordering requirement across processes means
558 // Cannot use MPI mutex for anything else!
559 // It will preprocess to nothing for MPI_THREAD_MULTIPLE!
560 // madness::ScopedMutex<madness::SCALABLE_MUTEX_TYPE> obolus(SafeMPI::charon);
561 int result = urtag++;
562 if (result >= 1000) MADNESS_EXCEPTION( "too many reserved tags in use" , result );
563 return result;
564 }
565
566 };
567 std::shared_ptr<Impl> pimpl;
568
570 friend int Finalize();
571
572 // For internal use only. Do not try to call this constructor. It is
573 // only used to construct Intarcomm in Create().
574 Intracomm(const std::shared_ptr<Impl>& i) : pimpl(i) { }
575
576 // Not allowed
578
579 // makes an uninitialized ptr
580 Intracomm() : pimpl(nullptr) {}
581
582 public:
583 struct WorldInitObject;
584
585 // For internal use only. Do not try to call this constructor. It is
586 // only used to construct COMM_WORLD.
587 Intracomm(const WorldInitObject&);
588
589 explicit Intracomm(const MPI_Comm& comm, bool take_ownership_of_comm = true) :
590 pimpl()
591 {
593 int rank = -1, size = -1;
594 MADNESS_MPI_TEST(MPI_Comm_rank(comm, &rank));
595 MADNESS_MPI_TEST(MPI_Comm_size(comm, &size));
596 take_ownership_of_comm =
597 take_ownership_of_comm && (! Comm_compare(comm, MPI_COMM_WORLD));
598 pimpl.reset(new Impl(comm, rank, size, take_ownership_of_comm));
599 }
600
601 Intracomm(const Intracomm& other) : pimpl(other.pimpl) { }
602
604
605 /**
606 * This collective operation creates a new \c Intracomm from an
607 * \c Intracomm::Group object. Must be called by all processes that
608 * belong to this communicator, but not all must use the same \c group .
609 * Thus this \c Intracomm can be partitioned into several \c Intracomm
610 * objects with one call.
611 *
612 * @param group Intracomm::Group describing the Intracomm object to be
613 * created (\c Intracomm::Get_group() and \c Intracomm::Group::Incl() )
614 * @return a new Intracomm object
615 */
616 Intracomm Create(Group group) const {
619 MPI_Comm group_comm;
620 MADNESS_MPI_TEST(MPI_Comm_create(pimpl->comm, group.group(), &group_comm));
621 int me; MADNESS_MPI_TEST(MPI_Comm_rank(group_comm, &me));
622 int nproc; MADNESS_MPI_TEST(MPI_Comm_size(group_comm, &nproc));
623 return Intracomm(std::shared_ptr<Impl>(new Impl(group_comm, me, nproc, true)));
624 }
625
626 static const int UNDEFINED_COLOR = MPI_UNDEFINED;
627 /**
628 * This collective operation creates a new \c Intracomm using
629 * the MPI_Comm_split. Must be called by all processes that
630 * belong to this communicator. Each caller must provide Color of the new Intracomm
631 * and Key (this controls the rank within the new Intracomm;
632 * ties are broken by the rank in this Intracomm).
633 *
634 * @param Color Specifies the new Intracomm that the calling process is to be assigned to.
635 * The value of color must be non-negative. If Color=UNDEFINED_COLOR then
636 * an uninitialized Intracomm object will be produced.
637 * @param Key The relative rank of the calling process in the group of the new Intracomm.
638 * If omitted, each communicator's ranks will be determined by
639 * the rank in the host communicator.
640 * @return a new Intracomm object
641 */
642 Intracomm Split(int Color, int Key = 0) const {
645 MPI_Comm group_comm;
646 MADNESS_MPI_TEST(MPI_Comm_split(pimpl->comm, Color, Key, &group_comm));
647 if (group_comm != MPI_COMM_NULL) {
648 int me; MADNESS_MPI_TEST(MPI_Comm_rank(group_comm, &me));
649 int nproc; MADNESS_MPI_TEST(MPI_Comm_size(group_comm, &nproc));
650 return Intracomm(std::shared_ptr<Impl>(new Impl(group_comm, me, nproc, true)));
651 }
652 else
653 return Intracomm();
654 }
655
658 /**
659 * This collective operation creates a new \c Intracomm using
660 * the MPI_Comm_split_type. Must be called by all processes that
661 * belong to this communicator. Each caller must provide the split type
662 * and Key (this controls the rank within the new Intracomm;
663 * ties are broken by the rank in this Intracomm).
664 *
665 * @param Type Controls how this Intracomm will be split.
666 * The value can only be UNDEFINED_SPLIT_TYPE or SHARED_SPLIT_TYPE.
667 * If Type=UNDEFINED_SPLIT_TYPE then
668 * an uninitialized Intracomm object will be produced.
669 * @param Key The relative rank of the calling process in the group of the new Intracomm.
670 * If omitted, each communicator's ranks will be determined by
671 * the rank in the host communicator.
672 * @return a new Intracomm object
673 */
674 Intracomm Split_type(int Type, int Key = 0) const {
677 MPI_Comm group_comm;
678 MPI_Info info;
679 MPI_Info_create(&info);
680 MADNESS_MPI_TEST(MPI_Comm_split_type(pimpl->comm, Type, Key, info, &group_comm));
681 MPI_Info_free(&info);
682 if (group_comm != MPI_COMM_NULL) {
683 int me; MADNESS_MPI_TEST(MPI_Comm_rank(group_comm, &me));
684 int nproc; MADNESS_MPI_TEST(MPI_Comm_size(group_comm, &nproc));
685 return Intracomm(std::shared_ptr<Impl>(new Impl(group_comm, me, nproc, true)));
686 }
687 else
688 return Intracomm();
689 }
690
691 /**
692 * Clones this Intracomm object
693 *
694 * @return a (deep) copy of this Intracomm object
695 */
696 Intracomm Clone() const {
697 return Create(this->Get_group());
698 }
699
700 bool operator==(const Intracomm& other) const {
701 return (pimpl == other.pimpl) || ((pimpl && other.pimpl) &&
702 Comm_compare(pimpl->comm, other.pimpl->comm));
703 }
704
705 /**
706 * This local operation returns the Intracomm::Group object corresponding to this intracommunicator
707 * @return the Intracomm::Group object corresponding to this intracommunicator
708 */
709 Group Get_group() const {
712 Group group(pimpl->comm);
713 return group;
714 }
715
718 return pimpl->comm;
719 }
720
721 int Get_rank() const {
723 return pimpl->me;
724 }
725
726 int Get_size() const {
728 return pimpl->numproc;
729 }
730
731 Request Isend(const void* buf, const int count, const MPI_Datatype datatype, const int dest, const int tag) const {
734 Request request;
735 MADNESS_MPI_TEST(MPI_Isend(const_cast<void*>(buf), count, datatype, dest,tag, pimpl->comm, request));
736 return request;
737 }
738
739 Request Issend(const void* buf, const int count, const MPI_Datatype datatype, const int dest, const int tag) const {
742 Request request;
743 MADNESS_MPI_TEST(MPI_Issend(const_cast<void*>(buf), count, datatype, dest,tag, pimpl->comm, request));
744 return request;
745 }
746
747 Request Irecv(void* buf, const int count, const MPI_Datatype datatype, const int src, const int tag) const {
750 Request request;
751 MADNESS_MPI_TEST(MPI_Irecv(buf, count, datatype, src, tag, pimpl->comm, request));
752 return request;
753 }
754
755 void Send(const void* buf, const int count, const MPI_Datatype datatype, int dest, int tag) const {
758 MADNESS_MPI_TEST(MPI_Ssend(const_cast<void*>(buf), count, datatype, dest, tag, pimpl->comm));
759 }
760
761#ifdef MADNESS_USE_BSEND_ACKS
762 void Bsend(const void* buf, size_t count, const MPI_Datatype datatype, int dest, int tag) const {
765 if (count>10 || datatype!=MPI_BYTE) MADNESS_EXCEPTION("Bsend: this protocol is only for 1-byte acks", count );
766 MADNESS_MPI_TEST(MPI_Bsend(const_cast<void*>(buf), count, datatype, dest, tag, pimpl->comm));
767 }
768#endif // MADNESS_USE_BSEND_ACKS
769
770 void Recv(void* buf, const int count, const MPI_Datatype datatype, const int source, const int tag, MPI_Status& status) const {
773 MADNESS_MPI_TEST(MPI_Recv(buf, count, datatype, source, tag, pimpl->comm, &status));
774 }
775
776 void Recv(void* buf, const int count, const MPI_Datatype datatype, const int source, const int tag) const {
779 MADNESS_MPI_TEST(MPI_Recv(buf, count, datatype, source, tag, pimpl->comm, MPI_STATUS_IGNORE));
780 }
781
782 void Bcast(void* buf, size_t count, const MPI_Datatype datatype, const int root) const {
785 MADNESS_MPI_TEST(MPI_Bcast(buf, count, datatype, root, pimpl->comm));
786 }
787
788 void Reduce(const void* sendbuf, void* recvbuf, const int count, const MPI_Datatype datatype, const MPI_Op op, const int root) const {
791 MADNESS_MPI_TEST(MPI_Reduce(const_cast<void*>(sendbuf), recvbuf, count, datatype, op, root, pimpl->comm));
792 }
793
794 void Allreduce(const void* sendbuf, void* recvbuf, const int count, const MPI_Datatype datatype, const MPI_Op op) const {
797 MADNESS_MPI_TEST(MPI_Allreduce(const_cast<void*>(sendbuf), recvbuf, count, datatype, op, pimpl->comm));
798 }
799 bool Get_attr(int key, void* value) const {
801 int flag = 0;
803 MADNESS_MPI_TEST(MPI_Comm_get_attr(pimpl->comm, key, value, &flag));
804 return flag != 0;
805 }
806
807 void Abort(int code=1) const {
808 // if SIGABRT has a handler, call std::abort to allow it be caught,
809 // else call MPI_Abort which does not seem to call abort at all,
810 // instead sends SIGTERM followed by SIGKILL
811 // if have a custom signal handler for SIGABRT (i.e. we are running under a
812 // debugger) then call abort()
813 struct sigaction sa;
814 auto rc = sigaction(SIGABRT, NULL, &sa);
815 if (rc == 0 && sa.sa_handler != SIG_DFL) {
816 std::abort();
817 } else {
818 MPI_Abort(pimpl->comm, code);
819 }
820 }
821
827
828 /// Returns a unique tag for temporary use (1023<tag<4095)
829
830 /// These tags are intended for one time use to avoid tag
831 /// collisions with other messages around the same time period.
832 /// It simply increments/wraps a counter and returns the next
833 /// legal value.
834 ///
835 /// So that send and receiver agree on the tag all processes
836 /// need to call this routine in the same sequence.
839 return pimpl->unique_tag();
840 }
841
842 /// \return the period of repeat of unique tags produces by unique_tag()
843 static int unique_tag_period() {
845 }
846
847 /// Returns a unique tag reserved for long-term use (0<tag<1000)
848
849 /// Get a tag from this routine for long-term/repeated use.
850 ///
851 /// Tags in [1000,1023] are statically assigned.
854 return pimpl->unique_reserved_tag();
855 }
856
857 /// Construct info about a binary tree with given root
858
859 /// Constructs a binary tree spanning the communicator with
860 /// process root as the root of the tree. Returns the logical
861 /// parent and children in the tree of the calling process. If
862 /// there is no parent/child the value -1 will be set.
863 void binary_tree_info(int root, int& parent, int& child0, int& child1);
864
865 }; // class Intracomm
866
867 namespace detail {
868
869 /// Initialize SafeMPI::COMM_WORLD
875
876 } // namespace detail
877
878
879 /// Analogous to MPI_Init_thread
880
881 /// \param argc the number of arguments in argv
882 /// \param argv the vector of command-line arguments
883 /// \param requested the desired thread level
884 /// \return provided thread level
885 inline int Init_thread(int & argc, char **& argv, int requested) {
886 int provided = 0;
887 MADNESS_MPI_TEST(MPI_Init_thread(&argc, &argv, requested, &provided));
889 return provided;
890 }
891
892 /// Analogous to MPI_Init_thread
893
894 /// \param requested the desired thread level
895 /// \return provided thread level
896 inline int Init_thread(int requested) {
897 int argc = 0;
898 char** argv = nullptr;
899 return SafeMPI::Init_thread(argc, argv, requested);
900 }
901
902 /// Analogous to MPI_Init
903
904 /// \param argc The number of arguments in argv
905 /// \param argv The vector of command-line arguments
906 inline void Init(int &argc, char **&argv) {
907 MADNESS_MPI_TEST(MPI_Init(&argc, &argv));
909 }
910
911 /// Analogous to MPI_Init
912 inline void Init() {
913 int argc = 0;
914 char** argv = nullptr;
915 SafeMPI::Init(argc,argv);
916 }
917
918 /// Analogous to MPI_Finalize
919
920 /// This returns status rather than throw an
921 /// exception upon failure because this is a "destructor", and throwing from
922 /// destructors is evil.
923 /// \return 0 if successful, nonzero otherwise (see MPI_Finalize() for the
924 /// return codes).
925 inline int Finalize() {
927 const int result = MPI_Finalize();
928 return result;
929 }
930
931 /// Analogous to MPI_Query_thread
932
933 /// \return the MPI thread level provided by SafeMPI::Init_thread()
934 inline int Query_thread() {
935 int provided;
937 return provided;
938 }
939
940 /// Wall time
941
942 /// \return The current wall time
943 inline double Wtime() { return MPI_Wtime(); }
944
945 /// Set buffer for \c Bsend .
946
947 /// \param buffer The buffer to be used by Bsend
948 /// \param size The size of the buffer in Bytes
949 inline void Attach_buffer(void* buffer, int size) {
950 MADNESS_MPI_TEST(MPI_Buffer_attach(buffer, size));
951 }
952
953 /// Unset the \c Bsend buffer.
954
955 /// \param[out] buffer The buffer that was used by Bsend
956 inline int Detach_buffer(void *&buffer) {
957 int size = 0;
958 MPI_Buffer_detach(&buffer, &size);
959 return size;
960 }
961
962 /// Analogous to MPI_Op_create
963 inline MPI_Op Op_create(MPI_User_function *user_fn, int commute) {
964 MPI_Op result;
965 MADNESS_MPI_TEST(MPI_Op_create(user_fn, commute, &result));
966 return result;
967 }
968
969 /// Analogous to MPI_Op_free
970 inline void Op_free(MPI_Op op) {
972 }
973
974} // namespace SafeMPI
975
976#endif // MADNESS_WORLD_SAFEMPI_H__INCLUDED
SafeMPI exception object.
Definition safempi.h:157
std::string mpi_statuses_error_string_
Definition safempi.h:160
bool can_elaborate() const noexcept
Definition safempi.h:214
Exception(const int mpi_error)
Definition safempi.h:163
char mpi_error_string_[MPI_MAX_ERROR_STRING]
Definition safempi.h:159
Exception & operator=(const Exception &other)
Definition safempi.h:203
friend std::ostream & operator<<(std::ostream &os, const Exception &e)
Definition safempi.h:221
virtual const char * what() const
Definition safempi.h:213
Exception(const int mpi_error, const int nstatuses, const int *indices, MPI_Status *const statuses) noexcept
Definition safempi.h:169
virtual ~Exception()
Definition safempi.h:211
const char * elaborate() const noexcept
Definition safempi.h:217
Exception(const Exception &other)
Definition safempi.h:196
Definition safempi.h:435
Group(const std::shared_ptr< Impl > &p)
Definition safempi.h:491
Group Incl(int n, const int *ranks) const
Definition safempi.h:437
MPI_Group group() const
Definition safempi.h:450
std::shared_ptr< Impl > pimpl
Definition safempi.h:493
Group(MPI_Comm comm)
Definition safempi.h:488
void Translate_ranks(int nproc, const int *ranks1, const Group &grp2, int *ranks2) const
Definition safempi.h:443
Group(const Group &other)
Definition safempi.h:455
Group()
Definition safempi.h:485
Wrapper around MPI_Comm. Has a shallow copy constructor; use Create(Get_group()) for deep copy.
Definition safempi.h:497
Intracomm(const std::shared_ptr< Impl > &i)
Definition safempi.h:574
Intracomm Clone() const
Definition safempi.h:696
void Allreduce(const void *sendbuf, void *recvbuf, const int count, const MPI_Datatype datatype, const MPI_Op op) const
Definition safempi.h:794
static bool Comm_compare(const MPI_Comm &comm1, const MPI_Comm &comm2)
Definition safempi.h:499
bool Get_attr(int key, void *value) const
Definition safempi.h:799
static const int SHARED_SPLIT_TYPE
Definition safempi.h:657
Intracomm Create(Group group) const
Definition safempi.h:616
Request Irecv(void *buf, const int count, const MPI_Datatype datatype, const int src, const int tag) const
Definition safempi.h:747
void Bcast(void *buf, size_t count, const MPI_Datatype datatype, const int root) const
Definition safempi.h:782
MPI_Comm & Get_mpi_comm() const
Definition safempi.h:716
void Reduce(const void *sendbuf, void *recvbuf, const int count, const MPI_Datatype datatype, const MPI_Op op, const int root) const
Definition safempi.h:788
Request Isend(const void *buf, const int count, const MPI_Datatype datatype, const int dest, const int tag) const
Definition safempi.h:731
friend int Finalize()
Analogous to MPI_Finalize.
Definition safempi.h:925
void binary_tree_info(int root, int &parent, int &child0, int &child1)
Construct info about a binary tree with given root.
Definition safempi.cc:39
Intracomm & operator=(const Intracomm &other)
Intracomm Split_type(int Type, int Key=0) const
Definition safempi.h:674
int Get_rank() const
Definition safempi.h:721
static int unique_tag_period()
Definition safempi.h:843
void Abort(int code=1) const
Definition safempi.h:807
static const int UNDEFINED_SPLIT_TYPE
Definition safempi.h:656
Intracomm(const MPI_Comm &comm, bool take_ownership_of_comm=true)
Definition safempi.h:589
int unique_tag()
Returns a unique tag for temporary use (1023<tag<4095)
Definition safempi.h:837
bool operator==(const Intracomm &other) const
Definition safempi.h:700
void Barrier() const
Definition safempi.h:822
std::shared_ptr< Impl > pimpl
Definition safempi.h:567
Group Get_group() const
Definition safempi.h:709
void Send(const void *buf, const int count, const MPI_Datatype datatype, int dest, int tag) const
Definition safempi.h:755
Intracomm Split(int Color, int Key=0) const
Definition safempi.h:642
int unique_reserved_tag()
Returns a unique tag reserved for long-term use (0<tag<1000)
Definition safempi.h:852
void Recv(void *buf, const int count, const MPI_Datatype datatype, const int source, const int tag) const
Definition safempi.h:776
~Intracomm()
Definition safempi.h:603
void Recv(void *buf, const int count, const MPI_Datatype datatype, const int source, const int tag, MPI_Status &status) const
Definition safempi.h:770
Intracomm(const Intracomm &other)
Definition safempi.h:601
int Get_size() const
Definition safempi.h:726
Intracomm()
Definition safempi.h:580
static const int UNDEFINED_COLOR
Definition safempi.h:626
Request Issend(const void *buf, const int count, const MPI_Datatype datatype, const int dest, const int tag) const
Definition safempi.h:739
Definition safempi.h:296
bool operator!=(const Request &other)
Definition safempi.h:325
MPI_Request request_
Definition safempi.h:303
bool Test(MPI_Status &status)
Definition safempi.h:416
Request & operator=(const MPI_Request &other)
Definition safempi.h:318
bool Test_got_lock_already()
Definition safempi.h:421
static bool Testany(int count, Request *requests, int &index)
Definition safempi.h:349
static int Testsome(int incount, Request *requests, int *indices)
Definition safempi.h:395
Request()
Definition safempi.h:308
Request(MPI_Request other)
Definition safempi.h:309
static int Testsome(int incount, Request *requests, int *indices, Status *statuses)
Definition safempi.h:367
bool Test_got_lock_already(MPI_Status &status)
Definition safempi.h:410
static bool Testany(int count, Request *requests, int &index, Status &status)
Definition safempi.h:331
Request & operator=(const Request &other)
Definition safempi.h:313
bool operator==(const Request &other)
Definition safempi.h:324
Request(const Request &other)
Definition safempi.h:310
bool Test()
Definition safempi.h:427
Definition safempi.h:231
int Get_count(const MPI_Datatype datatype) const
Definition safempi.h:269
Status & operator=(const MPI_Status other)
Definition safempi.h:247
int Get_error() const
Definition safempi.h:287
Status & operator=(const Status &other)
Definition safempi.h:242
void Set_tag(int tag)
Definition safempi.h:291
Status(const Status &other)
Definition safempi.h:238
MPI_Status status_
Definition safempi.h:233
int Get_tag() const
Definition safempi.h:285
Status(MPI_Status other)
Definition safempi.h:239
int Get_source() const
Definition safempi.h:283
Status(void)
Definition safempi.h:237
void Set_source(int source)
Definition safempi.h:289
void Set_error(int error)
Definition safempi.h:293
Mutex using pthread mutex operations.
Definition worldmutex.h:131
char * p(char *buf, const char *name, int k, int initial_level, double thresh, int order)
Definition derivatives.cc:72
static double function(const coord_3d &r)
Normalized gaussian.
Definition functionio.cc:100
Tensor< double > op(const Tensor< double > &x)
Definition kain.cc:508
Macros and tools pertaining to the configuration of MADNESS.
#define MADNESS_EXCEPTION(msg, value)
Macro for throwing a MADNESS exception.
Definition madness_exception.h:119
#define MADNESS_ASSERT(condition)
Assert a condition that should be free of side-effects since in release builds this might be a no-op.
Definition madness_exception.h:134
void init_comm_world()
Initialize SafeMPI::COMM_WORLD.
Definition safempi.h:870
void print_mpi_error(const int rc, const char *function, const int line, const char *file)
Definition safempi.h:142
Definition safempi.cc:35
Intracomm COMM_WORLD
Definition safempi.cc:67
void Init()
Analogous to MPI_Init.
Definition safempi.h:912
static const int MPIAR_TAG
Definition safempi.h:112
int Init_thread(int &argc, char **&argv, int requested)
Analogous to MPI_Init_thread.
Definition safempi.h:885
void Op_free(MPI_Op op)
Analogous to MPI_Op_free.
Definition safempi.h:970
void Attach_buffer(void *buffer, int size)
Set buffer for Bsend .
Definition safempi.h:949
madness::SCALABLE_MUTEX_TYPE charon
Definition safempi.cc:37
int Query_thread()
Analogous to MPI_Query_thread.
Definition safempi.h:934
int Finalize()
Analogous to MPI_Finalize.
Definition safempi.h:925
double Wtime()
Wall time.
Definition safempi.h:943
bool Is_initialized()
Check MPI initialization status.
Definition safempi.h:123
static const int DEFAULT_SEND_RECV_TAG
Definition safempi.h:113
static const int RMI_TAG
Definition safempi.h:111
int Detach_buffer(void *&buffer)
Unset the Bsend buffer.
Definition safempi.h:956
bool Is_finalized()
Check MPI finalization status.
Definition safempi.h:132
MPI_Op Op_create(MPI_User_function *user_fn, int commute)
Analogous to MPI_Op_create.
Definition safempi.h:963
Definition potentialmanager.cc:41
void error(const char *msg, int code)
Definition oldtest.cc:57
static const double c
Definition relops.cc:10
static const double m
Definition relops.cc:9
#define MADNESS_MPI_TEST(condition)
Definition safempi.h:79
#define SAFE_MPI_GLOBAL_MUTEX
Definition safempi.h:96
Definition test_dc.cc:47
Definition stubmpi.h:13
int MPI_SOURCE
Definition stubmpi.h:16
int MPI_TAG
Definition stubmpi.h:17
int MPI_ERROR
Definition stubmpi.h:18
Definition safempi.h:459
Impl(MPI_Comm comm)
Definition safempi.h:462
MPI_Group group
Definition safempi.h:460
~Impl()
Definition safempi.h:472
Impl(const Impl &other, int n, const int *ranks)
Definition safempi.h:466
Definition safempi.h:505
int numproc
Definition safempi.h:508
int urtag
Definition safempi.h:512
int unique_reserved_tag()
Returns a unique tag reserved for long-term use (0<tag<1000)
Definition safempi.h:556
bool owner
Definition safempi.h:509
static int unique_tag_period()
Definition safempi.h:545
int me
Definition safempi.h:507
int utag
Definition safempi.h:511
MPI_Comm comm
Definition safempi.h:506
int unique_tag()
Returns a unique tag for temporary use (1023<tag<=4095)
Definition safempi.h:533
Impl(const MPI_Comm &c, int m, int n, bool o)
Definition safempi.h:514
~Impl()
Definition safempi.h:518
#define MPI_SUCCESS
Definition stubmpi.h:36
int MPI_Op_free(MPI_Op *op)
Definition stubmpi.h:326
int MPI_Ssend(void *, int, MPI_Datatype, int, int, MPI_Comm)
Definition stubmpi.h:212
#define MPI_ERRORS_RETURN
Definition stubmpi.h:40
void() MPI_User_function(void *a, void *b, int *len, MPI_Datatype *)
Definition stubmpi.h:152
int MPI_Info_create(MPI_Info *info)
Definition stubmpi.h:330
int MPI_Bcast(void *, int, MPI_Datatype, int, MPI_Comm)
Definition stubmpi.h:241
#define MPI_COMM_NULL
Definition stubmpi.h:50
int MPI_Error_string(int errorcode, char *string, int *resultlen)
Definition stubmpi.h:296
int MPI_Isend(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Request *)
Definition stubmpi.h:209
int MPI_Op
Definition stubmpi.h:136
int MPI_Group_free(MPI_Group *group)
Definition stubmpi.h:167
int MPI_Request
Definition stubmpi.h:12
#define MPI_ERR_IN_STATUS
Definition stubmpi.h:39
int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm *newcomm)
Definition stubmpi.h:255
#define MPI_COMM_WORLD
Definition stubmpi.h:25
int MPI_Group
Definition stubmpi.h:11
int MPI_Comm_compare(MPI_Comm comm1, MPI_Comm comm2, int *result)
Definition stubmpi.h:286
int MPI_Finalize()
Definition stubmpi.h:175
int MPI_Info_free(MPI_Info *info)
Definition stubmpi.h:331
int MPI_Query_thread(int *provided)
Definition stubmpi.h:177
int MPI_Comm_create(MPI_Comm, MPI_Group, MPI_Comm *newcomm)
Definition stubmpi.h:270
#define MPI_REQUEST_NULL
Definition stubmpi.h:54
int MPI_Op_create(MPI_User_function *user_fn, int commute, MPI_Op *op)
Definition stubmpi.h:322
int MPI_Finalized(int *flag)
Definition stubmpi.h:176
#define MPI_STATUS_IGNORE
Definition stubmpi.h:21
#define MPI_BYTE
Definition stubmpi.h:77
int MPI_Recv(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Status *)
Definition stubmpi.h:215
#define MPI_STATUSES_IGNORE
Definition stubmpi.h:22
int MPI_Comm
Definition stubmpi.h:24
#define MPI_IDENT
Definition stubmpi.h:44
int MPI_Issend(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Request *)
Definition stubmpi.h:210
int MPI_Init_thread(int *, char ***, int, int *provided)
Definition stubmpi.h:173
unsigned int MPI_Comm_size(MPI_Comm, int *size)
Definition stubmpi.h:206
int MPI_Buffer_attach(void *, int)
Definition stubmpi.h:180
int MPI_Comm_set_errhandler(MPI_Comm comm, MPI_Errhandler errhandler)
Definition stubmpi.h:318
int MPI_Comm_split_type(MPI_Comm comm, int split_type, int key, MPI_Info info, MPI_Comm *newcomm)
Definition stubmpi.h:261
int MPI_Abort(MPI_Comm, int code)
Definition stubmpi.h:266
int MPI_Group_translate_ranks(MPI_Group, int, const int[], MPI_Group, int ranks2[])
Definition stubmpi.h:155
int MPI_Comm_rank(MPI_Comm, int *rank)
Definition stubmpi.h:205
int MPI_Comm_free(MPI_Comm *comm)
Definition stubmpi.h:281
double MPI_Wtime()
Definition stubmpi.h:320
int MPI_Comm_get_attr(MPI_Comm, int, void *, int *)
Definition stubmpi.h:253
#define MPI_COMM_TYPE_SHARED
Definition stubmpi.h:63
int MPI_Info
Definition stubmpi.h:30
int MPI_Allreduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype, MPI_Op, MPI_Comm)
Definition stubmpi.h:248
int MPI_Bsend(void *, int, MPI_Datatype, int, int, MPI_Comm)
Definition stubmpi.h:213
int MPI_Irecv(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Request *)
Definition stubmpi.h:214
int MPI_Comm_group(MPI_Comm, MPI_Group *group)
Definition stubmpi.h:276
int MPI_Barrier(MPI_Comm)
Definition stubmpi.h:268
int MPI_Testsome(int, MPI_Request *, int *outcount, int *, MPI_Status *)
Definition stubmpi.h:194
int MPI_Get_count(MPI_Status *, MPI_Datatype, int *count)
Definition stubmpi.h:199
int MPI_Initialized(int *flag)
Definition stubmpi.h:174
int MPI_Init(int *, char ***)
Definition stubmpi.h:172
#define MPI_MAX_ERROR_STRING
Definition stubmpi.h:41
int MPI_Test(MPI_Request *, int *flag, MPI_Status *)
Definition stubmpi.h:183
int MPI_Group_incl(MPI_Group group, int n, const int ranks[], MPI_Group *newgroup)
Definition stubmpi.h:162
int MPI_Buffer_detach(void *buffer, int *size)
Definition stubmpi.h:181
int MPI_Reduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype, MPI_Op, int, MPI_Comm)
Definition stubmpi.h:244
#define MPI_UNDEFINED
Definition stubmpi.h:26
int MPI_Datatype
Definition stubmpi.h:73
int MPI_Testany(int, MPI_Request[], int *index, int *flag, MPI_Status *)
Definition stubmpi.h:188
int me
Definition test_binsorter.cc:10
void e()
Definition test_sig.cc:75
double source(const coordT &r)
Definition testperiodic.cc:48
const char * status[2]
Definition testperiodic.cc:43
Implements Mutex, MutexFair, Spinlock, ConditionVariable.