11#pragma once
22#include " core/config_build.hpp"
3-
4- #if DMFE_WITH_CUDA
5- #include < cuda_runtime.h>
6- #include < thrust/device_vector.h>
7- #include < thrust/device_ptr.h>
8- #include < thrust/system_error.h>
9- #include < thrust/system/cuda/error.h>
10- #include < cstddef>
11- #include < cstdint>
12- #include < limits>
13- #include < new>
14-
15- namespace dmfe {
16- namespace detail {
17- inline bool async_pool_supported () {
18- #if defined(CUDART_VERSION) && (CUDART_VERSION >= 11020)
19- static int supported = -1 ;
20- if (supported >= 0 ) {
21- return supported != 0 ;
22- }
23- int device = 0 ;
24- cudaError_t dev_err = cudaGetDevice (&device);
25- if (dev_err != cudaSuccess) {
26- supported = 0 ;
27- return false ;
28- }
29- int attr = 0 ;
30- cudaError_t err = cudaDeviceGetAttribute (&attr, cudaDevAttrMemoryPoolsSupported, device);
31- if (err != cudaSuccess) {
32- supported = 0 ;
33- return false ;
34- }
35- supported = attr;
36- return supported != 0 ;
37- #else
38- return false ;
39- #endif
40- }
41-
42- inline void configure_async_pool_once () {
43- #if defined(CUDART_VERSION) && (CUDART_VERSION >= 11020)
44- static bool configured = false ;
45- if (configured) {
46- return ;
47- }
48- configured = true ;
49- int device = 0 ;
50- if (cudaGetDevice (&device) != cudaSuccess) {
51- return ;
52- }
53- cudaMemPool_t pool = nullptr ;
54- if (cudaDeviceGetDefaultMemPool (&pool, device) != cudaSuccess) {
55- return ;
56- }
57- std::uint64_t threshold = std::numeric_limits<std::uint64_t >::max ();
58- cudaMemPoolSetAttribute (pool, cudaMemPoolAttrReleaseThreshold, &threshold);
59- #endif
60- }
61-
62- inline void * allocate_device_bytes (std::size_t bytes, cudaStream_t stream) {
63- #if defined(CUDART_VERSION) && (CUDART_VERSION >= 11020)
64- if (stream != 0 && async_pool_supported ()) {
65- configure_async_pool_once ();
66- void * ptr = nullptr ;
67- cudaError_t err = cudaMallocAsync (&ptr, bytes, stream);
68- if (err == cudaSuccess) {
69- return ptr;
70- }
71- // Fall back if async allocation fails for any reason.
72- }
73- #endif
74- void * ptr = nullptr ;
75- cudaError_t err = cudaMalloc (&ptr, bytes);
76- if (err != cudaSuccess) {
77- throw thrust::system_error (err, thrust::cuda_category (), " cudaMalloc failed" );
78- }
79- return ptr;
80- }
81-
82- inline void deallocate_device_bytes (void * ptr, cudaStream_t stream) {
83- if (!ptr) {
84- return ;
85- }
86- #if defined(CUDART_VERSION) && (CUDART_VERSION >= 11020)
87- if (stream != 0 && async_pool_supported ()) {
88- cudaError_t err = cudaFreeAsync (ptr, stream);
89- if (err == cudaSuccess) {
90- return ;
91- }
92- // Fall back if async free fails for any reason.
93- }
94- #endif
95- cudaError_t err = cudaFree (ptr);
96- if (err != cudaSuccess) {
97- throw thrust::system_error (err, thrust::cuda_category (), " cudaFree failed" );
98- }
99- }
100- } // namespace detail
101-
102- template <typename T>
103- class cuda_async_allocator {
104- public:
105- using value_type = T;
106- using pointer = thrust::device_ptr<T>;
107- using const_pointer = thrust::device_ptr<const T>;
108- using reference = T&;
109- using const_reference = const T&;
110- using size_type = std::size_t ;
111- using difference_type = std::ptrdiff_t ;
112-
113- cuda_async_allocator () noexcept : stream_(0 ) {}
114- explicit cuda_async_allocator (cudaStream_t stream) noexcept : stream_(stream) {}
115-
116- template <class U >
117- cuda_async_allocator (const cuda_async_allocator<U>& other) noexcept : stream_(other.stream()) {}
118-
119- pointer allocate (std::size_t n) {
120- if (n > max_size ()) {
121- throw std::bad_alloc ();
122- }
123- std::size_t bytes = n * sizeof (T);
124- return thrust::device_pointer_cast (static_cast <T*>(detail::allocate_device_bytes (bytes, stream_)));
125- }
126-
127- void deallocate (pointer ptr, std::size_t ) noexcept {
128- try {
129- detail::deallocate_device_bytes (ptr.get (), stream_);
130- } catch (...) {
131- // Thrust allocators are required not to throw from deallocate.
132- }
133- }
134-
135- std::size_t max_size () const noexcept {
136- return std::numeric_limits<std::size_t >::max () / sizeof (T);
137- }
138-
139- cudaStream_t stream () const noexcept { return stream_; }
140-
141- template <class U >
142- struct rebind {
143- using other = cuda_async_allocator<U>;
144- };
145-
146- bool operator ==(const cuda_async_allocator& other) const noexcept {
147- return stream_ == other.stream_ ;
148- }
149-
150- bool operator !=(const cuda_async_allocator& other) const noexcept {
151- return !(*this == other);
152- }
153-
154- private:
155- cudaStream_t stream_;
156- };
157-
158- template <typename T>
159- using device_vector = thrust::device_vector<T, cuda_async_allocator<T>>;
160-
161- } // namespace dmfe
162-
163- #else
1643#include < vector>
1654
1665namespace dmfe {
1676template <typename T>
1687using device_vector = std::vector<T>;
169- }
170-
171- #endif
8+ }
0 commit comments