TIMPI
Public Member Functions | Private Attributes | List of all members
TIMPI::TIMPIInit Class Reference

The TIMPIInit class, when constructed, initializes any dependent libraries (e.g. More...

#include <timpi_init.h>

Public Member Functions

 TIMPIInit (int argc, const char *const *argv, int mpi_thread_requested=0, bool handle_mpi_errors=false, MPI_Comm COMM_WORLD_IN=MPI_COMM_WORLD)
 Initialize the library for use, with the command line options provided. More...
 
 TIMPIInit (int argc, const char *const *argv, int mpi_thread_requested=0, bool handle_mpi_errors=false)
 
virtual ~TIMPIInit ()
 Destructor. More...
 
const Communicatorcomm () const
 Returns the Communicator created by this object, which will be a compatibility shim if MPI is not enabled, or a wrapper for the user-input MPI_Comm if we were constructed with one, or a wrapper for MPI_COMM_WORLD by default. More...
 
Communicatorcomm ()
 

Private Attributes

std::unique_ptr< Communicator_comm
 
std::unique_ptr< SemiPermanent::Ref_ref
 
bool i_initialized_mpi
 
MPI_Errhandler my_errhandler
 
bool err_handler_set
 

Detailed Description

The TIMPIInit class, when constructed, initializes any dependent libraries (e.g.

MPI).

For many users, a single TIMPIInit object should be created at the start of your main() function.

Since "it is best not to perform much more than a return rc after calling MPI_Finalize", applications which want to do anything after TIMPIInit destruction should manage MPI initialization and finalization manually.

Definition at line 57 of file timpi_init.h.

Constructor & Destructor Documentation

◆ TIMPIInit() [1/2]

TIMPI::TIMPIInit::TIMPIInit ( int  argc,
const char *const *  argv,
int  mpi_thread_requested = 0,
bool  handle_mpi_errors = false,
MPI_Comm  COMM_WORLD_IN = MPI_COMM_WORLD 
)

Initialize the library for use, with the command line options provided.

This will e.g. call MPI_Init_thread if MPI is available and enabled and has not already been initialized.

mpi_thread_requested should be set to 0 when MPI_THREAD_SINGLE is desired, 1 when MPI_THREAD_FUNNELED initialization is desired, 2 when MPI_THREAD_SERIALIZED is desaired, and 3 when MPI_THREAD_MULTIPLE is desired

handle_mpi_errors should be set to true to use the "timpi_not_implemented()" behavior (e.g. throwing an exception) as an MPI error handler, which can aid in debugging.

When building with MPI, this method may take an optional parameter to use a user-specified MPI communicator.

Definition at line 44 of file timpi_init.C.

References _comm, _ref, err_handler_set, i_initialized_mpi, my_errhandler, and TIMPI_MPI_Handler().

47  :
48  i_initialized_mpi(false),
49  err_handler_set(false)
50 {
51  // Check whether the calling program has already initialized
52  // MPI, and avoid duplicate Init/Finalize
53  int flag;
54  timpi_call_mpi(MPI_Initialized (&flag));
55 
56  if (!flag)
57  {
58  int mpi_thread_provided;
59 
60  timpi_call_mpi
61  (MPI_Init_thread (&argc, const_cast<char ***>(&argv),
62  mpi_thread_requested, &mpi_thread_provided));
63 
64  if (mpi_thread_provided < mpi_thread_requested)
65  {
66  // Ideally, if an MPI stack tells us it's unsafe for us
67  // to use threads, we should scream and die or at least
68  // disable threads.
69  //
70  // In practice, we've encountered one MPI stack (an mvapich2
71  // configuration) that returned MPI_THREAD_SINGLE as a
72  // proper warning, two stacks that handle
73  // MPI_THREAD_FUNNELED properly, and two current stacks plus
74  // a couple old stacks that return MPI_THREAD_SINGLE but
75  // support threaded runs anyway, so we just emit a warning.
76  //
77  std::string thread_type;
78  switch (mpi_thread_requested)
79  {
80  case 0:
81  thread_type = "MPI_THREAD_SINGLE";
82  break;
83  case 1:
84  thread_type = "MPI_THREAD_FUNNELED";
85  break;
86  case 2:
87  thread_type = "MPI_THREAD_SERIALIZED";
88  break;
89  case 3:
90  thread_type = "MPI_THREAD_MULTIPLE";
91  break;
92  default:
93  timpi_error_msg("Unsupported mpi thread requested '" << mpi_thread_requested << "'");
94  }
95 
96  timpi_warning("Warning: MPI failed to guarantee " << thread_type << "\n"
97  << "for a threaded run.\n"
98  << std::endl);
99  }
100  this->i_initialized_mpi = true;
101  }
102 
103  // Duplicate the input communicator for internal use
104  // And get a Communicator copy too, to use
105  // as a default for that API
106  this->_comm = std::make_unique<Communicator>(COMM_WORLD_IN);
107 
108  // Let SemiPermanent know we need its objects for a while
109  this->_ref = std::make_unique<SemiPermanent::Ref>();
110 
111  // Set up an MPI error handler if requested. This helps us get
112  // into a debugger with a proper stack when an MPI error occurs.
113  if (handle_mpi_errors)
114  {
115  timpi_call_mpi
116  (MPI_Comm_create_errhandler(TIMPI_MPI_Handler, &my_errhandler));
117  timpi_call_mpi
118  (MPI_Comm_set_errhandler(COMM_WORLD_IN, my_errhandler));
119  timpi_call_mpi
120  (MPI_Comm_set_errhandler(MPI_COMM_WORLD, my_errhandler));
121  err_handler_set = true;
122  }
123 }
std::unique_ptr< SemiPermanent::Ref > _ref
Definition: timpi_init.h:108
void TIMPI_MPI_Handler(MPI_Comm *, int *,...)
Definition: timpi_init.C:33
bool i_initialized_mpi
Definition: timpi_init.h:111
MPI_Errhandler my_errhandler
Definition: timpi_init.h:113
std::unique_ptr< Communicator > _comm
Definition: timpi_init.h:105

◆ TIMPIInit() [2/2]

TIMPI::TIMPIInit::TIMPIInit ( int  argc,
const char *const *  argv,
int  mpi_thread_requested = 0,
bool  handle_mpi_errors = false 
)

Definition at line 125 of file timpi_init.C.

References _comm, and _ref.

128 {
129  this->_comm = std::make_unique<Communicator>(); // So comm() doesn't dereference null
130  this->_ref = std::make_unique<SemiPermanent::Ref>();
131 }
std::unique_ptr< SemiPermanent::Ref > _ref
Definition: timpi_init.h:108
std::unique_ptr< Communicator > _comm
Definition: timpi_init.h:105

◆ ~TIMPIInit()

TIMPI::TIMPIInit::~TIMPIInit ( )
virtual

Destructor.

Finalizes MPI if that was initialized by TIMPIInit.

Definition at line 136 of file timpi_init.C.

References _comm, _ref, TIMPI::Communicator::barrier(), comm(), err_handler_set, i_initialized_mpi, and my_errhandler.

137 {
138  // Every processor had better be ready to exit at the same time.
139  // Even if we're not doing parallel_only debugging, we don't want
140  // one processor to try to exit until all others are done working.
141 
142  // We could be destructing here because we're unwinding the stack
143  // due to a thrown exception, though. It's possible that an
144  // application is catching exceptions outside of the LibMeshInit
145  // scope, or that we're using a C++ compiler that does unwinding
146  // for uncaught exceptions (the standard says whether to go straight
147  // to terminate() or unwind first is "implementation-defined"). If
148  // *that* is the case then we can't safely communicate with other
149  // processors that might not all be unwinding too.
150 #ifdef TIMPI_ENABLE_EXCEPTIONS
151  if (!std::uncaught_exceptions())
152 #endif
153  this->comm().barrier();
154 
155  // Trigger any SemiPermanent cleanup before potentially finalizing MPI
156  _ref.reset();
157 
158 #ifdef TIMPI_HAVE_MPI
159  if (err_handler_set)
160  {
161  unsigned int error_code =
162  MPI_Errhandler_free(&my_errhandler);
163  if (error_code != MPI_SUCCESS)
164  {
165  std::cerr <<
166  "Failure when freeing MPI_Errhandler! Continuing..." <<
167  std::endl;
168  }
169  }
170 
171  this->_comm.reset();
172 
173  if (this->i_initialized_mpi)
174  {
175  // We can't just timpi_assert here because destructor,
176  // but we ought to report any errors
177  int error_code = MPI_Finalize();
178  if (error_code != MPI_SUCCESS)
179  {
180  char error_string[MPI_MAX_ERROR_STRING+1];
181  int error_string_len;
182  MPI_Error_string(error_code, error_string,
183  &error_string_len);
184  std::cerr << "Failure from MPI_Finalize():\n"
185  << error_string << std::endl;
186  }
187  }
188 #else
189  this->_comm.reset();
190 #endif
191 }
std::unique_ptr< SemiPermanent::Ref > _ref
Definition: timpi_init.h:108
void barrier() const
Pause execution until all processors reach a certain point.
Definition: communicator.C:225
bool i_initialized_mpi
Definition: timpi_init.h:111
MPI_Errhandler my_errhandler
Definition: timpi_init.h:113
std::unique_ptr< Communicator > _comm
Definition: timpi_init.h:105
const Communicator & comm() const
Returns the Communicator created by this object, which will be a compatibility shim if MPI is not ena...
Definition: timpi_init.h:100

Member Function Documentation

◆ comm() [1/2]

const Communicator& TIMPI::TIMPIInit::comm ( ) const
inline

Returns the Communicator created by this object, which will be a compatibility shim if MPI is not enabled, or a wrapper for the user-input MPI_Comm if we were constructed with one, or a wrapper for MPI_COMM_WORLD by default.

Definition at line 100 of file timpi_init.h.

References _comm.

Referenced by main(), and ~TIMPIInit().

100 { return *_comm; }
std::unique_ptr< Communicator > _comm
Definition: timpi_init.h:105

◆ comm() [2/2]

Communicator& TIMPI::TIMPIInit::comm ( )
inline

Definition at line 102 of file timpi_init.h.

References _comm.

102 { return *_comm; }
std::unique_ptr< Communicator > _comm
Definition: timpi_init.h:105

Member Data Documentation

◆ _comm

std::unique_ptr<Communicator> TIMPI::TIMPIInit::_comm
private

Definition at line 105 of file timpi_init.h.

Referenced by comm(), TIMPIInit(), and ~TIMPIInit().

◆ _ref

std::unique_ptr<SemiPermanent::Ref> TIMPI::TIMPIInit::_ref
private

Definition at line 108 of file timpi_init.h.

Referenced by TIMPIInit(), and ~TIMPIInit().

◆ err_handler_set

bool TIMPI::TIMPIInit::err_handler_set
private

Definition at line 114 of file timpi_init.h.

Referenced by TIMPIInit(), and ~TIMPIInit().

◆ i_initialized_mpi

bool TIMPI::TIMPIInit::i_initialized_mpi
private

Definition at line 111 of file timpi_init.h.

Referenced by TIMPIInit(), and ~TIMPIInit().

◆ my_errhandler

MPI_Errhandler TIMPI::TIMPIInit::my_errhandler
private

Definition at line 113 of file timpi_init.h.

Referenced by TIMPIInit(), and ~TIMPIInit().


The documentation for this class was generated from the following files: