cuda-api-wrappers
Thin C++-flavored wrappers for the CUDA Runtime API
devices.hpp
Go to the documentation of this file.
1 
6 #pragma once
7 #ifndef CUDA_API_WRAPPERS_DEVICES_HPP_
8 #define CUDA_API_WRAPPERS_DEVICES_HPP_
9 
10 #include "device.hpp"
11 
12 namespace cuda {
13 
14 namespace detail_ {
15 
16 // Note that while nothing constrains you from instantiating
17 // this class many times, all instances are the same (as CUDA
18 // devices aren't hot-pluggable).
19 class all_devices {
20 public:
21  using value_type = cuda::device_t;
22  using pointer = void; // No pointers, since we don't have any elements in actual memory
23  using const_pointer = void; // ditto
24  using reference = value_type; // device_t is already a reference type; and there is no instance-of-device_t here to reference
25  using const_reference = const value_type; // ditto
26  using size_type = decltype(device::count());
27  using difference_type = typename ::std::make_signed<size_type>::type;
28 
29  class index_based_iterator {
30  public:
31  using container = all_devices;
32  using difference_type = container::difference_type;
33  using value_type = container::value_type;
34  using pointer = container::pointer;
35  using reference = container::reference;
36  using iterator_category = ::std::random_access_iterator_tag;
37 
38  // Note: the sentinel iterator value has an index equal to num_indices
39 
40  // something about the traits
41 
42  index_based_iterator(size_type num_devices, size_type index)
43  : num_devices_(num_devices), index_(index)
44  {
45  if (index_ > num_devices_) { throw ::std::logic_error("Out of range"); }
46  }
47 
48  index_based_iterator(const index_based_iterator& it)
49  : index_based_iterator(it.num_devices_, it.index_) { }
50 
51  // Forward iterator requirements
52 
53  reference operator*() const { return device::get(index_); }
54 
55  index_based_iterator& operator++()
56  {
57  if (index_ == num_devices_) { throw ::std::logic_error("Out of range"); }
58  ++index_;
59  return *this;
60  }
61 
62  index_based_iterator operator++(int)
63  {
64  if (index_== num_devices_) { throw ::std::logic_error("Out of range"); }
65  return index_based_iterator(num_devices_, index_++);
66  }
67 
68  // Bidirectional iterator requirements
69  index_based_iterator& operator--()
70  {
71  if (index_ == 0) { throw ::std::logic_error("Out of range"); }
72  --index_;
73  return *this;
74  }
75 
76  index_based_iterator operator--(int)
77  {
78  if (index_ == 0) { throw ::std::logic_error("Out of range"); }
79  return index_based_iterator(num_devices_, index_--);
80  }
81 
82  // Random access iterator requirements
83  reference operator[](difference_type n) const
84  {
85  return device::get(device::id_t (index_ + n));
86  }
87 
88  index_based_iterator& operator+=(difference_type n)
89  {
90 #ifndef NDEBUG
91  if (index_ + n > num_devices_) { throw ::std::logic_error("Out of range"); }
92 #endif
93  index_ += n;
94  return *this;
95  }
96 
97  index_based_iterator operator+(difference_type n) const
98  {
99 #ifndef NDEBUG
100  if (n + index_ > num_devices_) {
101  throw ::std::logic_error("Out of range");
102  }
103 #endif
104  return index_based_iterator(num_devices_, index_ + n);
105  }
106 
107  index_based_iterator& operator-=(difference_type n)
108  {
109  if (n > index_) {
110  throw ::std::logic_error("Out of range");
111  }
112  index_ -= n;
113  return *this;
114  }
115 
116  index_based_iterator operator-(difference_type n) const
117  {
118  if (n > index_) {
119  throw ::std::logic_error("Out of range");
120  }
121  return index_based_iterator(num_devices_, index_ - n);
122  }
123 
124  difference_type operator-(const index_based_iterator& other) const
125  {
126  return this->index_ - other.index_;
127  }
128 
129  size_type index() const { return index_; }
130  size_type num_devices() const { return num_devices_; }
131 
132  protected:
133  size_type num_devices_;
134  size_type index_;
135  }; // class index_based_iterator
136 
137  using iterator = index_based_iterator;
138  using const_iterator = index_based_iterator;
139  using reverse_iterator = ::std::reverse_iterator<iterator>;
140  using const_reverse_iterator = ::std::reverse_iterator<const_iterator>;
141 
142 
143  all_devices() : num_devices_(device::count()) { }
144  ~all_devices() = default;
145  all_devices(const all_devices&) = default;
146  all_devices(all_devices&&) = default;
147  all_devices& operator=(const all_devices&) { return *this; };
148  all_devices& operator=(all_devices&&) { return *this; };
149 
150  // void fill(const value_type& u);
151  void swap(all_devices&) noexcept { } // all instances are basically the same
152 
153  // Iterators
154 
155  iterator begin() noexcept { return iterator(num_devices_, 0); }
156  const_iterator begin() const noexcept { return const_iterator(num_devices_, 0); }
157  iterator end() noexcept { return iterator(num_devices_, num_devices_); }
158  const_iterator end() const noexcept { return const_iterator(num_devices_, num_devices_); }
159  reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
160  const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
161  reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
162  const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
163  const_iterator cbegin() const noexcept { return const_iterator(num_devices_, 0); }
164  const_iterator cend() const noexcept { return const_iterator(num_devices_, num_devices_); }
165  const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
166  const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
167 
168  // Capacity
169 
170  size_type size() const noexcept { return num_devices_; }
171  size_type max_size() const noexcept { return num_devices_; }
172  bool empty() const noexcept { return size() == 0; }
173 
174  // Element access
175 
176  // reference at(size_type n);
177  const_reference at(size_type n) const
178  {
179  // Note; this getter will throw if the device index is out-of-range
180  return device::get(n);
181  }
182 
183  // reference operator[](size_type i);
184  const_reference operator[](size_type n) const { return at(n); }
185 
186 
187  // reference front();
188  const_reference front() const { return *begin(); }
189 
190  const_reference back() const noexcept { return num_devices_ ? *(end() - 1) : *end(); }
191  // reference back() noexcept;
192 
193 protected:
194  size_type num_devices_;
195 };
196 
197 inline bool operator== (
198  const all_devices::index_based_iterator& lhs,
199  const all_devices::index_based_iterator& rhs)
200 {
201 #ifndef NDEBUG
202  return lhs.num_devices() == rhs.num_devices() and lhs.index() == rhs.index();
203 #else
204  return lhs.index() == rhs.index();
205 #endif
206 }
207 
208 inline bool operator!= (
209  const all_devices::index_based_iterator& lhs,
210  const all_devices::index_based_iterator& rhs)
211 {
212  return not (lhs == rhs);
213 }
214 
215 } // namespace detail_
216 
217 inline detail_::all_devices devices()
218 {
219  return detail_::all_devices();
220 }
221 
222 } // namespace cuda
223 
224 #endif // CUDA_API_WRAPPERS_DEVICES_HPP_
A proxy class for CUDA devices, providing access to all Runtime API calls involving their use and man...
All definitions and functionality wrapping the CUDA Runtime API.
Definition: array.hpp:22
device::id_t count()
Get the number of CUDA devices usable on the system (with the current CUDA library and kernel driver)...
Definition: miscellany.hpp:56
CUdevice id_t
Numeric ID of a CUDA device used by the CUDA Runtime API.
Definition: types.hpp:752
Definition: kernel_launch.hpp:77