10#ifndef TPETRA_DETAILS_EXECUTIONSPACES_HPP
11#define TPETRA_DETAILS_EXECUTIONSPACES_HPP
17#include <Kokkos_Core.hpp>
19#include <Teuchos_RCP.hpp>
23#include "Tpetra_DLLExportMacro.h"
41#define TPETRA_DETAILS_SPACES_THROW(x) \
43 std::stringstream ss; \
44 ss << __FILE__ << ":" << __LINE__ << ": " << x; \
45 throw std::runtime_error(ss.str()); \
64#if defined(KOKKOS_ENABLE_CUDA)
65inline void success_or_throw(cudaError_t err,
const char *file,
67 if (err != cudaSuccess) {
69 ss << file <<
":" << line <<
": ";
70 ss << cudaGetErrorString(err);
71 throw std::runtime_error(ss.str());
74#define TPETRA_DETAILS_SPACES_CUDA_RUNTIME(x) \
75 Tpetra::Details::Spaces::success_or_throw((x), __FILE__, __LINE__)
86#if defined(KOKKOS_ENABLE_CUDA)
92 cudaEvent_t execSpaceWaitEvent_;
95 ~CudaInfo() =
default;
96 CudaInfo(
const CudaInfo &other) =
delete;
97 CudaInfo(CudaInfo &&other) =
delete;
99extern TPETRACORE_LIB_DLL_EXPORT CudaInfo cudaInfo;
103#if defined(KOKKOS_ENABLE_CUDA)
104template <
typename Space>
105using IsCuda = std::enable_if_t<std::is_same_v<Space, Kokkos::Cuda>,
bool>;
106template <
typename Space>
107using NotCuda = std::enable_if_t<!std::is_same_v<Space, Kokkos::Cuda>,
bool>;
108template <
typename S1,
typename S2>
109using BothCuda = std::enable_if_t<
110 std::is_same_v<S1, Kokkos::Cuda> && std::is_same_v<S2, Kokkos::Cuda>,
bool>;
111template <
typename S1,
typename S2>
112using NotBothCuda = std::enable_if_t<!std::is_same_v<S1, Kokkos::Cuda> ||
113 !std::is_same_v<S2, Kokkos::Cuda>,
117#if defined(KOKKOS_ENABLE_SERIAL)
119template <
typename Space>
120using IsSerial = std::enable_if_t<std::is_same_v<Space, Kokkos::Serial>,
bool>;
123#if defined(KOKKOS_ENABLE_OPENMP)
125template <
typename Space>
126using IsOpenMP = std::enable_if_t<std::is_same_v<Space, Kokkos::OpenMP>,
bool>;
129#if defined(KOKKOS_ENABLE_HIP)
131template <
typename Space>
132using IsHIP = std::enable_if_t<std::is_same_v<Space, Kokkos::HIP>,
bool>;
135#if defined(KOKKOS_ENABLE_SYCL)
137template <
typename Space>
138using IsSYCL = std::enable_if_t<std::is_same_v<Space, Kokkos::SYCL>,
bool>;
146template <
typename ExecSpace,
Priority priority = Priority::medium
147#if defined(KOKKOS_ENABLE_CUDA)
149 NotCuda<ExecSpace> =
true
162#if defined(KOKKOS_ENABLE_CUDA)
163template <
typename ExecSpace, Priority priority = Priority::medium,
164 IsCuda<ExecSpace> =
true>
165Kokkos::Cuda make_instance() {
171 prio = cudaInfo.highPrio_;
173 case Priority::medium:
174 prio = cudaInfo.mediumPrio_;
177 prio = cudaInfo.lowPrio_;
180 throw std::runtime_error(
"unexpected static Tpetra Space priority");
182 TPETRA_DETAILS_SPACES_CUDA_RUNTIME(
183 cudaStreamCreateWithPriority(&stream, cudaStreamNonBlocking, prio));
185 Kokkos::push_finalize_hook([=] {
186 if (stream !=
nullptr) {
187 TPETRA_DETAILS_SPACES_CUDA_RUNTIME(cudaStreamSynchronize(stream));
188 TPETRA_DETAILS_SPACES_CUDA_RUNTIME(cudaStreamDestroy(stream));
192 return Kokkos::Cuda(stream);
201template <
typename ExecSpace>
206 case Priority::medium:
211 throw std::runtime_error(
"unexpected dynamic Tpetra Space priority");
226template <
typename ExecSpace>
229 using execution_space = ExecSpace;
230 using rcp_type = Teuchos::RCP<const execution_space>;
238 template <Priority priority = Priority::medium>
241 "Tpetra::Details::Spaces::space_instance");
243 constexpr int p =
static_cast<int>(priority);
244 static_assert(p <
sizeof(instances) /
sizeof(instances[0]),
245 "Spaces::Priority enum error");
248 TPETRA_DETAILS_SPACES_THROW(
"requested instance id " << i <<
" (< 0)");
251 TPETRA_DETAILS_SPACES_THROW(
252 "requested instance id "
254 <<
") set by TPETRA_SPACES_ID_WARN_LIMIT");
259 while (
size_t(i) >= instances[p].size()) {
260 instances[p].push_back(Teuchos::ENull());
272 if (instances[p][i].is_null() || !instances[p][i].is_valid_ptr()) {
274 rcp_type r = Teuchos::RCP<const execution_space>(
278 instances[p][i] = r.create_weak();
284 auto r = instances[p][i].create_strong();
292 for (
int i = 0; i < static_cast<int>(Spaces::Priority::NUM_LEVELS); ++i) {
293 for (
const rcp_type &rcp : instances[i]) {
294 if (rcp.is_valid_ptr() && !rcp.is_null()) {
296 std::cerr << __FILE__ <<
":" << __LINE__
297 <<
" execution space instance survived to "
298 "~InstanceLifetimeManager. strong_count() = "
299 << rcp.strong_count()
300 <<
". Did a Tpetra object live past Kokkos::finalize()?"
309 std::vector<rcp_type>
310 instances[
static_cast<int>(Spaces::Priority::NUM_LEVELS)];
313#if defined(KOKKOS_ENABLE_CUDA)
314extern TPETRACORE_LIB_DLL_EXPORT InstanceLifetimeManager<Kokkos::Cuda> cudaSpaces;
316#if defined(KOKKOS_ENABLE_SERIAL)
317extern TPETRACORE_LIB_DLL_EXPORT InstanceLifetimeManager<Kokkos::Serial> serialSpaces;
319#if defined(KOKKOS_ENABLE_OPENMP)
320extern TPETRACORE_LIB_DLL_EXPORT InstanceLifetimeManager<Kokkos::OpenMP> openMPSpaces;
322#if defined(KOKKOS_ENABLE_HIP)
323extern TPETRACORE_LIB_DLL_EXPORT InstanceLifetimeManager<Kokkos::HIP> HIPSpaces;
325#if defined(KOKKOS_ENABLE_SYCL)
326extern TPETRACORE_LIB_DLL_EXPORT InstanceLifetimeManager<Kokkos::SYCL> SYCLSpaces;
329#if defined(KOKKOS_ENABLE_CUDA)
334template <
typename ExecSpace, Priority priority = Priority::medium,
335 IsCuda<ExecSpace> =
true>
336Teuchos::RCP<const ExecSpace> space_instance(
int i = 0) {
337 return cudaSpaces.space_instance<priority>(i);
341#if defined(KOKKOS_ENABLE_SERIAL)
345template <
typename ExecSpace, Priority priority = Priority::medium,
346 IsSerial<ExecSpace> =
true>
347Teuchos::RCP<const ExecSpace> space_instance(
int i = 0) {
348 return serialSpaces.space_instance<priority>(i);
352#if defined(KOKKOS_ENABLE_OPENMP)
356template <
typename ExecSpace, Priority priority = Priority::medium,
357 IsOpenMP<ExecSpace> =
true>
358Teuchos::RCP<const ExecSpace> space_instance(
int i = 0) {
359 return openMPSpaces.space_instance<priority>(i);
363#if defined(KOKKOS_ENABLE_HIP)
366template <
typename ExecSpace,
Priority priority = Priority::medium,
367 IsHIP<ExecSpace> =
true>
369 return HIPSpaces.space_instance<priority>(i);
372#if defined(KOKKOS_ENABLE_SYCL)
376template <
typename ExecSpace,
Priority priority = Priority::medium,
377 IsSYCL<ExecSpace> =
true>
379 return SYCLSpaces.space_instance<priority>(i);
389template <
typename ExecSpace>
395 case Priority::medium:
400 throw std::runtime_error(
401 "unexpected dynamic Tpetra Space priority in space_instance");
418template <
typename S1,
typename S2
419#if defined(KOKKOS_ENABLE_CUDA)
421 NotBothCuda<S1, S2> =
true
426 "Tpetra::Details::Spaces::exec_space_wait");
431#if defined(KOKKOS_ENABLE_CUDA)
432template <
typename S1,
typename S2, BothCuda<S1, S2> = true>
433void exec_space_wait(
const char *msg,
const S1 &waitee,
const S2 &waiter) {
435 "Tpetra::Details::Spaces::exec_space_wait");
439 if (waitee.impl_instance_id() !=
441 .impl_instance_id()) {
446 TPETRA_DETAILS_SPACES_CUDA_RUNTIME(
447 cudaEventRecord(cudaInfo.execSpaceWaitEvent_, waitee.cuda_stream()));
448 TPETRA_DETAILS_SPACES_CUDA_RUNTIME(cudaStreamWaitEvent(
449 waiter.cuda_stream(), cudaInfo.execSpaceWaitEvent_, 0 ));
454template <
typename S1,
typename S2>
455void exec_space_wait(
const S1 &waitee,
const S2 &waiter) {
457 "Tpetra::Details::Spaces::exec_space_wait");
459 exec_space_wait(
"anonymous", waitee, waiter);
462template <
typename ExecutionSpace>
463constexpr KOKKOS_INLINE_FUNCTION
bool is_gpu_exec_space() {
467#if defined(KOKKOS_ENABLE_CUDA)
469constexpr KOKKOS_INLINE_FUNCTION
bool is_gpu_exec_space<Kokkos::Cuda>() {
474#if defined(KOKKOS_ENABLE_HIP)
476constexpr KOKKOS_INLINE_FUNCTION
bool
477is_gpu_exec_space<Kokkos::HIP>() {
482#if defined(KOKKOS_ENABLE_SYCL)
484constexpr KOKKOS_INLINE_FUNCTION
bool
485is_gpu_exec_space<Kokkos::SYCL>() {
494#undef TPETRA_DETAILS_SPACES_THROW
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.
void exec_space_wait(const char *msg, const S1 &waitee, const S2 &)
cause future work submitted to waiter to wait for the current work in waitee to finish
ExecSpace make_instance()
Construct a Kokkos execution space instance with the following priority.
Teuchos::RCP< const ExecSpace > space_instance(const Priority &priority, int i=0)
get a strong Teuchos::RCP to Tpetra-managed Kokkos execution space instance
Priority
Priority interface for Tpetra's managed execution spaces.
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.
Provides reusable Kokkos execution space instances.
~InstanceLifetimeManager()
Issue a warning if any Tpetra-managed execution space instances survive to the end of static lifetime...
rcp_type space_instance(int i=0)
Retrieve a strong Teuchos::RCP<const ExecSpace> to instance i.
Nonmember function that computes a residual Computes R = B - A * X.
Namespace Tpetra contains the class and methods constituting the Tpetra library.