cuda-api-wrappers
Thin C++-flavored wrappers for the CUDA Runtime API
primary_context.hpp
Go to the documentation of this file.
1 
5 #ifndef CUDA_API_WRAPPERS_PRIMARY_CONTEXT_HPP_
6 #define CUDA_API_WRAPPERS_PRIMARY_CONTEXT_HPP_
7 
8 #include "current_context.hpp"
9 #include "context.hpp" // A primary context is a context, so can't avoid this
10 
11 namespace cuda {
12 
13 namespace device {
14 
16 class primary_context_t;
18 
19 namespace primary_context {
20 
21 namespace detail_ {
22 
23 struct state_t {
24  context::flags_t flags;
25  int is_active; // non-zero value means true
26 };
27 
28 inline state_t raw_state(device::id_t device_id)
29 {
30  state_t result;
31  auto status = cuDevicePrimaryCtxGetState(device_id, &result.flags, &result.is_active);
32  throw_if_error(status, "Failed obtaining the state of the primary context for "
33  + device::detail_::identify(device_id));
34  // Note: Not sanitizing the flags from having CU_CTX_MAP_HOST set
35  return result;
36 }
37 
38 inline context::flags_t flags(device::id_t device_id)
39 {
40  return raw_state(device_id).flags & ~CU_CTX_MAP_HOST;
41 }
42 
43 inline bool is_active(device::id_t device_id)
44 {
45  return raw_state(device_id).is_active;
46 }
47 
48 // We used this wrapper for a one-linear to track PC releases
49 inline status_t decrease_refcount_nothrow(device::id_t device_id) noexcept
50 {
51  return cuDevicePrimaryCtxRelease(device_id);
52 }
53 
54 inline void decrease_refcount(device::id_t device_id)
55 {
56  auto status = decrease_refcount_nothrow(device_id);
57  throw_if_error_lazy(status, "Failed releasing the reference to the primary context for " + device::detail_::identify(device_id));
58 }
59 
60 // Use this in destructors whose throwing behavior is controlled by the
61 // preprocessor definition THROW_IN_DESTRUCTORS
62 inline void decrease_refcount_in_dtor(device::id_t device_id) noexcept
63 {
64 #if THROW_IN_DESTRUCTORS
65  decrease_refcount(device_id);
66 #else
67  decrease_refcount_nothrow(device_id);
68 #endif
69 }
70 
71 inline handle_t obtain_and_increase_refcount(device::id_t device_id)
72 {
73  handle_t primary_context_handle;
74  auto status = cuDevicePrimaryCtxRetain(&primary_context_handle, device_id);
75  throw_if_error_lazy(status,
76  "Failed obtaining (and possibly creating, and adding a reference count to) the primary context for "
77  + device::detail_::identify(device_id));
78  return primary_context_handle;
79 }
80 
81 inline void increase_refcount(device::id_t device_id)
82 {
83  obtain_and_increase_refcount(device_id);
84 }
85 
86 } // namespace detail_
87 
94 inline bool is_active(const device_t& device);
95 
101 void destroy(const device_t& device);
102 
103 namespace detail_ {
104 
105 inline primary_context_t wrap(
106  device::id_t device_id,
107  context::handle_t handle,
108  bool decrease_refcount_on_destruct) noexcept;
109 
110 } // namespace detail_
111 
112 } // namespace primary_context
113 
122 class primary_context_t : public context_t {
123 
124 protected: // data members
125 
142  bool owns_refcount_unit_;
143 
144 protected: // constructors
145 
147  device::id_t device_id,
148  context::handle_t handle,
149  bool decrease_refcount_on_destruction) noexcept
150  : context_t(device_id, handle, false),
151  owns_refcount_unit_(decrease_refcount_on_destruction) { }
152  // Note we are _not_ increasing the reference count; we assume
153  // the primary context is already active. Also, like any context
154  // proxy, we are not making this context current on construction
155  // nor expecting it to be current throughout its lifetime.
156 
157 public:
158 
162  stream_t default_stream() const noexcept;
163 
164 public: // friendship
165 
166  friend class ::cuda::device_t;
167  friend primary_context_t device::primary_context::detail_::wrap(device::id_t, context::handle_t, bool) noexcept;
168 
169 public: // constructors and destructor
170 
172  : context_t(other), owns_refcount_unit_(other.owns_refcount_unit_)
173  {
174  if (owns_refcount_unit_) {
175  primary_context::detail_::obtain_and_increase_refcount(device_id_);
176  }
177  }
178 
179  primary_context_t(primary_context_t&& other) noexcept = default;
180 
181  ~primary_context_t() DESTRUCTOR_EXCEPTION_SPEC
182  {
183  if (owns_refcount_unit_) {
184  primary_context::detail_::decrease_refcount_in_dtor(device_id_);
185  }
186  }
187 
188 public: // operators
189 
190  primary_context_t& operator=(const primary_context_t& other) = delete;
191  primary_context_t& operator=(primary_context_t&& other) = default;
192 };
193 
194 namespace primary_context {
195 
196 namespace detail_ {
197 
198 // Note the refcount semantics here, they're a bit tricky
199 inline context::handle_t get_handle(device::id_t device_id, bool with_refcount_increase = false)
200 {
201  auto handle = obtain_and_increase_refcount(device_id);
202  if (not with_refcount_increase) {
203  decrease_refcount(device_id);
204  }
205  return handle;
206 }
207 
208 } // namespace detail_
209 
225 primary_context_t get(const device_t& device);
226 
227 namespace detail_ {
228 
236 primary_context_t leaky_get(device::id_t device_id);
237 
238 // Note that destroying the wrapped instance decreases the refcount,
239 // meaning that the handle must have been obtained with an "unmatched"
240 // refcount increase
242  id_t device_id,
243  handle_t handle,
244  bool decrease_refcount_on_destruct) noexcept
245 {
246  return {device_id, handle, decrease_refcount_on_destruct};
247 }
248 
249 } // namespace detail_
250 
251 
252 
253 } // namespace primary_context
254 } // namespace device
255 
256 namespace context {
257 
258 namespace detail_ {
259 
269 bool is_primary_for_device(handle_t handle, device::id_t device_id);
270 
271 handle_t get_primary_for_same_device(handle_t handle, bool assume_active = false);
272 
273 
274 inline bool is_primary(handle_t handle)
275 {
276  return is_primary_for_device(handle, get_device_id(handle));
277 }
278 
279 } // namespace detail_
280 
281 } // namespace context
282 
283 namespace device {
284 
285 namespace primary_context {
286 
287 namespace detail_ {
288 
289 inline bool is_current(device::id_t device_id)
290 {
291  auto current_context = context::current::detail_::get_handle();
292  return context::detail_::is_primary_for_device(current_context, device_id);
293 }
294 
295 } // namespace detail
296 
298 inline bool is_current()
299 {
300  auto device_id = context::current::detail_::get_device_id();
301  return detail_::is_current(device_id);
302 }
303 
304 } // namespace primary_context
305 
306 } // namespace device
307 
308 } // namespace cuda
309 
310 
311 // Should we want to let the primary context reset itself? That's something which regular
312 // contexts can't do. We might preclude this, and allow it through the device_t class,
313 // instead - it already has device_t::reset(), which should be the exact same thing. We
314 // don't really care if that destroys contexts we're holding on to, because: 1. It won't
315 // cause segmentation violations - we're not dereferencing freed pointers and 2. it's the
316 // user's problem, not ours.
317 
318 
319 #endif /* CUDA_API_WRAPPERS_PRIMARY_CONTEXT_HPP_ */
Proxy class for a CUDA stream.
Definition: stream.hpp:258
Wrapper class for a CUDA context.
Definition: context.hpp:249
Definitions and functionality wrapping CUDA APIs.
Definition: array.hpp:22
CUcontext handle_t
Raw CUDA driver handle for a context; see {context_t}.
Definition: types.hpp:880
A class for holding the primary context of a CUDA device.
Definition: primary_context.hpp:122
CUdevice id_t
Numeric ID of a CUDA device used by the CUDA Runtime API.
Definition: types.hpp:852
void throw_if_error(status_t status, const ::std::string &message) noexcept(false)
Do nothing...
Definition: error.hpp:346
Contains a proxy class for CUDA execution contexts.
#define throw_if_error_lazy(status__,...)
A macro for only throwing an error if we've failed - which also ensures no string is constructed unle...
Definition: error.hpp:327
CUarray handle_t
Raw CUDA driver handle for arrays (of any dimension)
Definition: array.hpp:34
device_t wrap(id_t id) NOEXCEPT_IF_NDEBUG
Returns a wrapper for the CUDA device with a given id.
Definition: device.hpp:820
bool is_active(const device_t &device)
Definition: device.hpp:34
Wrapper class for a CUDA device.
Definition: device.hpp:135
CUresult status_t
Indicates either the result (success or error index) of a CUDA Runtime or Driver API call...
Definition: types.hpp:74