device_uvector.hpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2020-2025, NVIDIA CORPORATION.
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #pragma once
7 
9 #include <rmm/detail/error.hpp>
10 #include <rmm/detail/exec_check_disable.hpp>
11 #include <rmm/detail/export.hpp>
12 #include <rmm/device_buffer.hpp>
14 #include <rmm/resource_ref.hpp>
15 
16 #include <cuda/std/span>
17 #include <thrust/iterator/reverse_iterator.h>
18 
19 #include <cstddef>
20 #include <type_traits>
21 #include <utility>
22 
23 namespace RMM_NAMESPACE {
67 template <typename T>
69  static_assert(std::is_trivially_copyable_v<T>,
70  "device_uvector only supports types that are trivially copyable.");
71 
72  public:
73  using value_type = T;
74  using size_type = std::size_t;
75  using reference = value_type&;
77  value_type const&;
78  using pointer = value_type*;
79  using const_pointer = value_type const*;
80  using iterator = pointer;
83  thrust::reverse_iterator<iterator>;
85  thrust::reverse_iterator<const_iterator>;
86 
87  RMM_EXEC_CHECK_DISABLE
88  ~device_uvector() = default;
89 
90  RMM_EXEC_CHECK_DISABLE
91  device_uvector(device_uvector&&) noexcept = default;
92 
93  RMM_EXEC_CHECK_DISABLE
94  device_uvector& operator=(device_uvector&&) noexcept =
95  default;
96 
100  device_uvector(device_uvector const&) = delete;
101 
105  device_uvector& operator=(device_uvector const&) = delete;
106 
110  device_uvector() = delete;
111 
123  explicit device_uvector(size_type size,
124  cuda_stream_view stream,
126  : _storage{elements_to_bytes(size), stream, mr}
127  {
128  }
129 
139  explicit device_uvector(device_uvector const& other,
140  cuda_stream_view stream,
142  : _storage{other._storage, stream, mr}
143  {
144  }
145 
154  [[nodiscard]] pointer element_ptr(size_type element_index) noexcept
155  {
156  assert(element_index < size());
157  return data() + element_index;
158  }
159 
168  [[nodiscard]] const_pointer element_ptr(size_type element_index) const noexcept
169  {
170  assert(element_index < size());
171  return data() + element_index;
172  }
173 
210  void set_element_async(size_type element_index, value_type const& value, cuda_stream_view stream)
211  {
212  RMM_EXPECTS(
213  element_index < size(), "Attempt to access out of bounds element.", rmm::out_of_range);
214 
215  if constexpr (std::is_same_v<value_type, bool>) {
216  RMM_CUDA_TRY(
217  cudaMemsetAsync(element_ptr(element_index), value, sizeof(value), stream.value()));
218  return;
219  }
220 
221  if constexpr (std::is_fundamental_v<value_type>) {
222  if (value == value_type{0}) {
223  set_element_to_zero_async(element_index, stream);
224  return;
225  }
226  }
227 
228  RMM_CUDA_TRY(cudaMemcpyAsync(
229  element_ptr(element_index), &value, sizeof(value), cudaMemcpyDefault, stream.value()));
230  }
231 
232  // We delete the r-value reference overload to prevent asynchronously copying from a literal or
233  // implicit temporary value after it is deleted or goes out of scope.
234  void set_element_async(size_type, value_type const&&, cuda_stream_view) = delete;
235 
259  {
260  RMM_EXPECTS(
261  element_index < size(), "Attempt to access out of bounds element.", rmm::out_of_range);
262  RMM_CUDA_TRY(
263  cudaMemsetAsync(element_ptr(element_index), 0, sizeof(value_type), stream.value()));
264  }
265 
295  void set_element(size_type element_index, T const& value, cuda_stream_view stream)
296  {
297  set_element_async(element_index, value, stream);
298  stream.synchronize_no_throw();
299  }
300 
313  [[nodiscard]] value_type element(size_type element_index, cuda_stream_view stream) const
314  {
315  RMM_EXPECTS(
316  element_index < size(), "Attempt to access out of bounds element.", rmm::out_of_range);
317  value_type value;
318  RMM_CUDA_TRY(cudaMemcpyAsync(
319  &value, element_ptr(element_index), sizeof(value), cudaMemcpyDefault, stream.value()));
320  stream.synchronize();
321  return value;
322  }
323 
335  [[nodiscard]] value_type front_element(cuda_stream_view stream) const
336  {
337  return element(0, stream);
338  }
339 
351  [[nodiscard]] value_type back_element(cuda_stream_view stream) const
352  {
353  return element(size() - 1, stream);
354  }
355 
368  void reserve(size_type new_capacity, cuda_stream_view stream)
369  {
370  _storage.reserve(elements_to_bytes(new_capacity), stream);
371  }
372 
389  void resize(size_type new_size, cuda_stream_view stream)
390  {
391  _storage.resize(elements_to_bytes(new_size), stream);
392  }
393 
401  void shrink_to_fit(cuda_stream_view stream) { _storage.shrink_to_fit(stream); }
402 
408  device_buffer release() noexcept { return std::move(_storage); }
409 
416  [[nodiscard]] size_type capacity() const noexcept
417  {
418  return bytes_to_elements(_storage.capacity());
419  }
420 
429  [[nodiscard]] pointer data() noexcept { return static_cast<pointer>(_storage.data()); }
430 
439  [[nodiscard]] const_pointer data() const noexcept
440  {
441  return static_cast<const_pointer>(_storage.data());
442  }
443 
451  [[nodiscard]] iterator begin() noexcept { return data(); }
452 
460  [[nodiscard]] const_iterator cbegin() const noexcept { return data(); }
461 
469  [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); }
470 
479  [[nodiscard]] iterator end() noexcept { return data() + size(); }
480 
489  [[nodiscard]] const_iterator cend() const noexcept { return data() + size(); }
490 
499  [[nodiscard]] const_iterator end() const noexcept { return cend(); }
500 
508  [[nodiscard]] reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
509 
517  [[nodiscard]] const_reverse_iterator crbegin() const noexcept
518  {
519  return const_reverse_iterator(cend());
520  }
521 
529  [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return crbegin(); }
530 
539  [[nodiscard]] reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
540 
550  [[nodiscard]] const_reverse_iterator crend() const noexcept
551  {
552  return const_reverse_iterator(begin());
553  }
554 
563  [[nodiscard]] const_reverse_iterator rend() const noexcept { return crend(); }
564 
568  [[nodiscard]] size_type size() const noexcept { return bytes_to_elements(_storage.size()); }
569 
573  [[nodiscard]] std::int64_t ssize() const noexcept
574  {
575  assert(size() < static_cast<size_type>(std::numeric_limits<int64_t>::max()) &&
576  "Size overflows signed integer");
577  return static_cast<int64_t>(size());
578  }
579 
583  [[nodiscard]] bool is_empty() const noexcept { return size() == 0; }
584 
588  [[nodiscard]] operator cuda::std::span<T const>() const noexcept
589  {
590  return cuda::std::span<T const>{data(), size()};
591  }
592 
596  [[nodiscard]] operator cuda::std::span<T>() noexcept
597  {
598  return cuda::std::span<T>{data(), size()};
599  }
600 
605  [[nodiscard]] rmm::device_async_resource_ref memory_resource() const noexcept
606  {
607  return _storage.memory_resource();
608  }
609 
613  [[nodiscard]] cuda_stream_view stream() const noexcept { return _storage.stream(); }
614 
626  void set_stream(cuda_stream_view stream) noexcept { _storage.set_stream(stream); }
627 
628  private:
629  device_buffer _storage{};
630 
631  [[nodiscard]] size_type constexpr elements_to_bytes(size_type num_elements) const noexcept
632  {
633  return num_elements * sizeof(value_type);
634  }
635 
636  [[nodiscard]] size_type constexpr bytes_to_elements(size_type num_bytes) const noexcept
637  {
638  return num_bytes / sizeof(value_type);
639  }
640 };
641  // end of group
643 } // namespace RMM_NAMESPACE
Strongly-typed non-owning wrapper for CUDA streams with default constructor.
Definition: cuda_stream_view.hpp:28
void synchronize() const
Synchronize the viewed CUDA stream.
void synchronize_no_throw() const noexcept
Synchronize the viewed CUDA stream. Does not throw if there is an error.
cudaStream_t value() const noexcept
Get the wrapped stream.
RAII construct for device memory allocation.
Definition: device_buffer.hpp:70
An uninitialized vector of elements in device memory.
Definition: device_uvector.hpp:68
reverse_iterator rend() noexcept
Returns reverse_iterator to the element preceding the first element of the vector.
Definition: device_uvector.hpp:539
const_iterator cend() const noexcept
Returns a const_iterator to the element following the last element of the vector.
Definition: device_uvector.hpp:489
const_reverse_iterator crend() const noexcept
Returns a const_reverse_iterator to the element preceding the first element of the vector.
Definition: device_uvector.hpp:550
value_type * pointer
The type of the pointer returned by data()
Definition: device_uvector.hpp:78
thrust::reverse_iterator< const_iterator > const_reverse_iterator
The type of the iterator returned by crbegin()
Definition: device_uvector.hpp:85
void set_element_async(size_type element_index, value_type const &value, cuda_stream_view stream)
Performs an asynchronous copy of v to the specified element in device memory.
Definition: device_uvector.hpp:210
bool is_empty() const noexcept
true if the vector contains no elements, i.e. size() == 0
Definition: device_uvector.hpp:583
size_type size() const noexcept
The number of elements in the vector.
Definition: device_uvector.hpp:568
const_pointer data() const noexcept
Returns const pointer to underlying device storage.
Definition: device_uvector.hpp:439
void resize(size_type new_size, cuda_stream_view stream)
Resizes the vector to contain new_size elements.
Definition: device_uvector.hpp:389
void set_element(size_type element_index, T const &value, cuda_stream_view stream)
Performs a synchronous copy of v to the specified element in device memory.
Definition: device_uvector.hpp:295
thrust::reverse_iterator< iterator > reverse_iterator
The type of the iterator returned by rbegin()
Definition: device_uvector.hpp:83
reverse_iterator rbegin() noexcept
Returns a reverse_iterator to the last element.
Definition: device_uvector.hpp:508
pointer data() noexcept
Returns pointer to underlying device storage.
Definition: device_uvector.hpp:429
void shrink_to_fit(cuda_stream_view stream)
Forces deallocation of unused device memory.
Definition: device_uvector.hpp:401
iterator end() noexcept
Returns an iterator to the element following the last element of the vector.
Definition: device_uvector.hpp:479
std::size_t size_type
The type used for the size of the vector.
Definition: device_uvector.hpp:74
const_reverse_iterator crbegin() const noexcept
Returns a const_reverse_iterator to the last element.
Definition: device_uvector.hpp:517
size_type capacity() const noexcept
Returns the number of elements that can be held in currently allocated storage.
Definition: device_uvector.hpp:416
std::int64_t ssize() const noexcept
The signed number of elements in the vector.
Definition: device_uvector.hpp:573
T value_type
Stored value type.
Definition: device_uvector.hpp:73
const_iterator cbegin() const noexcept
Returns a const_iterator to the first element.
Definition: device_uvector.hpp:460
value_type back_element(cuda_stream_view stream) const
Returns the last element.
Definition: device_uvector.hpp:351
const_pointer const_iterator
The type of the const iterator returned by cbegin()
Definition: device_uvector.hpp:81
device_buffer release() noexcept
Release ownership of device memory storage.
Definition: device_uvector.hpp:408
void set_element_to_zero_async(size_type element_index, cuda_stream_view stream)
Asynchronously sets the specified element to zero in device memory.
Definition: device_uvector.hpp:258
device_uvector(device_uvector &&) noexcept=default
Default move constructor.
pointer iterator
The type of the iterator returned by begin()
Definition: device_uvector.hpp:80
void reserve(size_type new_capacity, cuda_stream_view stream)
Increases the capacity of the vector to new_capacity elements.
Definition: device_uvector.hpp:368
value_type & reference
Reference type returned by operator[](size_type)
Definition: device_uvector.hpp:75
const_reverse_iterator rend() const noexcept
Returns const_reverse_iterator to the element preceding the first element of the vector.
Definition: device_uvector.hpp:563
const_iterator end() const noexcept
Returns an iterator to the element following the last element of the vector.
Definition: device_uvector.hpp:499
pointer element_ptr(size_type element_index) noexcept
Returns pointer to the specified element.
Definition: device_uvector.hpp:154
value_type front_element(cuda_stream_view stream) const
Returns the first element.
Definition: device_uvector.hpp:335
value_type const * const_pointer
The type of the pointer returned by data() const.
Definition: device_uvector.hpp:79
device_uvector(device_uvector const &other, cuda_stream_view stream, device_async_resource_ref mr=mr::get_current_device_resource_ref())
Construct a new device_uvector by deep copying the contents of another device_uvector.
Definition: device_uvector.hpp:139
value_type const & const_reference
Constant reference type returned by operator[](size_type) const.
Definition: device_uvector.hpp:77
const_reverse_iterator rbegin() const noexcept
Returns a const_reverse_iterator to the last element.
Definition: device_uvector.hpp:529
value_type element(size_type element_index, cuda_stream_view stream) const
Returns the specified element from device memory.
Definition: device_uvector.hpp:313
const_pointer element_ptr(size_type element_index) const noexcept
Returns pointer to the specified element.
Definition: device_uvector.hpp:168
const_iterator begin() const noexcept
Returns a const_iterator to the first element.
Definition: device_uvector.hpp:469
iterator begin() noexcept
Returns an iterator to the first element.
Definition: device_uvector.hpp:451
Exception thrown when attempting to access outside of a defined range.
Definition: error.hpp:99
device_async_resource_ref get_current_device_resource_ref()
Get the device_async_resource_ref for the current device.
Definition: per_device_resource.hpp:400
detail::cccl_async_resource_ref< cuda::mr::resource_ref< cuda::mr::device_accessible > > device_async_resource_ref
Alias for a cuda::mr::async_resource_ref with the property cuda::mr::device_accessible.
Definition: resource_ref.hpp:32
Management of per-device device_memory_resources.