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  auto result = cuDevicePrimaryCtxRelease(device_id);
52  return result;
53 }
54 
55 inline void decrease_refcount(device::id_t device_id)
56 {
57  auto status = decrease_refcount_nothrow(device_id);
58  throw_if_error_lazy(status, "Failed releasing the reference to the primary context for " + device::detail_::identify(device_id));
59 }
60 
61 inline handle_t obtain_and_increase_refcount(device::id_t device_id)
62 {
63  handle_t primary_context_handle;
64  auto status = cuDevicePrimaryCtxRetain(&primary_context_handle, device_id);
65  throw_if_error_lazy(status,
66  "Failed obtaining (and possibly creating, and adding a reference count to) the primary context for "
67  + device::detail_::identify(device_id));
68  return primary_context_handle;
69 }
70 
71 inline void increase_refcount(device::id_t device_id)
72 {
73  obtain_and_increase_refcount(device_id);
74 }
75 
76 } // namespace detail_
77 
84 inline bool is_active(const device_t& device);
85 
91 void destroy(const device_t& device);
92 
93 namespace detail_ {
94 
95 inline primary_context_t wrap(
96  device::id_t device_id,
97  context::handle_t handle,
98  bool decrease_refcount_on_destruct) noexcept;
99 
100 } // namespace detail_
101 
102 } // namespace primary_context
103 
112 class primary_context_t : public context_t {
113 
114 protected: // data members
115 
132  bool owns_refcount_unit_;
133 
134 protected: // constructors
135 
137  device::id_t device_id,
138  context::handle_t handle,
139  bool decrease_refcount_on_destruction) noexcept
140  : context_t(device_id, handle, false),
141  owns_refcount_unit_(decrease_refcount_on_destruction) { }
142  // Note we are _not_ increasing the reference count; we assume
143  // the primary context is already active. Also, like any context
144  // proxy, we are not making this context current on construction
145  // nor expecting it to be current throughout its lifetime.
146 
147 public:
148 
152  stream_t default_stream() const noexcept;
153 
154 public: // friendship
155 
156  friend class device_t;
157  friend primary_context_t device::primary_context::detail_::wrap(device::id_t, context::handle_t, bool) noexcept;
158 
159 public: // constructors and destructor
160 
162  : context_t(other), owns_refcount_unit_(other.owns_refcount_unit_)
163  {
164  if (owns_refcount_unit_) {
165  primary_context::detail_::obtain_and_increase_refcount(device_id_);
166  }
167  }
168 
169  primary_context_t(primary_context_t&& other) noexcept = default;
170 
171  ~primary_context_t() NOEXCEPT_IF_NDEBUG
172  {
173  if (owns_refcount_unit_) {
174 #ifndef NDEBUG
175  device::primary_context::detail_::decrease_refcount_nothrow(device_id_);
176  // Swallow any error to avoid termination on throwing from a dtor
177 #else
178  primary_context::detail_::decrease_refcount(device_id_);
179 #endif
180  }
181  }
182 
183 public: // operators
184 
185  primary_context_t& operator=(const primary_context_t& other) = delete;
186  primary_context_t& operator=(primary_context_t&& other) = default;
187 };
188 
189 namespace primary_context {
190 
191 namespace detail_ {
192 
193 // Note the refcount semantics here, they're a bit tricky
194 inline context::handle_t get_handle(device::id_t device_id, bool with_refcount_increase = false)
195 {
196  auto handle = obtain_and_increase_refcount(device_id);
197  if (not with_refcount_increase) {
198  decrease_refcount(device_id);
199  }
200  return handle;
201 }
202 
203 } // namespace detail_
204 
220 primary_context_t get(const device_t& device);
221 
222 namespace detail_ {
223 
231 primary_context_t leaky_get(device::id_t device_id);
232 
233 // Note that destroying the wrapped instance decreases the refcount,
234 // meaning that the handle must have been obtained with an "unmatched"
235 // refcount increase
237  id_t device_id,
238  handle_t handle,
239  bool decrease_refcount_on_destruct) noexcept
240 {
241  return {device_id, handle, decrease_refcount_on_destruct};
242 }
243 
244 } // namespace detail_
245 
246 
247 
248 } // namespace primary_context
249 } // namespace device
250 
251 namespace context {
252 
253 namespace detail_ {
254 
264 bool is_primary_for_device(handle_t handle, device::id_t device_id);
265 
266 handle_t get_primary_for_same_device(handle_t handle, bool assume_active = false);
267 
268 
269 inline bool is_primary(handle_t handle)
270 {
271  return is_primary_for_device(handle, get_device_id(handle));
272 }
273 
274 } // namespace detail_
275 
276 } // namespace context
277 
278 namespace device {
279 
280 namespace primary_context {
281 
282 namespace detail_ {
283 
284 inline bool is_current(device::id_t device_id)
285 {
286  auto current_context = context::current::detail_::get_handle();
287  return context::detail_::is_primary_for_device(current_context, device_id);
288 }
289 
290 } // namespace detail
291 
293 inline bool is_current()
294 {
295  auto device_id = context::current::detail_::get_device_id();
296  return detail_::is_current(device_id);
297 }
298 
299 } // namespace primary_context
300 
301 } // namespace device
302 
303 } // namespace cuda
304 
305 
306 // Should we want to let the primary context reset itself? That's something which regular
307 // contexts can't do. We might preclude this, and allow it through the device_t class,
308 // instead - it already has device_t::reset(), which should be the exact same thing. We
309 // don't really care if that destroys contexts we're holding on to, because: 1. It won't
310 // cause segmentation violations - we're not dereferencing freed pointers and 2. it's the
311 // user's problem, not ours.
312 
313 
314 #endif /* CUDA_API_WRAPPERS_PRIMARY_CONTEXT_HPP_ */
Proxy class for a CUDA stream.
Definition: stream.hpp:246
Wrapper class for a CUDA context.
Definition: context.hpp:244
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:878
A class for holding the primary context of a CUDA device.
Definition: primary_context.hpp:112
CUdevice id_t
Numeric ID of a CUDA device used by the CUDA Runtime API.
Definition: types.hpp:850
void throw_if_error(status_t status, const ::std::string &message) noexcept(false)
Do nothing...
Definition: error.hpp:335
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:316
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:825
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:77