QMCPACK
SYCLallocator.hpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2022 QMCPACK developers.
6 //
7 // File developed by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory
8 //
9 // File created by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory
10 //////////////////////////////////////////////////////////////////////////////////////
11 // -*- C++ -*-
12 /** @file SYCLallocator.hpp
13  * this file provides three C++ memory allocators using SYCL specific memory allocation functions.
14  *
15  * SYCLManagedAllocator allocates SYCL shared memory
16  * SYCLAllocator allocates SYCL device memory
17  * SYCLHostAllocator allocates SYCL host memory
18  * They are based on CUDA*Allocator implementation
19  */
20 #ifndef QMCPLUSPLUS_SYCL_ALLOCATOR_H
21 #define QMCPLUSPLUS_SYCL_ALLOCATOR_H
22 
23 #include <memory>
24 #include <cstdlib>
25 #include <stdexcept>
26 #include <atomic>
27 #include <limits>
28 #include <sycl/sycl.hpp>
29 #include "config.h"
30 #include "allocator_traits.hpp"
31 #include "SYCLruntime.hpp"
32 
33 namespace qmcplusplus
34 {
35 extern std::atomic<size_t> SYCLallocator_device_mem_allocated;
36 
38 
39 /** allocator for SYCL shared memory
40  * @tparm T data type
41  * @tparm ALIGN alignment in bytes
42  */
43 template<typename T, size_t ALIGN = QMC_SIMD_ALIGNMENT>
45 {
46  typedef T value_type;
47  typedef size_t size_type;
48  typedef T* pointer;
49  typedef const T* const_pointer;
50 
51  static constexpr size_t alignment = ALIGN;
52 
53  SYCLSharedAllocator() = default;
54  template<class U>
56  {}
57 
58  template<class U>
59  struct rebind
60  {
62  };
63 
64  T* allocate(std::size_t n)
65  {
66  T* pt = sycl::aligned_alloc_shared<T>(ALIGN, n, getSYCLDefaultDeviceDefaultQueue());
67  return pt;
68  }
69  void deallocate(T* p, std::size_t) { sycl::free(p, getSYCLDefaultDeviceDefaultQueue()); }
70 };
71 
72 template<class T1, class T2>
74 {
75  return true;
76 }
77 template<class T1, class T2>
79 {
80  return false;
81 }
82 
83 /** allocator for SYCL device memory
84  * @tparm T data type
85  * @tparm ALIGN alignment in bytes
86  *
87  * using this with something other than Ohmms containers?
88  * -- use caution, write unit tests! --
89  * It's not tested beyond use in some unit tests using std::vector with constant size.
90  * SYCLAllocator appears to meet all the nonoptional requirements of a c++ Allocator.
91  *
92  * Some of the default implementations in std::allocator_traits
93  * of optional Allocator requirements may cause runtime or compilation failures.
94  * They assume there is only one memory space and that the host has access to it.
95  */
96 template<typename T, size_t ALIGN = 64>
98 {
99 public:
100  typedef T value_type;
101  typedef size_t size_type;
102  typedef T* pointer;
103  typedef const T* const_pointer;
104 
105  static constexpr size_t alignment = ALIGN;
106 
107  SYCLAllocator() = default;
108  template<class U>
110  {}
111 
112  template<class U>
113  struct rebind
114  {
116  };
117 
118  T* allocate(std::size_t n)
119  {
120  T* pt = sycl::aligned_alloc_device<T>(ALIGN, n, getSYCLDefaultDeviceDefaultQueue());
121  SYCLallocator_device_mem_allocated += n * sizeof(T);
122  return pt;
123  }
124 
125  void deallocate(T* p, std::size_t n)
126  {
127  sycl::free(p, getSYCLDefaultDeviceDefaultQueue());
128  SYCLallocator_device_mem_allocated -= n * sizeof(T);
129  }
130 
131  /** Provide a construct for std::allocator_traits::contruct to call.
132  * Don't do anything on construct, pointer p is on the device!
133  *
134  * For example std::vector calls this to default initialize each element. You'll segfault
135  * if std::allocator_traits::construct tries doing that at p.
136  *
137  * The standard is a bit confusing on this point. Implementing this is an optional requirement
138  * of Allocator from C++11 on, its not slated to be removed.
139  *
140  * Its deprecated for the std::allocator in c++17 and will be removed in c++20. But we are not implementing
141  * std::allocator.
142  *
143  * STL containers only use Allocators through allocator_traits and std::allocator_traits handles the case
144  * where no construct method is present in the Allocator.
145  * But std::allocator_traits will call the Allocators construct method if present.
146  */
147  template<class U, class... Args>
148  static void construct(U* p, Args&&... args)
149  {}
150 
151  /** Give std::allocator_traits something to call.
152  * The default if this isn't present is to call p->~T() which
153  * we can't do on device memory.
154  */
155  template<class U>
156  static void destroy(U* p)
157  {}
158 
159  void copyToDevice(T* device_ptr, T* host_ptr, size_t n)
160  {
161  getSYCLDefaultDeviceDefaultQueue().memcpy(device_ptr, host_ptr, n * sizeof(T)).wait();
162  }
163 
164  void copyFromDevice(T* host_ptr, T* device_ptr, size_t n)
165  {
166  getSYCLDefaultDeviceDefaultQueue().memcpy(host_ptr, device_ptr, n * sizeof(T)).wait();
167  }
168 
169  void copyDeviceToDevice(T* to_ptr, size_t n, T* from_ptr)
170  {
171  getSYCLDefaultDeviceDefaultQueue().memcpy(to_ptr, from_ptr, n * sizeof(T)).wait();
172  }
173 };
174 
175 template<class T1, class T2>
177 {
178  return true;
179 }
180 template<class T1, class T2>
182 {
183  return false;
184 }
185 
186 template<typename T>
188 {
189  static const bool is_host_accessible = false;
190  static const bool is_dual_space = false;
191  static void fill_n(T* ptr, size_t n, const T& value)
192  {
193  //THINK
194  //qmcplusplus::SYCLfill_n(ptr, n, value);
195  }
196  static void updateTo(SYCLAllocator<T>& alloc, T* host_ptr, size_t n)
197  {
198  T* device_ptr = alloc.getDevicePtr(host_ptr);
199  alloc.copyToDevice(device_ptr, host_ptr, n);
200  }
201 
202  static void updateFrom(SYCLAllocator<T>& alloc, T* host_ptr, size_t n)
203  {
204  T* device_ptr = alloc.getDevicePtr(host_ptr);
205  alloc.copyFromDevice(host_ptr, device_ptr, n);
206  }
207 };
208 
209 /** allocator for SYCL host pinned memory
210  * @tparm T data type
211  * @tparm ALIGN alignment in bytes
212  */
213 template<typename T, size_t ALIGN = QMC_SIMD_ALIGNMENT>
215 {
216  typedef T value_type;
217  typedef size_t size_type;
218  typedef T* pointer;
219  typedef const T* const_pointer;
220 
221  static constexpr size_t alignment = ALIGN;
222 
223  SYCLHostAllocator() = default;
224  template<class U>
226  {}
227 
228  template<class U>
229  struct rebind
230  {
232  };
233 
234  T* allocate(std::size_t n) { return sycl::aligned_alloc_host<T>(ALIGN, n, getSYCLDefaultDeviceDefaultQueue()); }
235  void deallocate(T* p, std::size_t) { sycl::free(p, getSYCLDefaultDeviceDefaultQueue()); }
236 };
237 
238 template<class T1, class T2>
240 {
241  return true;
242 }
243 
244 template<class T1, class T2>
246 {
247  return false;
248 }
249 
250 } // namespace qmcplusplus
251 
252 #endif
void copyFromDevice(T *host_ptr, T *device_ptr, size_t n)
allocator for SYCL host pinned memory T data type ALIGN alignment in bytes
sycl::queue & getSYCLDefaultDeviceDefaultQueue()
return a reference to the per-device default queue
Definition: SYCLruntime.cpp:18
SYCLSharedAllocator(const SYCLSharedAllocator< U > &)
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
static void updateFrom(SYCLAllocator< T > &alloc, T *host_ptr, size_t n)
static void updateTo(SYCLAllocator< T > &alloc, T *host_ptr, size_t n)
static void destroy(U *p)
Give std::allocator_traits something to call.
allocator for SYCL device memory T data type ALIGN alignment in bytes
bool operator==(const Matrix< T, Alloc > &lhs, const Matrix< T, Alloc > &rhs)
Definition: OhmmsMatrix.h:388
void copyToDevice(T *device_ptr, T *host_ptr, size_t n)
void deallocate(T *p, std::size_t n)
static void construct(U *p, Args &&... args)
Provide a construct for std::allocator_traits::contruct to call.
void deallocate(T *p, std::size_t)
SYCLAllocator(const SYCLAllocator< U > &)
static constexpr bool is_host_accessible
static constexpr size_t alignment
template class analogous to std::allocator_traits.
size_t getSYCLdeviceMemAllocated()
std::atomic< size_t > SYCLallocator_device_mem_allocated
void copyDeviceToDevice(T *to_ptr, size_t n, T *from_ptr)
static constexpr size_t alignment
SYCLHostAllocator(const SYCLHostAllocator< U > &)
static constexpr size_t alignment
T * allocate(std::size_t n)
void deallocate(T *p, std::size_t)
allocator for SYCL shared memory T data type ALIGN alignment in bytes
bool operator!=(const Matrix< T, Alloc > &lhs, const Matrix< T, Alloc > &rhs)
Definition: OhmmsMatrix.h:403