Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_Core.cpp
1// @HEADER
2// *****************************************************************************
3// Tpetra: Templated Linear Algebra Services Package
4//
5// Copyright 2008 NTESS and the Tpetra contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#include "Tpetra_Core.hpp"
11#include "Tpetra_Details_mpiIsInitialized.hpp"
12
13#ifdef HAVE_TPETRACORE_MPI
14#include <Teuchos_DefaultMpiComm.hpp> // this includes mpi.h too
15#endif // HAVE_TPETRACORE_MPI
16#include <Teuchos_DefaultSerialComm.hpp>
17
18#include <Kokkos_Core.hpp>
19#include "Tpetra_Details_checkLaunchBlocking.hpp"
22#include "KokkosKernels_EagerInitialize.hpp"
24
25namespace Tpetra {
26
27namespace { // (anonymous)
28
29#if defined(HAVE_TPETRACORE_MPI)
30bool mpiIsInitializedAndNotFinalized() {
31 int isInitialized = 0;
32 int isFinalized = 0;
33 // Not sure if MPI_Initialized or MPI_Finalized meet the strong
34 // exception guarantee.
35 try {
36 (void)MPI_Initialized(&isInitialized);
37 } catch (...) {
38 isInitialized = 0;
39 }
40 try {
41 (void)MPI_Finalized(&isFinalized);
42 } catch (...) {
43 isFinalized = 0;
44 }
45 return isInitialized != 0 && isFinalized == 0;
46}
47#endif // defined(HAVE_TPETRACORE_MPI)
48
49// Whether one of the Tpetra::initialize() functions has been called before.
50bool tpetraIsInitialized_ = false;
51
52// Whether Tpetra initialized Kokkos. Tpetra::finalize only
53// finalizes Kokkos if it initialized Kokkos. Otherwise,
54// something else initialized Kokkos and is responsible for
55// finalizing it.
56bool tpetraInitializedKokkos_ = false;
57
58#ifdef HAVE_TPETRACORE_MPI
59// Whether Tpetra initialized MPI. Tpetra::finalize only
60// finalizes MPI if it initialized MPI. Otherwise, something else
61// initialized MPI and is responsible for finalizing it.
62bool tpetraInitializedMpi_ = false;
63#endif // HAVE_TPETRACORE_MPI
64
65// Tpetra's default communicator, wrapped in a Teuchos wrapper.
66// After Tpetra::finalize() is called, this GOES AWAY (is set to null).
67Teuchos::RCP<const Teuchos::Comm<int> > wrappedDefaultComm_;
68
69#ifdef HAVE_TPETRACORE_MPI
70
71int getRankHarmlessly(MPI_Comm comm) {
72 int myRank = 0;
73 if (mpiIsInitializedAndNotFinalized()) {
74 try {
75 (void)MPI_Comm_rank(comm, &myRank);
76 } catch (...) {
77 // Not sure if MPI_Comm_rank meets strong exception guarantee
78 myRank = 0;
79 }
80 }
81 return myRank;
82}
83
84// This takes the same arguments as MPI_Init and the first two
85// arguments of initialize().
86void initMpiIfNeeded(int* argc, char*** argv) {
87 // Both MPI_Initialized and MPI_Finalized report true after
88 // MPI_Finalize has been called. It's not legal to call
89 // MPI_Init after MPI_Finalize has been called (see MPI 3.0
90 // Standard, Section 8.7). It would be unusual for users to
91 // want to use Tpetra after MPI_Finalize has been called, but
92 // there's no reason why we should forbid it. It just means
93 // that Tpetra will need to run without MPI.
94
95 const bool mpiReady = mpiIsInitializedAndNotFinalized();
96 if (!mpiReady) {
97 // Tpetra doesn't currently need to call MPI_Init_thread,
98 // since with Tpetra, only one thread ever calls MPI
99 // functions. If we ever want to explore
100 // MPI_THREAD_MULTIPLE, here would be the place to call
101 // MPI_Init_thread.
102 const int err = MPI_Init(argc, argv);
103 TEUCHOS_TEST_FOR_EXCEPTION(err != MPI_SUCCESS, std::runtime_error,
104 "MPI_Init failed with "
105 "error code "
106 << err << " != MPI_SUCCESS. If MPI was set up "
107 "correctly, then this should not happen, since we have already "
108 "checked that MPI_Init (or MPI_Init_thread) has not yet been "
109 "called. This may indicate that your MPI library is corrupted "
110 "or that it is incorrectly linked to your program.");
111 tpetraInitializedMpi_ = true;
112 }
113}
114#endif // HAVE_TPETRACORE_MPI
115
116} // namespace
117
120}
121
122Teuchos::RCP<const Teuchos::Comm<int> > getDefaultComm() {
123 // It's technically not correct to call this function if Tpetra
124 // has not yet been initialized, but requiring that may break some
125 // downstream tests.
126 //
127 // This function initializes wrappedDefaultComm_ lazily.
128 // Tpetra::initialize should not set it up.
129 if (wrappedDefaultComm_.is_null()) {
130 Teuchos::RCP<const Teuchos::Comm<int> > comm;
131#ifdef HAVE_TPETRACORE_MPI
132 // Teuchos::MpiComm's constructor used to invoke MPI collectives.
133 // It still reserves the right to do so. This means MPI must be
134 // initialized and not finalized.
136 if (mpiReady) {
137 comm = Teuchos::rcp(new Teuchos::MpiComm<int>(MPI_COMM_WORLD));
138 } else {
139 comm = Teuchos::rcp(new Teuchos::SerialComm<int>());
140 }
141#else
142 comm = Teuchos::rcp(new Teuchos::SerialComm<int>());
143#endif // HAVE_TPETRACORE_MPI
144 wrappedDefaultComm_ = comm;
145 }
146 return wrappedDefaultComm_;
147}
148
149void initialize(int* argc, char*** argv) {
151#if defined(HAVE_TPETRACORE_MPI)
153#endif // defined(HAVE_TPETRACORE_MPI)
154
155 // Initialize Kokkos using the new function
156 if (!Kokkos::is_initialized()) {
159 }
160
162 }
164}
165
166#ifdef HAVE_TPETRACORE_MPI
167void initialize(int* argc, char*** argv, MPI_Comm comm) {
168 if (!tpetraIsInitialized_) {
169#if defined(HAVE_TPETRACORE_MPI)
170 initMpiIfNeeded(argc, argv);
171 // It's technically legal to initialize Tpetra after
172 // MPI_Finalize has been called. This means that we can't call
173 // MPI_Comm_rank without first checking MPI_Finalized.
174 const int myRank = getRankHarmlessly(comm);
175#else
176 const int myRank = 0;
177#endif // defined(HAVE_TPETRACORE_MPI)
178
179 // Initialize Kokkos using the new function
180 if (!Kokkos::is_initialized()) {
181 Tpetra::Details::initializeKokkos(argc, argv, myRank);
182 tpetraInitializedKokkos_ = true;
183 }
184
186 }
187 tpetraIsInitialized_ = true;
188
189 // Set the default communicator. We set it here, after the above
190 // initialize() call, just in case users have not yet initialized
191 // MPI. (This is legal if users pass in a predefined
192 // communicator, like MPI_COMM_WORLD or MPI_COMM_SELF.)
193 //
194 // What if users have already called initialize() before, but with
195 // a different default communicator? There are two possible
196 // things we could do here:
197 //
198 // 1. Test via MPI_Comm_compare whether comm differs from the
199 // raw MPI communicator in wrappedDefaultComm_ (if indeed it
200 // is an MpiComm).
201 // 2. Accept that the user might want to change the default
202 // communicator, and let them do it.
203 //
204 // I prefer #2. Perhaps it would be sensible to print a warning
205 // here, but on which process? Would we use the old or the new
206 // communicator to find that process' rank? We don't want to use
207 // MPI_COMM_WORLD's Process 0, since neither communicator might
208 // include that process. Furthermore, in some environments, only
209 // Process 0 in MPI_COMM_WORLD is allowed to do I/O. Thus, we
210 // just let the change go without a warning.
211 wrappedDefaultComm_ = Teuchos::rcp(new Teuchos::MpiComm<int>(comm));
212}
213#endif // HAVE_TPETRACORE_MPI
214
215void initialize(int* argc, char*** argv,
216 const Teuchos::RCP<const Teuchos::Comm<int> >& comm) {
218#if defined(HAVE_TPETRACORE_MPI)
220#endif // defined(HAVE_TPETRACORE_MPI)
221
222 // Initialize Kokkos using the new function
223 if (!Kokkos::is_initialized()) {
224 Tpetra::Details::initializeKokkos(argc, argv, !comm.is_null() ? comm->getRank() : 0);
226 }
227
229 }
231 wrappedDefaultComm_ = comm;
232}
233
234void finalize() {
236 return; // user didn't call initialize(), so do nothing at all
237 }
238
239 // Tpetra should only finalize Kokkos if it initialized Kokkos.
240 // See Github Issue #434.
241 // Note: Kokkos finalization is now handled by the atexit hook set up in
242 // Tpetra::Details::initializeKokkos(), so we don't need to call it here.
243 // The atexit hook ensures Kokkos::finalize() is called automatically.
244
245 // Make sure that no outstanding references to the communicator
246 // remain. If users gave initialize() an MPI_Comm, _they_ are
247 // responsible for freeing it before calling finalize().
248 wrappedDefaultComm_ = Teuchos::null;
249
250#ifdef HAVE_TPETRACORE_MPI
251 // Tpetra should only finalize MPI if it initialized MPI.
252 // See Github Issue #434.
254 // finalize() is a kind of destructor, so it's a bad idea to
255 // throw an exception on error. MPI implementations do have
256 // the option to throw on error, so let's catch that here.
257 try {
259 // This must be called by the same thread that called
260 // MPI_Init or MPI_Init_thread (possibly, but not
261 // necessarily, in Tpetra::initialize()).
263 }
264 } catch (...) {
265 }
266 }
267#endif // HAVE_TPETRACORE_MPI
268
269 tpetraIsInitialized_ = false; // it's not anymore.
270}
271
275
276#ifdef HAVE_TPETRA_MPI
277ScopeGuard::ScopeGuard(int* argc, char*** argv, MPI_Comm comm) {
279}
280#endif // HAVE_TPETRA_MPI
281
285
286} // namespace Tpetra
Functions for initializing and finalizing Tpetra.
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.
Declaration functions that use Kokkos' profiling library to add deep copies between memory spaces,...
Declaration of Tpetra::Details::initializeKokkos.
Struct that holds views of the contents of a CrsMatrix.
static void reject_unrecognized_env_vars()
Search the environment for TPETRA_ variables and reject unrecognized ones.
ScopeGuard()=delete
Default constructor (FORBIDDEN)
~ScopeGuard()
Finalize Tpetra.
bool mpiIsInitialized()
Has MPI_Init been called (on this process)?
void initializeKokkos(int *argc, char ***argv, int myRank)
Initialize Kokkos, using command-line arguments (if any) given to Teuchos::GlobalMPISession.
Namespace Tpetra contains the class and methods constituting the Tpetra library.
void initialize(int *argc, char ***argv)
Initialize Tpetra.
bool isInitialized()
Whether Tpetra is in an initialized state.
void finalize()
Finalize Tpetra.
Teuchos::RCP< const Teuchos::Comm< int > > getDefaultComm()
Get Tpetra's default communicator.