MADNESS  version 0.9
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  $Id$
33 */
34 
35 
36 #ifndef MADNESS_WORLD_WORLDMPI_H__INCLUDED
37 #define MADNESS_WORLD_WORLDMPI_H__INCLUDED
38 
41 
42 /*
43 // If include mpi.h BEFORE stdio/iostream should not need undefs
44 #ifdef SEEK_CUR
45 #undef SEEK_CUR
46 #endif
47 #ifdef SEEK_SET
48 #undef SEEK_SET
49 #endif
50 #ifdef SEEK_END
51 #undef SEEK_END
52 #endif
53 */
54 
55 #include <madness/world/safempi.h>
58 #include <cstdlib>
59 
60 
61 #ifdef MADNESS_USE_BSEND_ACKS
62 #define MADNESS_ACK_BUFF_SIZE 1000
63 #endif // MADNESS_USE_BSEND_ACKS
64 
65 #define MPI_THREAD_STRING(level) \
66  ( level==MPI_THREAD_SERIALIZED ? "THREAD_SERIALIZED" : \
67  ( level==MPI_THREAD_MULTIPLE ? "THREAD_MULTIPLE" : \
68  ( level==MPI_THREAD_FUNNELED ? "THREAD_FUNNELED" : \
69  ( level==MPI_THREAD_SINGLE ? "THREAD_SINGLE" : "THREAD_UNKNOWN" ) ) ) )
70 
71 namespace madness {
72 
73  // Forward declarations
74  class World;
75  World& initialize(int&, char**&, const SafeMPI::Intracomm&);
76  void finalize();
77 
78  static const Tag DYNAMIC_TAG_BASE = 1024;
79 
80  namespace detail {
81 
82  class WorldMpiRuntime;
83 
85 
88  class WorldMpi {
89  private:
90  // Friends of MpiWorld
91  friend class WorldMpiRuntime;
92 
93  // This shared pointer is used to manage the lifetime of the MPI
94  // within MADNESS. It ensures that MPI is destroyed only after the
95  // last world object is destroyed.
96  static std::shared_ptr<WorldMpi> world_mpi;
97  static bool own_mpi;
98 
99 #ifdef MADNESS_USE_BSEND_ACKS
100  static char* mpi_ack_buffer[MADNESS_ACK_BUFF_SIZE];
101 #endif // MADNESS_USE_BSEND_ACKS
102 
104 
108  WorldMpi(int& argc, char**& argv, int requested) {
109  if(own_mpi) {
110  // Assume that MADNESS is managing MPI.
111  SafeMPI::Init_thread(argc, argv, requested);
112  } else {
113  // MPI has already been initialized, so it is the user's
114  // responsibility to manage MPI and MADNESS world objects.
116  }
117 
118 #ifdef MADNESS_USE_BSEND_ACKS
119  // Register the acknowlegement buffer for RMI
120  SafeMPI::Attach_buffer(mpi_ack_buffer, MADNESS_ACK_BUFF_SIZE);
121 #endif // MADNESS_USE_BSEND_ACKS
122  }
123 
124  // Not allowed
125  WorldMpi(const WorldMpi&);
126  WorldMpi& operator=(const WorldMpi&);
127 
128  public:
129 
131 
134 #ifdef MADNESS_USE_BSEND_ACKS
135  // Unregister the acknowlegement buffer for RMI
136  void* buff = NULL;
138 #endif // MADNESS_USE_BSEND_ACKS
139 
140  // Teardown MPI/SafeMPI
141  if(own_mpi) {
142  const int result = SafeMPI::Finalize();
143 
144  // Check that MPI exited cleanly.
145  if(result != MPI_SUCCESS) {
146  // Print the error message returned by MPI_Finalize().
147  char mpi_error_string[MPI_MAX_ERROR_STRING];
148  int len = 0;
149  if(MPI_Error_string(result, mpi_error_string, &len) != MPI_SUCCESS) {
150  std::strncpy(mpi_error_string, "UNKNOWN MPI ERROR!", MPI_MAX_ERROR_STRING);
151  }
152  std::cout << "!! MPI Error: " << mpi_error_string << "\n";
153  }
154  }
155  }
156 
158 
169  static void initialize(int& argc, char**& argv, int requested) {
170  // Check that world_mpi has not been initialized yet and that
171  // MPI has not been finalized
172  MADNESS_ASSERT(! world_mpi);
173  MADNESS_ASSERT(! SafeMPI::Is_finalized());
174 
175  // Check for ownership of MPI (user or MADNESS runtime).
176  own_mpi = ! SafeMPI::Is_initialized();
177 
178  // Initialize the MPI runtime
179  world_mpi.reset(new WorldMpi(argc, argv, requested));
180 
181  // Check that the thread support provided by MPI matches the
182  // requested and required thread support.
183  const int provided = SafeMPI::Query_thread();
184  const int rank = SafeMPI::COMM_WORLD.Get_rank();
185  if((provided < requested) && (rank == 0)) {
186  std::cout << "!! Error: MPI_Init_thread did not provide requested functionality: "
187  << MPI_THREAD_STRING(requested) << " (" << MPI_THREAD_STRING(provided) << "). \n"
188  << "!! Error: The MPI standard makes no guarantee about the correctness of a program in such circumstances. \n"
189  << "!! Error: Please reconfigure your MPI to provide the proper thread support. \n"
190  << std::endl;
192  } else if((provided > requested) && (rank == 0)) {
193  std::cout << "!! Warning: MPI_Init_thread provided more than the requested functionality: "
194  << MPI_THREAD_STRING(requested) << " (" << MPI_THREAD_STRING(provided) << "). \n"
195  << "!! Warning: You are likely using an MPI implementation with mediocre thread support. \n"
196  << std::endl;
197  }
198 
199 #if defined(MVAPICH2_VERSION)
200  // Check that MVAPICH2 has has the correct thread affinity
201  char * mv2_string = NULL;
202  int mv2_affinity = 1; /* this is the default behavior of MVAPICH2 */
203 
204  if ((mv2_string = getenv("MV2_ENABLE_AFFINITY")) != NULL) {
205  mv2_affinity = atoi(mv2_string);
206  }
207 
208  if (mv2_affinity!=0) {
209  std::cout << "!! Error: You are using MVAPICH2 with affinity enabled, probably by default. \n"
210  << "!! Error: This will cause catastrophic performance issues in MADNESS. \n"
211  << "!! Error: Rerun your job with MV2_ENABLE_AFFINITY=0 \n"
212  << std::endl;
214  }
215 #endif // defined(MVAPICH2_VERSION)
216  }
217 
219 
223  static void finalize() {
224  world_mpi.reset();
225  }
226  }; // class WorldMpi
227 
229 
233  private:
234  std::shared_ptr<WorldMpi> world_mpi;
235 
236  public:
237  WorldMpiRuntime() : world_mpi(WorldMpi::world_mpi) { }
238  ~WorldMpiRuntime() { world_mpi.reset(); }
239  }; // class WorldMpiInstance
240 
241  } // namespace detail
242 
243 
246 
247  // Not allowed
249  WorldMpiInterface& operator=(const WorldMpiInterface&);
250 
251  public:
253  detail::WorldMpiRuntime(), SafeMPI::Intracomm(comm)
254  { }
255 
257 
260  return *static_cast<SafeMPI::Intracomm*>(this);
261  }
262 
268 
269  // !! All of the routines below call the protected interfaces provided above.
270  // !! Please ensure any additional routines follow this convention.
272  template <typename T>
274  Isend(const T& datum, int dest, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const {
275  return SafeMPI::Intracomm::Isend(&datum, sizeof(T), MPI_BYTE, dest, tag);
276  }
277 
279  template <typename T>
281  Irecv(T* buf, int count, int source, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const {
282  return SafeMPI::Intracomm::Irecv(buf, count*sizeof(T), MPI_BYTE, source, tag);
283  }
284 
285 
287  template <typename T>
289  Irecv(T& buf, int source, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const {
290  return SafeMPI::Intracomm::Irecv(&buf, sizeof(T), MPI_BYTE, source, tag);
291  }
292 
293 
295  template <class T>
296  void Send(const T* buf, long lenbuf, int dest, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const {
297  SafeMPI::Intracomm::Send((void*)buf, lenbuf*sizeof(T), MPI_BYTE, dest, tag);
298  }
299 
300 
302 
304  template <typename T>
305  typename madness::disable_if<std::is_pointer<T>, void>::type
306  Send(const T& datum, int dest, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const {
307  SafeMPI::Intracomm::Send((void*)&datum, sizeof(T), MPI_BYTE, dest, tag);
308  }
309 
310 
312  template <typename T>
313  void Recv(T* buf, long lenbuf, int src, int tag) const {
314  SafeMPI::Intracomm::Recv(buf, lenbuf*sizeof(T), MPI_BYTE, src, tag);
315  }
316 
318  template <typename T>
319  void Recv(T* buf, long lenbuf, int src, int tag, SafeMPI::Status& status) const {
320  SafeMPI::Intracomm::Recv(buf, lenbuf*sizeof(T), MPI_BYTE, src, tag, status);
321  }
322 
323 
325  template <typename T>
326  typename madness::disable_if<std::is_pointer<T>, void>::type
327  Recv(T& buf, int src, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const {
328  SafeMPI::Intracomm::Recv(&buf, sizeof(T), MPI_BYTE, src, tag);
329  }
330 
331 
333 
335  template <typename T>
336  void Bcast(T* buffer, int count, int root) const {
337  SafeMPI::Intracomm::Bcast(buffer,count*sizeof(T),MPI_BYTE,root);
338  }
339 
340 
342 
344  template <typename T>
345  typename madness::disable_if<std::is_pointer<T>, void>::type
346  Bcast(T& buffer, int root) const {
347  SafeMPI::Intracomm::Bcast(&buffer, sizeof(T), MPI_BYTE,root);
348  }
349 
350  int rank() const { return SafeMPI::Intracomm::Get_rank(); }
351 
352  int nproc() const { return SafeMPI::Intracomm::Get_size(); }
353 
354  int size() const { return SafeMPI::Intracomm::Get_size(); }
355  }; // class WorldMpiInterface
356 
357 }
358 
359 #endif // MADNESS_WORLD_WORLDMPI_H__INCLUDED
void Attach_buffer(void *buffer, int size)
Set buffer for Bsend .
Definition: safempi.h:773
Serializes calls to MPI in case it does not support THREAD_MULTIPLE.
Definition: shared_ptr_bits.h:38
Request Isend(const void *buf, const int count, const MPI_Datatype datatype, const int dest, const int tag) const
Definition: safempi.h:580
void Recv(void *buf, const int count, const MPI_Datatype datatype, const int source, const int tag, MPI_Status &status) const
Definition: safempi.h:611
MPI runtime reference counter.
Definition: worldmpi.h:232
void Recv(T *buf, long lenbuf, int src, int tag) const
Receive data of up to lenbuf elements from process dest.
Definition: worldmpi.h:313
#define MPI_THREAD_STRING(level)
Definition: worldmpi.h:65
Wrapper around MPI_Comm. Has a shallow copy constructor; use Create(Get_group()) for deep copy...
Definition: safempi.h:437
bool Is_initialized()
Check MPI initialization status.
Definition: safempi.h:112
static void initialize(int &argc, char **&argv, int requested)
Initialize the MPI runtime.
Definition: worldmpi.h:169
MPI singleton that manages MPI setup and teardown for MADNESS.
Definition: worldmpi.h:88
int Finalize()
Analogous to MPI_Finalize.
Definition: safempi.h:749
madness::disable_if< std::is_pointer< T >, void >::type Recv(T &buf, int src, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const
Receive datum from process src.
Definition: worldmpi.h:327
char * strncpy()
Intracomm(const WorldInitObject &)
Definition: safempi.cc:66
WorldMpiRuntime()
Definition: worldmpi.h:237
int Tag
Used to clearly identify message tag/type.
Definition: worldtypes.h:38
~WorldMpi()
WorldMpi destructor.
Definition: worldmpi.h:133
void init_comm_world()
Initialize SafeMPI::COMM_WORLD.
Definition: safempi.h:695
SafeMPI::Request Irecv(T *buf, int count, int source, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const
Async receive data of up to lenbuf elements from process dest.
Definition: worldmpi.h:281
madness::disable_if< std::is_pointer< T >, 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:306
SafeMPI::Intracomm & comm()
Returns the associated SafeMPI communicator.
Definition: worldmpi.h:259
int Get_size() const
Definition: safempi.h:575
This class wraps/extends the MPI interface for World.
Definition: worldmpi.h:245
POD holding excitation energy and response vector for a single excitation.
Definition: tdhf_CIS.h:134
World & initialize(int &argc, char **&argv)
Initialize the MADNESS runtime.
Definition: world.cc:134
#define MPI_COMM_WORLD
Definition: stubmpi.h:23
int MPI_Error_string(int errorcode, char *string, int *resultlen)
Definition: stubmpi.h:203
int Detach_buffer(void *&buffer)
Unset the Bsend buffer.
Definition: safempi.h:780
disable_if from Boost for conditionally instantiating templates based on type
Definition: enable_if.h:78
~WorldMpiRuntime()
Definition: worldmpi.h:238
#define MPI_BYTE
Definition: stubmpi.h:66
int size() const
Definition: worldmpi.h:354
madness::disable_if< std::is_pointer< T >, SafeMPI::Request >::type Isend(const T &datum, int dest, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const
Isend one element ... disabled for pointers to reduce accidental misuse.
Definition: worldmpi.h:274
void Bcast(T *buffer, int count, int root) const
MPI broadcast an array of count elements.
Definition: worldmpi.h:336
int Init_thread(int &argc, char **&argv, int requested)
Analogous to MPI_Init_thread.
Definition: safempi.h:709
const T1 &f1 return GTEST_2_TUPLE_() T(f0, f1)
madness::disable_if< std::is_pointer< T >, SafeMPI::Request >::type Irecv(T &buf, int source, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const
Async receive datum from process dest with default tag=1.
Definition: worldmpi.h:289
~WorldMpiInterface()
Definition: worldmpi.h:256
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:319
void finalize()
Call this once at the very end of your main program instead of calling MPI_Finalize.
Definition: world.cc:212
static void finalize()
Finalize the MPI runtime.
Definition: worldmpi.h:223
int Query_thread()
Analogous to MPI_Query_thread.
Definition: safempi.h:758
int Get_rank() const
Definition: safempi.h:570
WorldMpiInterface(const SafeMPI::Intracomm &comm)
Definition: worldmpi.h:252
Definition: safempi.h:243
void reset()
Definition: shared_ptr_bits.h:459
int rank() const
Definition: worldmpi.h:350
bool Is_finalized()
Check MPI finalization status.
Definition: safempi.h:121
madness::disable_if< std::is_pointer< T >, void >::type Bcast(T &buffer, int root) const
MPI broadcast a datum.
Definition: worldmpi.h:346
#define MPI_MAX_ERROR_STRING
Definition: stubmpi.h:31
Intracomm COMM_WORLD
Definition: safempi.cc:70
Definition: safempi.cc:36
void Bcast(void *buf, size_t count, const MPI_Datatype datatype, const int root) const
Definition: safempi.h:623
Request Irecv(void *buf, const int count, const MPI_Datatype datatype, const int src, const int tag) const
Definition: safempi.h:588
void Send(const void *buf, const int count, const MPI_Datatype datatype, int dest, int tag) const
Definition: safempi.h:596
Holds machinery to set up Functions/FuncImpls using various Factories and Interfaces.
Definition: chem/atomutil.cc:45
Definition: safempi.h:178
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:296
int nproc() const
Definition: worldmpi.h:352
#define MPI_SUCCESS
Definition: stubmpi.h:28
int MPI_Abort(MPI_Comm, int code)
Definition: stubmpi.h:174