|
1 |
| -/*! |
2 |
| - * Copyright 2022 by XGBoost Contributors |
3 |
| - * \file common.h |
4 |
| - * \brief cuda pinned allocator for usage with thrust containers |
| 1 | +/** |
| 2 | + * Copyright 2022-2024, XGBoost Contributors |
| 3 | + * |
| 4 | + * @brief cuda pinned allocator for usage with thrust containers |
5 | 5 | */
|
6 | 6 |
|
7 | 7 | #pragma once
|
8 | 8 |
|
9 |
| -#include <cstddef> |
10 |
| -#include <limits> |
| 9 | +#include <cuda_runtime.h> |
11 | 10 |
|
12 |
| -#include "common.h" |
| 11 | +#include <cstddef> // for size_t |
| 12 | +#include <limits> // for numeric_limits |
13 | 13 |
|
14 |
| -namespace xgboost { |
15 |
| -namespace common { |
16 |
| -namespace cuda { |
| 14 | +#include "common.h" |
17 | 15 |
|
| 16 | +namespace xgboost::common::cuda_impl { |
18 | 17 | // \p pinned_allocator is a CUDA-specific host memory allocator
|
19 | 18 | // that employs \c cudaMallocHost for allocation.
|
20 | 19 | //
|
21 | 20 | // This implementation is ported from the experimental/pinned_allocator
|
22 | 21 | // that Thrust used to provide.
|
23 | 22 | //
|
24 | 23 | // \see https://en.cppreference.com/w/cpp/memory/allocator
|
| 24 | + |
25 | 25 | template <typename T>
|
26 |
| -class pinned_allocator; |
| 26 | +struct PinnedAllocPolicy { |
| 27 | + using pointer = T*; // NOLINT: The type returned by address() / allocate() |
| 28 | + using const_pointer = const T*; // NOLINT: The type returned by address() |
| 29 | + using size_type = std::size_t; // NOLINT: The type used for the size of the allocation |
| 30 | + using value_type = T; // NOLINT: The type of the elements in the allocator |
| 31 | + |
| 32 | + size_type max_size() const { // NOLINT |
| 33 | + return std::numeric_limits<size_type>::max() / sizeof(value_type); |
| 34 | + } |
27 | 35 |
|
28 |
| -template <> |
29 |
| -class pinned_allocator<void> { |
30 |
| - public: |
31 |
| - using value_type = void; // NOLINT: The type of the elements in the allocator |
32 |
| - using pointer = void*; // NOLINT: The type returned by address() / allocate() |
33 |
| - using const_pointer = const void*; // NOLINT: The type returned by address() |
34 |
| - using size_type = std::size_t; // NOLINT: The type used for the size of the allocation |
35 |
| - using difference_type = std::ptrdiff_t; // NOLINT: The type of the distance between two pointers |
| 36 | + pointer allocate(size_type cnt, const_pointer = nullptr) { // NOLINT |
| 37 | + if (cnt > this->max_size()) { |
| 38 | + throw std::bad_alloc{}; |
| 39 | + } // end if |
36 | 40 |
|
37 |
| - template <typename U> |
38 |
| - struct rebind { // NOLINT |
39 |
| - using other = pinned_allocator<U>; // NOLINT: The rebound type |
40 |
| - }; |
41 |
| -}; |
| 41 | + pointer result(nullptr); |
| 42 | + dh::safe_cuda(cudaMallocHost(reinterpret_cast<void**>(&result), cnt * sizeof(value_type))); |
| 43 | + return result; |
| 44 | + } |
42 | 45 |
|
| 46 | + void deallocate(pointer p, size_type) { dh::safe_cuda(cudaFreeHost(p)); } // NOLINT |
| 47 | +}; |
43 | 48 |
|
44 | 49 | template <typename T>
|
45 |
| -class pinned_allocator { |
| 50 | +struct ManagedAllocPolicy { |
| 51 | + using pointer = T*; // NOLINT: The type returned by address() / allocate() |
| 52 | + using const_pointer = const T*; // NOLINT: The type returned by address() |
| 53 | + using size_type = std::size_t; // NOLINT: The type used for the size of the allocation |
| 54 | + using value_type = T; // NOLINT: The type of the elements in the allocator |
| 55 | + |
| 56 | + size_type max_size() const { // NOLINT |
| 57 | + return std::numeric_limits<size_type>::max() / sizeof(value_type); |
| 58 | + } |
| 59 | + |
| 60 | + pointer allocate(size_type cnt, const_pointer = nullptr) { // NOLINT |
| 61 | + if (cnt > this->max_size()) { |
| 62 | + throw std::bad_alloc{}; |
| 63 | + } // end if |
| 64 | + |
| 65 | + pointer result(nullptr); |
| 66 | + dh::safe_cuda(cudaMallocManaged(reinterpret_cast<void**>(&result), cnt * sizeof(value_type))); |
| 67 | + return result; |
| 68 | + } |
| 69 | + |
| 70 | + void deallocate(pointer p, size_type) { dh::safe_cuda(cudaFree(p)); } // NOLINT |
| 71 | +}; |
| 72 | + |
| 73 | +template <typename T, template <typename> typename Policy> |
| 74 | +class CudaHostAllocatorImpl : public Policy<T> { // NOLINT |
46 | 75 | public:
|
47 |
| - using value_type = T; // NOLINT: The type of the elements in the allocator |
48 |
| - using pointer = T*; // NOLINT: The type returned by address() / allocate() |
49 |
| - using const_pointer = const T*; // NOLINT: The type returned by address() |
50 |
| - using reference = T&; // NOLINT: The parameter type for address() |
51 |
| - using const_reference = const T&; // NOLINT: The parameter type for address() |
52 |
| - using size_type = std::size_t; // NOLINT: The type used for the size of the allocation |
| 76 | + using value_type = typename Policy<T>::value_type; // NOLINT |
| 77 | + using pointer = typename Policy<T>::pointer; // NOLINT |
| 78 | + using const_pointer = typename Policy<T>::const_pointer; // NOLINT |
| 79 | + using size_type = typename Policy<T>::size_type; // NOLINT |
| 80 | + |
| 81 | + using reference = T&; // NOLINT: The parameter type for address() |
| 82 | + using const_reference = const T&; // NOLINT: The parameter type for address() |
| 83 | + |
53 | 84 | using difference_type = std::ptrdiff_t; // NOLINT: The type of the distance between two pointers
|
54 | 85 |
|
55 | 86 | template <typename U>
|
56 |
| - struct rebind { // NOLINT |
57 |
| - using other = pinned_allocator<U>; // NOLINT: The rebound type |
| 87 | + struct rebind { // NOLINT |
| 88 | + using other = CudaHostAllocatorImpl<U, Policy>; // NOLINT: The rebound type |
58 | 89 | };
|
59 | 90 |
|
60 |
| - XGBOOST_DEVICE inline pinned_allocator() {}; // NOLINT: host/device markup ignored on defaulted functions |
61 |
| - XGBOOST_DEVICE inline ~pinned_allocator() {} // NOLINT: host/device markup ignored on defaulted functions |
62 |
| - XGBOOST_DEVICE inline pinned_allocator(pinned_allocator const&) {} // NOLINT: host/device markup ignored on defaulted functions |
| 91 | + CudaHostAllocatorImpl() = default; |
| 92 | + ~CudaHostAllocatorImpl() = default; |
| 93 | + CudaHostAllocatorImpl(CudaHostAllocatorImpl const&) = default; |
63 | 94 |
|
64 |
| - pinned_allocator& operator=(pinned_allocator const& that) = default; |
65 |
| - pinned_allocator& operator=(pinned_allocator&& that) = default; |
| 95 | + CudaHostAllocatorImpl& operator=(CudaHostAllocatorImpl const& that) = default; |
| 96 | + CudaHostAllocatorImpl& operator=(CudaHostAllocatorImpl&& that) = default; |
66 | 97 |
|
67 | 98 | template <typename U>
|
68 |
| - XGBOOST_DEVICE inline pinned_allocator(pinned_allocator<U> const&) {} // NOLINT |
69 |
| - |
70 |
| - XGBOOST_DEVICE inline pointer address(reference r) { return &r; } // NOLINT |
71 |
| - XGBOOST_DEVICE inline const_pointer address(const_reference r) { return &r; } // NOLINT |
72 |
| - |
73 |
| - inline pointer allocate(size_type cnt, const_pointer = nullptr) { // NOLINT |
74 |
| - if (cnt > this->max_size()) { throw std::bad_alloc(); } // end if |
| 99 | + CudaHostAllocatorImpl(CudaHostAllocatorImpl<U, Policy> const&) {} // NOLINT |
75 | 100 |
|
76 |
| - pointer result(nullptr); |
77 |
| - dh::safe_cuda(cudaMallocHost(reinterpret_cast<void**>(&result), cnt * sizeof(value_type))); |
78 |
| - return result; |
79 |
| - } |
| 101 | + pointer address(reference r) { return &r; } // NOLINT |
| 102 | + const_pointer address(const_reference r) { return &r; } // NOLINT |
80 | 103 |
|
81 |
| - inline void deallocate(pointer p, size_type) { dh::safe_cuda(cudaFreeHost(p)); } // NOLINT |
| 104 | + bool operator==(CudaHostAllocatorImpl const& x) const { return true; } |
82 | 105 |
|
83 |
| - inline size_type max_size() const { return (std::numeric_limits<size_type>::max)() / sizeof(T); } // NOLINT |
| 106 | + bool operator!=(CudaHostAllocatorImpl const& x) const { return !operator==(x); } |
| 107 | +}; |
84 | 108 |
|
85 |
| - XGBOOST_DEVICE inline bool operator==(pinned_allocator const& x) const { return true; } |
| 109 | +template <typename T> |
| 110 | +using pinned_allocator = CudaHostAllocatorImpl<T, PinnedAllocPolicy>; // NOLINT |
86 | 111 |
|
87 |
| - XGBOOST_DEVICE inline bool operator!=(pinned_allocator const& x) const { |
88 |
| - return !operator==(x); |
89 |
| - } |
90 |
| -}; |
91 |
| -} // namespace cuda |
92 |
| -} // namespace common |
93 |
| -} // namespace xgboost |
| 112 | +template <typename T> |
| 113 | +using managed_allocator = CudaHostAllocatorImpl<T, ManagedAllocPolicy>; // NOLINT |
| 114 | +} // namespace xgboost::common::cuda_impl |
0 commit comments