10 #ifndef TPETRA_DETAILS_EXECUTIONSPACES_HPP
11 #define TPETRA_DETAILS_EXECUTIONSPACES_HPP
17 #include <Kokkos_Core.hpp>
19 #include <Teuchos_RCP.hpp>
40 #define TPETRA_DETAILS_SPACES_THROW(x) \
42 std::stringstream ss; \
43 ss << __FILE__ << ":" << __LINE__ << ": " << x; \
44 throw std::runtime_error(ss.str()); \
63 #if defined(KOKKOS_ENABLE_CUDA)
64 inline void success_or_throw(cudaError_t err,
const char *file,
66 if (err != cudaSuccess) {
68 ss << file <<
":" << line <<
": ";
69 ss << cudaGetErrorString(err);
70 throw std::runtime_error(ss.str());
73 #define TPETRA_DETAILS_SPACES_CUDA_RUNTIME(x) \
74 Tpetra::Details::Spaces::success_or_throw((x), __FILE__, __LINE__)
75 #endif // KOKKOS_ENABLE_CUDA
85 #if defined(KOKKOS_ENABLE_CUDA)
91 cudaEvent_t execSpaceWaitEvent_;
94 ~CudaInfo() =
default;
95 CudaInfo(
const CudaInfo &other) =
delete;
96 CudaInfo(CudaInfo &&other) =
delete;
98 extern CudaInfo cudaInfo;
99 #endif // KOKKOS_ENABLE_CUDA
102 #if defined(KOKKOS_ENABLE_CUDA)
103 template <
typename Space>
104 using IsCuda = std::enable_if_t<std::is_same_v<Space, Kokkos::Cuda>,
bool>;
105 template <
typename Space>
106 using NotCuda = std::enable_if_t<!std::is_same_v<Space, Kokkos::Cuda>,
bool>;
107 template <
typename S1,
typename S2>
108 using BothCuda = std::enable_if_t<
109 std::is_same_v<S1, Kokkos::Cuda> && std::is_same_v<S2, Kokkos::Cuda>,
bool>;
110 template <
typename S1,
typename S2>
111 using NotBothCuda = std::enable_if_t<!std::is_same_v<S1, Kokkos::Cuda> ||
112 !std::is_same_v<S2, Kokkos::Cuda>,
114 #endif // KOKKOS_ENABLE_CUDA
116 #if defined(KOKKOS_ENABLE_SERIAL)
117 template <
typename Space>
119 using IsSerial = std::enable_if_t<std::is_same_v<Space, Kokkos::Serial>,
bool>;
120 #endif // KOKKOS_ENABLE_SERIAL
122 #if defined(KOKKOS_ENABLE_OPENMP)
123 template <
typename Space>
125 using IsOpenMP = std::enable_if_t<std::is_same_v<Space, Kokkos::OpenMP>,
bool>;
126 #endif // KOKKOS_ENABLE_OPENMP
128 #if defined(KOKKOS_ENABLE_HIP)
129 template <
typename Space>
131 using IsHIP = std::enable_if_t<std::is_same_v<Space, Kokkos::HIP>,
bool>;
132 #endif // KOKKOS_ENABLE_HIP
134 #if defined(KOKKOS_ENABLE_SYCL)
135 template <
typename Space>
137 using IsSYCL = std::enable_if_t<std::is_same_v<Space, Kokkos::Experimental::SYCL>,
bool>;
138 #endif // KOKKOS_ENABLE_SYCL
145 template <
typename ExecSpace, Priority priority = Priority::medium
146 #if defined(KOKKOS_ENABLE_CUDA)
148 NotCuda<ExecSpace> =
true
149 #endif // KOKKOS_ENABLE_CUDA
151 ExecSpace make_instance() {
161 #if defined(KOKKOS_ENABLE_CUDA)
162 template <
typename ExecSpace, Priority priority = Priority::medium,
163 IsCuda<ExecSpace> =
true>
164 Kokkos::Cuda make_instance() {
170 prio = cudaInfo.highPrio_;
172 case Priority::medium:
173 prio = cudaInfo.mediumPrio_;
176 prio = cudaInfo.lowPrio_;
179 throw std::runtime_error(
"unexpected static Tpetra Space priority");
181 TPETRA_DETAILS_SPACES_CUDA_RUNTIME(
182 cudaStreamCreateWithPriority(&stream, cudaStreamNonBlocking, prio));
183 return Kokkos::Cuda(stream,
true );
185 #endif // KOKKOS_ENABLE_CUDA
192 template <
typename ExecSpace>
193 ExecSpace make_instance(
const Priority &prio) {
196 return make_instance<ExecSpace, Priority::high>();
197 case Priority::medium:
198 return make_instance<ExecSpace, Priority::medium>();
200 return make_instance<ExecSpace, Priority::low>();
202 throw std::runtime_error(
"unexpected dynamic Tpetra Space priority");
217 template <
typename ExecSpace>
220 using execution_space = ExecSpace;
221 using rcp_type = Teuchos::RCP<const execution_space>;
229 template <Priority priority = Priority::medium>
232 "Tpetra::Details::Spaces::space_instance");
234 constexpr
int p =
static_cast<int>(priority);
235 static_assert(p <
sizeof(instances) /
sizeof(instances[0]),
236 "Spaces::Priority enum error");
239 TPETRA_DETAILS_SPACES_THROW(
"requested instance id " << i <<
" (< 0)");
242 TPETRA_DETAILS_SPACES_THROW(
243 "requested instance id "
245 <<
") set by TPETRA_SPACES_ID_WARN_LIMIT");
250 while (
size_t(i) >= instances[p].size()) {
251 instances[p].push_back(Teuchos::ENull());
263 if (instances[p][i].is_null() || !instances[p][i].is_valid_ptr()) {
265 rcp_type r = Teuchos::RCP<const execution_space>(
266 new ExecSpace(make_instance<ExecSpace, priority>()));
269 instances[p][i] = r.create_weak();
275 auto r = instances[p][i].create_strong();
283 for (
int i = 0; i < static_cast<int>(Spaces::Priority::NUM_LEVELS); ++i) {
284 for (
const rcp_type &rcp : instances[i]) {
285 if (rcp.is_valid_ptr() && !rcp.is_null()) {
287 std::cerr << __FILE__ <<
":" << __LINE__
288 <<
" execution space instance survived to "
289 "~InstanceLifetimeManager. strong_count() = "
290 << rcp.strong_count()
291 <<
". Did a Tpetra object live past Kokkos::finalize()?"
300 std::vector<rcp_type>
301 instances[
static_cast<int>(Spaces::Priority::NUM_LEVELS)];
304 #if defined(KOKKOS_ENABLE_CUDA)
305 extern InstanceLifetimeManager<Kokkos::Cuda> cudaSpaces;
307 #if defined(KOKKOS_ENABLE_SERIAL)
308 extern InstanceLifetimeManager<Kokkos::Serial> serialSpaces;
310 #if defined(KOKKOS_ENABLE_OPENMP)
311 extern InstanceLifetimeManager<Kokkos::OpenMP> openMPSpaces;
313 #if defined(KOKKOS_ENABLE_HIP)
314 extern InstanceLifetimeManager<Kokkos::HIP> HIPSpaces;
316 #if defined(KOKKOS_ENABLE_SYCL)
317 extern InstanceLifetimeManager<Kokkos::Experimental::SYCL> SYCLSpaces;
320 #if defined(KOKKOS_ENABLE_CUDA)
325 template <
typename ExecSpace, Priority priority = Priority::medium,
326 IsCuda<ExecSpace> =
true>
327 Teuchos::RCP<const ExecSpace> space_instance(
int i = 0) {
328 return cudaSpaces.space_instance<priority>(i);
332 #if defined(KOKKOS_ENABLE_SERIAL)
336 template <
typename ExecSpace, Priority priority = Priority::medium,
337 IsSerial<ExecSpace> =
true>
338 Teuchos::RCP<const ExecSpace> space_instance(
int i = 0) {
339 return serialSpaces.space_instance<priority>(i);
343 #if defined(KOKKOS_ENABLE_OPENMP)
347 template <
typename ExecSpace, Priority priority = Priority::medium,
348 IsOpenMP<ExecSpace> =
true>
349 Teuchos::RCP<const ExecSpace> space_instance(
int i = 0) {
350 return openMPSpaces.space_instance<priority>(i);
354 #if defined(KOKKOS_ENABLE_HIP)
357 template <
typename ExecSpace, Priority priority = Priority::medium,
358 IsHIP<ExecSpace> =
true>
359 Teuchos::RCP<const ExecSpace> space_instance(
int i = 0) {
360 return HIPSpaces.space_instance<priority>(i);
363 #if defined(KOKKOS_ENABLE_SYCL)
367 template <
typename ExecSpace, Priority priority = Priority::medium,
368 IsSYCL<ExecSpace> =
true>
369 Teuchos::RCP<const ExecSpace> space_instance(
int i = 0) {
370 return SYCLSpaces.space_instance<priority>(i);
379 template <
typename ExecSpace>
380 Teuchos::RCP<const ExecSpace> space_instance(
const Priority &priority,
384 return space_instance<ExecSpace, Priority::high>(i);
385 case Priority::medium:
386 return space_instance<ExecSpace, Priority::medium>(i);
388 return space_instance<ExecSpace, Priority::low>(i);
390 throw std::runtime_error(
391 "unexpected dynamic Tpetra Space priority in space_instance");
408 template <
typename S1,
typename S2
409 #if defined(KOKKOS_ENABLE_CUDA)
411 NotBothCuda<S1, S2> =
true
414 void exec_space_wait(
const char *msg,
const S1 &waitee,
const S2 & ) {
416 "Tpetra::Details::Spaces::exec_space_wait");
421 #if defined(KOKKOS_ENABLE_CUDA)
422 template <
typename S1,
typename S2, BothCuda<S1, S2> = true>
423 void exec_space_wait(
const char *msg,
const S1 &waitee,
const S2 &waiter) {
425 "Tpetra::Details::Spaces::exec_space_wait");
429 if (waitee.impl_instance_id() !=
431 .impl_instance_id()) {
436 TPETRA_DETAILS_SPACES_CUDA_RUNTIME(
437 cudaEventRecord(cudaInfo.execSpaceWaitEvent_, waitee.cuda_stream()));
438 TPETRA_DETAILS_SPACES_CUDA_RUNTIME(cudaStreamWaitEvent(
439 waiter.cuda_stream(), cudaInfo.execSpaceWaitEvent_, 0 ));
444 template <
typename S1,
typename S2>
445 void exec_space_wait(
const S1 &waitee,
const S2 &waiter) {
447 "Tpetra::Details::Spaces::exec_space_wait");
449 exec_space_wait(
"anonymous", waitee, waiter);
452 template <
typename ExecutionSpace>
453 constexpr KOKKOS_INLINE_FUNCTION
bool is_gpu_exec_space() {
457 #if defined(KOKKOS_ENABLE_CUDA)
459 constexpr KOKKOS_INLINE_FUNCTION
bool is_gpu_exec_space<Kokkos::Cuda>() {
464 #if defined(KOKKOS_ENABLE_HIP)
466 constexpr KOKKOS_INLINE_FUNCTION
bool
467 is_gpu_exec_space<Kokkos::HIP>() {
472 #if defined(KOKKOS_ENABLE_SYCL)
474 constexpr KOKKOS_INLINE_FUNCTION
bool
475 is_gpu_exec_space<Kokkos::Experimental::SYCL>() {
484 #undef TPETRA_DETAILS_SPACES_THROW
486 #endif // TPETRA_DETAILS_EXECUTIONSPACES_HPP
Declaration of Tpetra::Details::Profiling, a scope guard for Kokkos Profiling.
static size_t spacesIdWarnLimit()
Warn if more than this many Kokkos spaces are accessed.
rcp_type space_instance(int i=0)
Retrieve a strong Teuchos::RCP<const ExecSpace> to instance i
~InstanceLifetimeManager()
Issue a warning if any Tpetra-managed execution space instances survive to the end of static lifetime...
Provides reusable Kokkos execution space instances.
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.