MADNESS 0.10.1
worldmpi.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
32#ifndef MADNESS_WORLD_WORLDMPI_H__INCLUDED
33#define MADNESS_WORLD_WORLDMPI_H__INCLUDED
34
35/**
36 \file worldmpi.h
37 \brief Implements \c WorldMpiInterface.
38 \ingroup mpi
39*/
40
41/*
42// If include mpi.h BEFORE stdio/iostream should not need undefs
43#ifdef SEEK_CUR
44#undef SEEK_CUR
45#endif
46#ifdef SEEK_SET
47#undef SEEK_SET
48#endif
49#ifdef SEEK_END
50#undef SEEK_END
51#endif
52*/
53
54#include <type_traits>
57#include <cstdlib>
58
59/// \addtogroup mpi
60/// @{
61
62#ifdef MADNESS_USE_BSEND_ACKS
63/// \todo Verify: Size of the acknowledgment buffer.
64#define MADNESS_ACK_BUFF_SIZE 1000
65#endif // MADNESS_USE_BSEND_ACKS
66
67/// String description of the MPI thread level.
68
69/// \param[in] level The MPI thread level.
70/// \return A string description of the thread level.
71#define MPI_THREAD_STRING(level) \
72 ( level==MPI_THREAD_SERIALIZED ? "THREAD_SERIALIZED" : \
73 ( level==MPI_THREAD_MULTIPLE ? "THREAD_MULTIPLE" : \
74 ( level==MPI_THREAD_FUNNELED ? "THREAD_FUNNELED" : \
75 ( level==MPI_THREAD_SINGLE ? "THREAD_SINGLE" : "THREAD_UNKNOWN" ) ) ) )
76
77namespace madness {
78
79 // Forward declarations
80 class World;
81 World& initialize(int&, char**&, const SafeMPI::Intracomm&, bool);
82 void finalize();
83
84 /// \todo Brief description needed.
85 static const Tag DYNAMIC_TAG_BASE = 1024;
86
87 namespace detail {
88
89 class WorldMpiRuntime;
90
91 /// MPI singleton that manages MPI setup and teardown for MADNESS.
92
93 /// MADNESS will call \c WorldMpi::initialize and \c WorldMpi::finalize
94 /// to setup and teardown the MPI runtime.
95 class WorldMpi {
96 private:
97 // Friends of MpiWorld
98 friend class WorldMpiRuntime;
99
100 /// Pointer to help MADNESS manage MPI.
101
102 /// This shared pointer is used to manage the lifetime of the MPI
103 /// within MADNESS. It ensures that MPI is destroyed only after the
104 /// last world object is destroyed.
105 static std::shared_ptr<WorldMpi> world_mpi;
106 static bool own_mpi; ///< \todo Brief description needed.
107
108#ifdef MADNESS_USE_BSEND_ACKS
109 /// Acknowledgment buffer.
110 static char* mpi_ack_buffer[MADNESS_ACK_BUFF_SIZE];
111#endif // MADNESS_USE_BSEND_ACKS
112
113 /// \c WorldMpi constructor.
114
115 /// Initialize the MPI runtime for MADNESS.
116 /// \note This constructor is private to prevent incorrect
117 /// initialization. The user should call \c initialize.
118 /// \param[in,out] argc The number of command-line arguments to process.
119 /// \param[in,out] argv The command-line arguments.
120 /// \param requested The requested thread support for MPI runtime
121 WorldMpi(int& argc, char**& argv, int requested) {
122 if(own_mpi) {
123 // Assume that MADNESS is managing MPI.
124 SafeMPI::Init_thread(argc, argv, requested);
125 } else {
126 // MPI has already been initialized, so it is the user's
127 // responsibility to manage MPI and MADNESS world objects.
129 }
130
131#ifdef MADNESS_USE_BSEND_ACKS
132 // Register the acknowlegement buffer for RMI
133 SafeMPI::Attach_buffer(mpi_ack_buffer, MADNESS_ACK_BUFF_SIZE);
134#endif // MADNESS_USE_BSEND_ACKS
135 }
136
137 // Not allowed
138 WorldMpi(const WorldMpi&) = delete;
139 WorldMpi& operator=(const WorldMpi&) = delete;
140
141 public:
142
143 /// \c WorldMpi destructor.
144
145 /// This will teardown the MPI, SafeMPI.
147#ifdef MADNESS_USE_BSEND_ACKS
148 // Unregister the acknowlegement buffer for RMI
149 void* buff = nullptr;
151#endif // MADNESS_USE_BSEND_ACKS
152
153 // Teardown MPI/SafeMPI
154 if(own_mpi) {
155 const int result = SafeMPI::Finalize();
156
157 // Check that MPI exited cleanly.
158 if(result != MPI_SUCCESS) {
159 // Print the error message returned by MPI_Finalize().
160 char mpi_error_string[MPI_MAX_ERROR_STRING];
161 int len = 0;
162 if(MPI_Error_string(result, mpi_error_string, &len) != MPI_SUCCESS) {
163 std::strncpy(mpi_error_string, "UNKNOWN MPI ERROR!", MPI_MAX_ERROR_STRING);
164 }
165 std::cout << "!! MPI Error: " << mpi_error_string << "\n";
166 }
167 }
168 }
169
170 /// Initialize the MPI runtime.
171
172 /// This function starts the MPI runtime. If MPI is already running,
173 /// then MADNESS delegate responsibility for MPI to the user. In
174 /// either case, MPI thread support is checked to make sure MPI will
175 /// play nice with MADNESS.
176 ///
177 /// \throw madness::Exception When MADNESS has already been initialized.
178 /// \throw madness::Exception When MPI has already been finalized.
179 /// \throw SafeMPI::Exception When an MPI error occurs.
180 ///
181 /// \param[in,out] argc The number of command line arguments.
182 /// \param[in,out] argv The values of command line arguments.
183 /// \param[in] requested The requested thread support for MPI runtime.
184 static void initialize(int& argc, char**& argv, int requested) {
185 // Check that world_mpi has not been initialized yet and that
186 // MPI has not been finalized
189
190 // Check for ownership of MPI (user or MADNESS runtime).
192
193 // Initialize the MPI runtime
194 world_mpi.reset(new WorldMpi(argc, argv, requested));
195
196 // Check that the thread support provided by MPI matches the
197 // requested and required thread support.
198 const int provided = SafeMPI::Query_thread();
199 const int rank = SafeMPI::COMM_WORLD.Get_rank();
200 if((provided < requested) && (rank == 0)) {
201 std::cout << "!! Error: MPI_Init_thread did not provide requested functionality: "
202 << MPI_THREAD_STRING(requested) << " (" << MPI_THREAD_STRING(provided) << "). \n"
203 << "!! Error: The MPI standard makes no guarantee about the correctness of a program in such circumstances. \n"
204 << "!! Error: Please reconfigure your MPI to provide the proper thread support. \n"
205 << std::endl;
207 } else if((provided > requested) && (rank == 0)) {
208 std::cout << "!! Warning: MPI_Init_thread provided more than the requested functionality: "
209 << MPI_THREAD_STRING(requested) << " (" << MPI_THREAD_STRING(provided) << "). \n"
210 << "!! Warning: You are likely using an MPI implementation with mediocre thread support. \n"
211 << std::endl;
212 }
213
214#if defined(MVAPICH2_VERSION)
215 // Check that MVAPICH2 has has the correct thread affinity
216 char * mv2_string = nullptr;
217 int mv2_affinity = 1; /* this is the default behavior of MVAPICH2 */
218
219 if ((mv2_string = getenv("MV2_ENABLE_AFFINITY")) != nullptr) {
220 mv2_affinity = atoi(mv2_string);
221 }
222
223 if (mv2_affinity!=0) {
224 std::cout << "!! Error: You are using MVAPICH2 with affinity enabled, probably by default. \n"
225 << "!! Error: This will cause catastrophic performance issues in MADNESS. \n"
226 << "!! Error: Rerun your job with MV2_ENABLE_AFFINITY=0 \n"
227 << std::endl;
229 }
230#endif // defined(MVAPICH2_VERSION)
231 }
232
233 /// Finalize the MPI runtime.
234
235 /// This function starts the teardown process of the MPI runtime.
236 /// The actual \c MPI_Finalize will only be called when all the
237 /// objects using MPI have been destroyed.
238 static void finalize() {
239 world_mpi.reset();
240 }
241 }; // class WorldMpi
242
243 /// MPI runtime reference counter.
244
245 /// This object is used to manage the lifetime of the MPI runtime by
246 /// holding a reference to the `WorldMpi::world_mpi` pointer.
248 private:
249 /// A pointer to `WorldMpi::world_mpi`. Used to help manage the lifetime of MPI.
250 std::shared_ptr<WorldMpi> world_mpi;
251
252 public:
253 /// Constructor.
255
256 /// Destructor.
258 }; // class WorldMpiInstance
259
260 } // namespace detail
261
262
263 /// This class wraps/extends the MPI interface for \c World.
266 {
267
268 // Not allowed
271
272 public:
273 /// Constructs an interface in the specified \c SafeMPI communicator.
274
275 /// \todo Verify this documentation.
276 /// \param[in] comm The communicator.
280
282
283 /// Returns the associated \c SafeMPI communicator.
284
285 /// \return The associated \c SafeMPI communicator.
287 return *static_cast<SafeMPI::Intracomm*>(this);
288 }
289
295
296 // !! All of the routines below call the protected interfaces provided above.
297 // !! Please ensure any additional routines follow this convention.
298
299 /// Isend one element.
300
301 /// \note Disabled for pointers to reduce accidental misuse.
302 /// \tparam T The type of data to send.
303 /// \param[in] datum The element to send.
304 /// \param[in] dest The destination process.
305 /// \param[in] tag The MPI tag.
306 template <typename T>
307 typename std::enable_if<!std::is_pointer<T>::value, SafeMPI::Request>::type
308 Isend(const T& datum, int dest, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const {
309 return SafeMPI::Intracomm::Isend(&datum, sizeof(T), MPI_BYTE, dest, tag);
310 }
311
312 /// Async receive data of up to \c count elements from process \c source.
313
314 /// \tparam T The type of data to receive.
315 /// \param[out] buf Where to put the received data.
316 /// \param[in] count The number of data elements to receive.
317 /// \param[in] source The source process.
318 /// \param[in] tag The MPI tag.
319 template <typename T>
321 Irecv(T* buf, int count, int source, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const {
322 return SafeMPI::Intracomm::Irecv(buf, count*sizeof(T), MPI_BYTE, source, tag);
323 }
324
325
326 /// Async receive datum from process \c source with default `tag=1`.
327
328 /// \tparam T The type of data to receive.
329 /// \param[out] buf Where to put the received datum.
330 /// \param[in] source The source process.
331 /// \param[in] tag The MPI tag.
332 template <typename T>
333 typename std::enable_if<!std::is_pointer<T>::value, SafeMPI::Request>::type
334 Irecv(T& buf, int source, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const {
335 return SafeMPI::Intracomm::Irecv(&buf, sizeof(T), MPI_BYTE, source, tag);
336 }
337
338
339 /// Send array of \c lenbuf elements to process \c dest.
340
341 /// \tparam T The type of data to send.
342 /// \param[in] buf Pointer to the data.
343 /// \param[in] lenbuf The number of data elements to send.
344 /// \param[in] dest The destination process.
345 /// \param[in] tag The MPI tag.
346 template <class T>
347 void Send(const T* buf, long lenbuf, int dest, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const {
348 SafeMPI::Intracomm::Send((void*)buf, lenbuf*sizeof(T), MPI_BYTE, dest, tag);
349 }
350
351
352 /// Send element to process \c dest with default `tag=1001`.
353
354 /// \note Disabled for pointers to reduce accidental misuse.
355 /// \tparam T The type of data to send.
356 /// \param[in] datum The data element to send.
357 /// \param[in] dest The destination process.
358 /// \param[in] tag The MPI tag.
359 template <typename T>
360 typename std::enable_if<!std::is_pointer<T>::value, void>::type
361 Send(const T& datum, int dest, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const {
362 SafeMPI::Intracomm::Send((void*)&datum, sizeof(T), MPI_BYTE, dest, tag);
363 }
364
365
366 /// Receive data of up to \c lenbuf elements from process \c src.
367
368 /// \tparam T The type of data to receive.
369 /// \param[out] buf Where to put the received data.
370 /// \param[in] lenbuf The maximum number of data elements to receive.
371 /// \param[in] src The source process.
372 /// \param[in] tag The MPI tag.
373 template <typename T>
374 void Recv(T* buf, long lenbuf, int src, int tag) const {
375 SafeMPI::Intracomm::Recv(buf, lenbuf*sizeof(T), MPI_BYTE, src, tag);
376 }
377
378 /// Receive data of up to \c lenbuf elements from process \c dest with \c status.
379
380 /// \tparam T The type of data to receive.
381 /// \param[out] buf Where to put the received data.
382 /// \param[in] lenbuf The maximum number of data elements to receive.
383 /// \param[in] src The source process.
384 /// \param[in] tag The MPI tag.
385 /// \param[in] status The status.
386 template <typename T>
387 void Recv(T* buf, long lenbuf, int src, int tag, SafeMPI::Status& status) const {
388 SafeMPI::Intracomm::Recv(buf, lenbuf*sizeof(T), MPI_BYTE, src, tag, status);
389 }
390
391
392 /// Receive datum from process \c src.
393
394 /// \tparam T The type of data to receive.
395 /// \param[out] buf The received datum.
396 /// \param[in] src The source process.
397 /// \param[in] tag The MPI tag.
398 template <typename T>
399 typename std::enable_if<!std::is_pointer<T>::value, void>::type
400 Recv(T& buf, int src, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const {
401 SafeMPI::Intracomm::Recv(&buf, sizeof(T), MPI_BYTE, src, tag);
402 }
403
404
405 /// MPI broadcast an array of \c count elements.
406
407 /// \note Read documentation about interaction of MPI collectives and
408 /// AM/task handling.
409 /// \tparam T The type of data to broadcast.
410 /// \param[in,out] buffer The data to send (if this is the \c root
411 /// process); otherwise, a buffer to receive the data.
412 /// \param[in] count The number of data elements being broadcast.
413 /// \param[in] root The process that is sending the data to other
414 /// processes.
415 template <typename T>
416 void Bcast(T* buffer, int count, int root) const {
417 SafeMPI::Intracomm::Bcast(buffer,count*sizeof(T),MPI_BYTE,root);
418 }
419
420
421 /// MPI broadcast a datum.
422
423 /// \note Read documentation about interaction of MPI collectives and
424 /// AM/task handling.
425 /// \tparam T The type of data to broadcast.
426 /// \param[in,out] buffer The datum to send (if this is the \c root
427 /// process); otherwise, the received datum.
428 /// \param[in] root The process that is sending the data to other
429 /// processes.
430 template <typename T>
431 typename std::enable_if<!std::is_pointer<T>::value, void>::type
432 Bcast(T& buffer, int root) const {
433 SafeMPI::Intracomm::Bcast(&buffer, sizeof(T), MPI_BYTE, root);
434 }
435
436 /// Access the rank of this process.
437
438 /// \return The rank of this process.
439 int rank() const { return SafeMPI::Intracomm::Get_rank(); }
440
441 /// Access the total number of processes.
442
443 /// \return The number of processes.
444 int nproc() const { return SafeMPI::Intracomm::Get_size(); }
445
446 /// Access the total number of processes.
447
448 /// \return The number of processes.
449 int size() const { return SafeMPI::Intracomm::Get_size(); }
450 }; // class WorldMpiInterface
451
452}
453
454/// @}
455
456#endif // MADNESS_WORLD_WORLDMPI_H__INCLUDED
Wrapper around MPI_Comm. Has a shallow copy constructor; use Create(Get_group()) for deep copy.
Definition safempi.h:490
Request Irecv(void *buf, const int count, const MPI_Datatype datatype, const int src, const int tag) const
Definition safempi.h:740
void Bcast(void *buf, size_t count, const MPI_Datatype datatype, const int root) const
Definition safempi.h:775
Request Isend(const void *buf, const int count, const MPI_Datatype datatype, const int dest, const int tag) const
Definition safempi.h:724
int Get_rank() const
Definition safempi.h:714
void Send(const void *buf, const int count, const MPI_Datatype datatype, int dest, int tag) const
Definition safempi.h:748
void Recv(void *buf, const int count, const MPI_Datatype datatype, const int source, const int tag, MPI_Status &status) const
Definition safempi.h:763
int Get_size() const
Definition safempi.h:719
Intracomm()
Definition safempi.h:573
Definition safempi.h:289
Definition safempi.h:224
This class wraps/extends the MPI interface for World.
Definition worldmpi.h:266
void Recv(T *buf, long lenbuf, int src, int tag, SafeMPI::Status &status) const
Receive data of up to lenbuf elements from process dest with status.
Definition worldmpi.h:387
int nproc() const
Access the total number of processes.
Definition worldmpi.h:444
std::enable_if<!std::is_pointer< T >::value, SafeMPI::Request >::type Isend(const T &datum, int dest, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const
Isend one element.
Definition worldmpi.h:308
std::enable_if<!std::is_pointer< T >::value, SafeMPI::Request >::type Irecv(T &buf, int source, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const
Async receive datum from process source with default tag=1.
Definition worldmpi.h:334
std::enable_if<!std::is_pointer< T >::value, void >::type Send(const T &datum, int dest, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const
Send element to process dest with default tag=1001.
Definition worldmpi.h:361
void Bcast(T *buffer, int count, int root) const
MPI broadcast an array of count elements.
Definition worldmpi.h:416
SafeMPI::Request Irecv(T *buf, int count, int source, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const
Async receive data of up to count elements from process source.
Definition worldmpi.h:321
WorldMpiInterface(const WorldMpiInterface &)=delete
SafeMPI::Intracomm & comm()
Returns the associated SafeMPI communicator.
Definition worldmpi.h:286
int size() const
Access the total number of processes.
Definition worldmpi.h:449
void Send(const T *buf, long lenbuf, int dest, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const
Send array of lenbuf elements to process dest.
Definition worldmpi.h:347
std::enable_if<!std::is_pointer< T >::value, void >::type Bcast(T &buffer, int root) const
MPI broadcast a datum.
Definition worldmpi.h:432
std::enable_if<!std::is_pointer< T >::value, void >::type Recv(T &buf, int src, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const
Receive datum from process src.
Definition worldmpi.h:400
int rank() const
Access the rank of this process.
Definition worldmpi.h:439
void Recv(T *buf, long lenbuf, int src, int tag) const
Receive data of up to lenbuf elements from process src.
Definition worldmpi.h:374
WorldMpiInterface(const SafeMPI::Intracomm &comm)
Constructs an interface in the specified SafeMPI communicator.
Definition worldmpi.h:277
WorldMpiInterface & operator=(const WorldMpiInterface &)=delete
MPI runtime reference counter.
Definition worldmpi.h:247
std::shared_ptr< WorldMpi > world_mpi
A pointer to WorldMpi::world_mpi. Used to help manage the lifetime of MPI.
Definition worldmpi.h:250
WorldMpiRuntime()
Constructor.
Definition worldmpi.h:254
~WorldMpiRuntime()
Destructor.
Definition worldmpi.h:257
MPI singleton that manages MPI setup and teardown for MADNESS.
Definition worldmpi.h:95
WorldMpi(int &argc, char **&argv, int requested)
WorldMpi constructor.
Definition worldmpi.h:121
WorldMpi & operator=(const WorldMpi &)=delete
static void initialize(int &argc, char **&argv, int requested)
Initialize the MPI runtime.
Definition worldmpi.h:184
static void finalize()
Finalize the MPI runtime.
Definition worldmpi.h:238
WorldMpi(const WorldMpi &)=delete
~WorldMpi()
WorldMpi destructor.
Definition worldmpi.h:146
auto T(World &world, response_space &f) -> response_space
Definition global_functions.cc:34
#define MPI_THREAD_STRING(level)
String description of the MPI thread level.
Definition worldmpi.h:71
static bool own_mpi
Flag storing if MADNESS is responsible for MPI.
Definition worldmpi.h:106
static std::shared_ptr< WorldMpi > world_mpi
Pointer to help MADNESS manage MPI.
Definition worldmpi.h:105
#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:863
Definition safempi.cc:35
Intracomm COMM_WORLD
Definition safempi.cc:67
int Init_thread(int &argc, char **&argv, int requested)
Analogous to MPI_Init_thread.
Definition safempi.h:878
void Attach_buffer(void *buffer, int size)
Set buffer for Bsend .
Definition safempi.h:942
int Query_thread()
Analogous to MPI_Query_thread.
Definition safempi.h:927
int Finalize()
Analogous to MPI_Finalize.
Definition safempi.h:918
bool Is_initialized()
Check MPI initialization status.
Definition safempi.h:116
static const int DEFAULT_SEND_RECV_TAG
Definition safempi.h:106
int Detach_buffer(void *&buffer)
Unset the Bsend buffer.
Definition safempi.h:949
bool Is_finalized()
Check MPI finalization status.
Definition safempi.h:125
Namespace for all elements and tools of MADNESS.
Definition DFParameters.h:10
void finalize()
Call this once at the very end of your main program instead of MPI_Finalize().
Definition world.cc:232
static const Tag DYNAMIC_TAG_BASE
Definition worldmpi.h:85
World & initialize(int &argc, char **&argv, bool quiet)
Definition world.cc:145
std::string type(const PairType &n)
Definition PNOParameters.h:18
Serializes calls to MPI in case it does not support THREAD_MULTIPLE.
#define MPI_SUCCESS
Definition stubmpi.h:36
int MPI_Error_string(int errorcode, char *string, int *resultlen)
Definition stubmpi.h:296
#define MPI_COMM_WORLD
Definition stubmpi.h:25
#define MPI_BYTE
Definition stubmpi.h:77
int MPI_Abort(MPI_Comm, int code)
Definition stubmpi.h:266
#define MPI_MAX_ERROR_STRING
Definition stubmpi.h:41
double source(const coordT &r)
Definition testperiodic.cc:48
const char * status[2]
Definition testperiodic.cc:43
Defines types used by the parallel runtime.
int Tag
Used to clearly identify message tag/type.
Definition worldtypes.h:44