DPC++ Runtime
Runtime libraries for oneAPI DPC++
sycl_mem_obj_t.hpp
Go to the documentation of this file.
1 //==------------ sycl_mem_obj_t.hpp - SYCL standard header file ------------==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #pragma once
10 
12 #include <sycl/detail/common.hpp>
13 #include <sycl/detail/export.hpp>
16 #include <sycl/event.hpp>
19 #include <sycl/property_list.hpp>
20 #include <sycl/stl.hpp>
21 
22 #include <cstring>
23 #include <memory>
24 #include <type_traits>
25 
26 namespace sycl {
28 namespace detail {
29 
30 // Forward declarations
31 class context_impl;
32 class event_impl;
33 class plugin;
34 
35 using ContextImplPtr = std::shared_ptr<context_impl>;
36 using EventImplPtr = std::shared_ptr<event_impl>;
37 
38 // The class serves as a base for all SYCL memory objects.
39 class __SYCL_EXPORT SYCLMemObjT : public SYCLMemObjI {
40 
41  // The check for output iterator is commented out as it blocks set_final_data
42  // with void * argument to be used.
43  // TODO: Align these checks with the SYCL specification when the behaviour
44  // with void * is clarified.
45  template <typename T>
46  using EnableIfOutputPointerT = std::enable_if_t<
47  /*is_output_iterator<T>::value &&*/ std::is_pointer<T>::value>;
48 
49  template <typename T>
50  using EnableIfOutputIteratorT = std::enable_if_t<
51  /*is_output_iterator<T>::value &&*/ !std::is_pointer<T>::value>;
52 
53 public:
54  SYCLMemObjT(const size_t SizeInBytes, const property_list &Props,
55  std::unique_ptr<SYCLMemObjAllocator> Allocator)
56  : MAllocator(std::move(Allocator)), MProps(Props), MInteropEvent(nullptr),
57  MInteropContext(nullptr), MInteropMemObject(nullptr),
58  MOpenCLInterop(false), MHostPtrReadOnly(false), MNeedWriteBack(true),
59  MSizeInBytes(SizeInBytes), MUserPtr(nullptr), MShadowCopy(nullptr),
60  MUploadDataFunctor(nullptr), MSharedPtrStorage(nullptr) {}
61 
62  SYCLMemObjT(const property_list &Props,
63  std::unique_ptr<SYCLMemObjAllocator> Allocator)
64  : SYCLMemObjT(/*SizeInBytes*/ 0, Props, std::move(Allocator)) {}
65 
66  SYCLMemObjT(pi_native_handle MemObject, const context &SyclContext,
67  const size_t SizeInBytes, event AvailableEvent,
68  std::unique_ptr<SYCLMemObjAllocator> Allocator);
69 
70  SYCLMemObjT(cl_mem MemObject, const context &SyclContext,
71  event AvailableEvent,
72  std::unique_ptr<SYCLMemObjAllocator> Allocator)
73  : SYCLMemObjT(pi::cast<pi_native_handle>(MemObject), SyclContext,
74  /*SizeInBytes*/ (size_t)0, AvailableEvent,
75  std::move(Allocator)) {}
76 
77  SYCLMemObjT(pi_native_handle MemObject, const context &SyclContext,
78  bool OwmNativeHandle, event AvailableEvent,
79  std::unique_ptr<SYCLMemObjAllocator> Allocator);
80 
81  virtual ~SYCLMemObjT() = default;
82 
83  const plugin &getPlugin() const;
84 
85  size_t getSizeInBytes() const override { return MSizeInBytes; }
86  __SYCL2020_DEPRECATED("get_count() is deprecated, please use size() instead")
87  size_t get_count() const { return size(); }
88  size_t size() const noexcept {
89  size_t AllocatorValueSize = MAllocator->getValueSize();
90  return (getSizeInBytes() + AllocatorValueSize - 1) / AllocatorValueSize;
91  }
92 
93  template <typename propertyT> bool has_property() const noexcept {
94  return MProps.has_property<propertyT>();
95  }
96 
97  template <typename propertyT> propertyT get_property() const {
98  return MProps.get_property<propertyT>();
99  }
100 
101  void addOrReplaceAccessorProperties(const property_list &PropertyList) {
102  MProps.add_or_replace_accessor_properties(PropertyList);
103  }
104 
106  MProps.delete_accessor_property(Kind);
107  }
108 
109  const std::unique_ptr<SYCLMemObjAllocator> &get_allocator_internal() const {
110  return MAllocator;
111  }
112 
113  void *allocateHostMem() override { return MAllocator->allocate(size()); }
114 
115  void releaseHostMem(void *Ptr) override {
116  if (Ptr)
117  MAllocator->deallocate(Ptr, size());
118  }
119 
120  void releaseMem(ContextImplPtr Context, void *MemAllocation) override;
121 
122  void *getUserPtr() const {
123  return MOpenCLInterop ? static_cast<void *>(MInteropMemObject) : MUserPtr;
124  }
125 
126  void set_write_back(bool NeedWriteBack) { MNeedWriteBack = NeedWriteBack; }
127 
128  void set_final_data(std::nullptr_t) { MUploadDataFunctor = nullptr; }
129 
131  MUploadDataFunctor = [this]() {
132  if (MSharedPtrStorage.use_count() > 1) {
133  void *FinalData = const_cast<void *>(MSharedPtrStorage.get());
134  updateHostMemory(FinalData);
135  }
136  };
137  }
138 
140  const std::function<void(const std::function<void(void *const Ptr)> &)>
141  &FinalDataFunc) {
142 
143  auto UpdateFunc = [this](void *const Ptr) { updateHostMemory(Ptr); };
144  MUploadDataFunctor = [FinalDataFunc, UpdateFunc]() {
145  FinalDataFunc(UpdateFunc);
146  };
147  }
148 
149 protected:
150  void updateHostMemory(void *const Ptr);
151 
152  // Update host with the latest data + notify scheduler that the memory object
153  // is going to die. After this method is finished no further operations with
154  // the memory object is allowed. This method is executed from child's
155  // destructor. This cannot be done in SYCLMemObjT's destructor as child's
156  // members must be alive.
157  void updateHostMemory();
158 
159 public:
160  bool useHostPtr() {
161  return has_property<property::buffer::use_host_ptr>() ||
162  has_property<property::image::use_host_ptr>();
163  }
164 
165  bool canReuseHostPtr(void *HostPtr, const size_t RequiredAlign) {
166  bool Aligned =
167  (reinterpret_cast<std::uintptr_t>(HostPtr) % RequiredAlign) == 0;
168  return Aligned || useHostPtr();
169  }
170 
171  void handleHostData(void *HostPtr, const size_t RequiredAlign) {
172  if (!MHostPtrReadOnly && HostPtr) {
173  set_final_data([HostPtr](const std::function<void(void *const Ptr)> &F) {
174  F(HostPtr);
175  });
176  }
177 
178  if (canReuseHostPtr(HostPtr, RequiredAlign)) {
179  MUserPtr = HostPtr;
180  } else {
181  setAlign(RequiredAlign);
182  MShadowCopy = allocateHostMem();
183  MUserPtr = MShadowCopy;
184  std::memcpy(MUserPtr, HostPtr, MSizeInBytes);
185  }
186  }
187 
188  void handleHostData(const void *HostPtr, const size_t RequiredAlign) {
189  MHostPtrReadOnly = true;
190  handleHostData(const_cast<void *>(HostPtr), RequiredAlign);
191  }
192 
193  void handleHostData(const std::shared_ptr<void> &HostPtr,
194  const size_t RequiredAlign, bool IsConstPtr) {
195  MSharedPtrStorage = HostPtr;
196  MHostPtrReadOnly = IsConstPtr;
197  if (HostPtr) {
198  if (!MHostPtrReadOnly)
199  set_final_data_from_storage();
200 
201  if (canReuseHostPtr(HostPtr.get(), RequiredAlign))
202  MUserPtr = HostPtr.get();
203  else {
204  setAlign(RequiredAlign);
205  MShadowCopy = allocateHostMem();
206  MUserPtr = MShadowCopy;
207  std::memcpy(MUserPtr, HostPtr.get(), MSizeInBytes);
208  }
209  }
210  }
211 
212  void handleHostData(const std::function<void(void *)> &CopyFromInput,
213  const size_t RequiredAlign, bool IsConstPtr) {
214  MHostPtrReadOnly = IsConstPtr;
215  setAlign(RequiredAlign);
216  if (useHostPtr())
217  throw runtime_error(
218  "Buffer constructor from a pair of iterator values does not support "
219  "use_host_ptr property.",
220  PI_ERROR_INVALID_OPERATION);
221 
222  setAlign(RequiredAlign);
223  MShadowCopy = allocateHostMem();
224  MUserPtr = MShadowCopy;
225 
226  CopyFromInput(MUserPtr);
227  }
228 
229  void setAlign(size_t RequiredAlign) {
230  MAllocator->setAlignment(RequiredAlign);
231  }
232 
233  static size_t getBufSizeForContext(const ContextImplPtr &Context,
234  pi_native_handle MemObject);
235 
236  void *allocateMem(ContextImplPtr Context, bool InitFromUserData,
237  void *HostPtr, RT::PiEvent &InteropEvent) override {
238  (void)Context;
239  (void)InitFromUserData;
240  (void)HostPtr;
241  (void)InteropEvent;
242  throw runtime_error("Not implemented", PI_ERROR_INVALID_OPERATION);
243  }
244 
245  MemObjType getType() const override { return MemObjType::Undefined; }
246 
247  ContextImplPtr getInteropContext() const override { return MInteropContext; }
248 
249  bool hasUserDataPtr() const { return MUserPtr != nullptr; };
250 
251  bool isInterop() const;
252 
253  bool isHostPointerReadOnly() const { return MHostPtrReadOnly; }
254 
255 protected:
256  // An allocateMem helper that determines which host ptr to use
257  void determineHostPtr(const ContextImplPtr &Context, bool InitFromUserData,
258  void *&HostPtr, bool &HostPtrReadOnly);
259 
260  // Allocator used for allocation memory on host.
261  std::unique_ptr<SYCLMemObjAllocator> MAllocator;
262  // Properties passed by user.
264  // Event passed by user to interoperability constructor.
265  // Should wait on this event before start working with such memory object.
267  // Context passed by user to interoperability constructor.
269  // Native backend memory object handle passed by user to interoperability
270  // constructor.
272  // Indicates whether memory object is created using interoperability
273  // constructor or not.
275  // Indicates if user provided pointer is read only.
277  // Indicates if memory object should write memory to the host on destruction.
279  // Size of memory.
280  size_t MSizeInBytes;
281  // User's pointer passed to constructor.
282  void *MUserPtr;
283  // Copy of memory passed by user to constructor.
284  void *MShadowCopy;
285  // Function which update host with final data on memory object destruction.
286  std::function<void(void)> MUploadDataFunctor;
287  // Field which holds user's shared_ptr in case of memory object is created
288  // using constructor with shared_ptr.
289  std::shared_ptr<const void> MSharedPtrStorage;
290 };
291 
292 } // namespace detail
293 } // __SYCL_INLINE_VER_NAMESPACE(_V1)
294 } // namespace sycl
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:41
const std::unique_ptr< SYCLMemObjAllocator > & get_allocator_internal() const
ContextImplPtr getInteropContext() const override
__SYCL2020_DEPRECATED("get_count() is deprecated, please use size() instead") size_t get_count() const
virtual ~SYCLMemObjT()=default
bool has_property() const noexcept
void handleHostData(const std::shared_ptr< void > &HostPtr, const size_t RequiredAlign, bool IsConstPtr)
void releaseHostMem(void *Ptr) override
SYCLMemObjT(const property_list &Props, std::unique_ptr< SYCLMemObjAllocator > Allocator)
std::shared_ptr< const void > MSharedPtrStorage
void * allocateMem(ContextImplPtr Context, bool InitFromUserData, void *HostPtr, RT::PiEvent &InteropEvent) override
MemObjType getType() const override
void addOrReplaceAccessorProperties(const property_list &PropertyList)
size_t size() const noexcept
void setAlign(size_t RequiredAlign)
SYCLMemObjT(cl_mem MemObject, const context &SyclContext, event AvailableEvent, std::unique_ptr< SYCLMemObjAllocator > Allocator)
SYCLMemObjT(const size_t SizeInBytes, const property_list &Props, std::unique_ptr< SYCLMemObjAllocator > Allocator)
std::function< void(void)> MUploadDataFunctor
void set_final_data(const std::function< void(const std::function< void(void *const Ptr)> &)> &FinalDataFunc)
void set_final_data(std::nullptr_t)
void handleHostData(const void *HostPtr, const size_t RequiredAlign)
void deleteAccessorProperty(const PropWithDataKind &Kind)
void set_write_back(bool NeedWriteBack)
std::unique_ptr< SYCLMemObjAllocator > MAllocator
size_t getSizeInBytes() const override
void handleHostData(void *HostPtr, const size_t RequiredAlign)
void handleHostData(const std::function< void(void *)> &CopyFromInput, const size_t RequiredAlign, bool IsConstPtr)
bool canReuseHostPtr(void *HostPtr, const size_t RequiredAlign)
The plugin class provides a unified interface to the underlying low-level runtimes for the device-agn...
Definition: plugin.hpp:90
An event object can be used to synchronize memory transfers, enqueues of kernels and signaling barrie...
Definition: event.hpp:40
Objects of the property_list class are containers for the SYCL properties.
#define __SYCL_INLINE_VER_NAMESPACE(X)
::pi_event PiEvent
Definition: pi.hpp:121
::pi_mem PiMem
Definition: pi.hpp:119
const plugin & getPlugin()
Definition: pi.cpp:509
std::shared_ptr< sycl::detail::context_impl > ContextImplPtr
Definition: event_impl.hpp:30
std::shared_ptr< event_impl > EventImplPtr
Definition: cg.hpp:42
void memcpy(void *Dst, const void *Src, std::size_t Size)
---— Error handling, matching OpenCL plugin semantics.
Definition: access.hpp:14
uintptr_t pi_native_handle
Definition: pi.h:111
To cast(From value)
Definition: pi_opencl.cpp:42