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/detail/ur.hpp>
17 #include <sycl/event.hpp>
20 #include <sycl/property_list.hpp>
21 #include <sycl/range.hpp>
22 
23 #include <atomic>
24 #include <cstring>
25 #include <memory>
26 #include <type_traits>
27 
28 namespace sycl {
29 inline namespace _V1 {
30 namespace detail {
31 
32 // Forward declarations
33 class context_impl;
34 class event_impl;
35 class plugin;
36 
37 using ContextImplPtr = std::shared_ptr<context_impl>;
38 using EventImplPtr = std::shared_ptr<event_impl>;
39 
40 // The class serves as a base for all SYCL memory objects.
41 class SYCLMemObjT : public SYCLMemObjI {
42 
43  // The check for output iterator is commented out as it blocks set_final_data
44  // with void * argument to be used.
45  // TODO: Align these checks with the SYCL specification when the behaviour
46  // with void * is clarified.
47  template <typename T>
48  using EnableIfOutputPointerT = std::enable_if_t<
49  /*is_output_iterator<T>::value &&*/ std::is_pointer<T>::value>;
50 
51  template <typename T>
52  using EnableIfOutputIteratorT = std::enable_if_t<
53  /*is_output_iterator<T>::value &&*/ !std::is_pointer<T>::value>;
54 
55 public:
56  SYCLMemObjT(const size_t SizeInBytes, const property_list &Props,
57  std::unique_ptr<SYCLMemObjAllocator> Allocator)
58  : MAllocator(std::move(Allocator)), MProps(Props), MInteropEvent(nullptr),
59  MInteropContext(nullptr), MInteropMemObject(nullptr),
60  MOpenCLInterop(false), MHostPtrReadOnly(false), MNeedWriteBack(true),
61  MSizeInBytes(SizeInBytes), MUserPtr(nullptr), MShadowCopy(nullptr),
62  MUploadDataFunctor(nullptr), MSharedPtrStorage(nullptr),
63  MHostPtrProvided(false) {}
64 
65  SYCLMemObjT(const property_list &Props,
66  std::unique_ptr<SYCLMemObjAllocator> Allocator)
67  : SYCLMemObjT(/*SizeInBytes*/ 0, Props, std::move(Allocator)) {}
68 
69  SYCLMemObjT(ur_native_handle_t MemObject, const context &SyclContext,
70  const size_t SizeInBytes, event AvailableEvent,
71  std::unique_ptr<SYCLMemObjAllocator> Allocator);
72 
73  SYCLMemObjT(cl_mem MemObject, const context &SyclContext,
74  event AvailableEvent,
75  std::unique_ptr<SYCLMemObjAllocator> Allocator)
76  : SYCLMemObjT(ur::cast<ur_native_handle_t>(MemObject), SyclContext,
77  /*SizeInBytes*/ (size_t)0, AvailableEvent,
78  std::move(Allocator)) {}
79 
80  SYCLMemObjT(ur_native_handle_t MemObject, const context &SyclContext,
81  bool OwnNativeHandle, event AvailableEvent,
82  std::unique_ptr<SYCLMemObjAllocator> Allocator);
83 
84  SYCLMemObjT(ur_native_handle_t MemObject, const context &SyclContext,
85  bool OwnNativeHandle, event AvailableEvent,
86  std::unique_ptr<SYCLMemObjAllocator> Allocator,
87  ur_image_format_t Format, range<3> Range3WithOnes,
88  unsigned Dimensions, size_t ElementSize);
89 
90  virtual ~SYCLMemObjT() = default;
91 
92  const PluginPtr &getPlugin() const;
93 
94  size_t getSizeInBytes() const noexcept override { return MSizeInBytes; }
95  __SYCL2020_DEPRECATED("get_count() is deprecated, please use size() instead")
96  size_t get_count() const { return size(); }
97  size_t size() const noexcept {
98  size_t AllocatorValueSize = MAllocator->getValueSize();
99  return (getSizeInBytes() + AllocatorValueSize - 1) / AllocatorValueSize;
100  }
101 
102  template <typename propertyT> bool has_property() const noexcept {
103  return MProps.has_property<propertyT>();
104  }
105 
106  template <typename propertyT> propertyT get_property() const {
107  return MProps.get_property<propertyT>();
108  }
109 
110  void addOrReplaceAccessorProperties(const property_list &PropertyList) {
112  }
113 
116  }
117 
118  const std::unique_ptr<SYCLMemObjAllocator> &get_allocator_internal() const {
119  return MAllocator;
120  }
121 
122  void *allocateHostMem() override { return MAllocator->allocate(size()); }
123 
124  void releaseHostMem(void *Ptr) override {
125  if (Ptr)
126  MAllocator->deallocate(Ptr, size());
127  }
128 
129  void releaseMem(ContextImplPtr Context, void *MemAllocation) override;
130 
131  void *getUserPtr() const {
132  return MOpenCLInterop ? static_cast<void *>(MInteropMemObject) : MUserPtr;
133  }
134 
135  void set_write_back(bool NeedWriteBack) { MNeedWriteBack = NeedWriteBack; }
136 
137  void set_final_data(std::nullptr_t) { MUploadDataFunctor = nullptr; }
138 
140  MUploadDataFunctor = [this]() {
141  if (MSharedPtrStorage.use_count() > 1) {
142  void *FinalData = const_cast<void *>(MSharedPtrStorage.get());
143  updateHostMemory(FinalData);
144  }
145  };
146  MHostPtrProvided = true;
147  }
148 
150  const std::function<void(const std::function<void(void *const Ptr)> &)>
151  &FinalDataFunc) {
152 
153  auto UpdateFunc = [this](void *const Ptr) { updateHostMemory(Ptr); };
154  MUploadDataFunctor = [FinalDataFunc, UpdateFunc]() {
155  FinalDataFunc(UpdateFunc);
156  };
157  MHostPtrProvided = true;
158  }
159 
160 protected:
161  void updateHostMemory(void *const Ptr);
162 
163  // Update host with the latest data + notify scheduler that the memory object
164  // is going to die. After this method is finished no further operations with
165  // the memory object is allowed. This method is executed from child's
166  // destructor. This cannot be done in SYCLMemObjT's destructor as child's
167  // members must be alive.
168  void updateHostMemory();
169 
170 public:
171  bool useHostPtr() {
172  return has_property<property::buffer::use_host_ptr>() ||
173  has_property<property::image::use_host_ptr>();
174  }
175 
176  bool canReadHostPtr(void *HostPtr, const size_t RequiredAlign) {
177  bool Aligned =
178  (reinterpret_cast<std::uintptr_t>(HostPtr) % RequiredAlign) == 0;
179  return Aligned || useHostPtr();
180  }
181 
182  bool canReuseHostPtr(void *HostPtr, const size_t RequiredAlign) {
183  return !MHostPtrReadOnly && canReadHostPtr(HostPtr, RequiredAlign);
184  }
185 
186  void handleHostData(void *HostPtr, const size_t RequiredAlign) {
187  MHostPtrProvided = true;
188  if (!MHostPtrReadOnly && HostPtr) {
189  set_final_data([HostPtr](const std::function<void(void *const Ptr)> &F) {
190  F(HostPtr);
191  });
192  }
193 
194  if (HostPtr) {
195  if (canReuseHostPtr(HostPtr, RequiredAlign)) {
196  MUserPtr = HostPtr;
197  } else if (canReadHostPtr(HostPtr, RequiredAlign)) {
198  MUserPtr = HostPtr;
199  MCreateShadowCopy = [this, RequiredAlign, HostPtr]() -> void {
200  setAlign(RequiredAlign);
203  std::memcpy(MUserPtr, HostPtr, MSizeInBytes);
204  };
205  } else {
206  setAlign(RequiredAlign);
209  std::memcpy(MUserPtr, HostPtr, MSizeInBytes);
210  }
211  }
212  }
213 
214  void handleHostData(const void *HostPtr, const size_t RequiredAlign) {
215  MHostPtrReadOnly = true;
216  handleHostData(const_cast<void *>(HostPtr), RequiredAlign);
217  }
218 
219  void handleHostData(const std::shared_ptr<void> &HostPtr,
220  const size_t RequiredAlign, bool IsConstPtr) {
221  MHostPtrProvided = true;
222  MSharedPtrStorage = HostPtr;
223  MHostPtrReadOnly = IsConstPtr;
224  if (HostPtr) {
225  if (!MHostPtrReadOnly)
227 
228  if (canReuseHostPtr(HostPtr.get(), RequiredAlign)) {
229  MUserPtr = HostPtr.get();
230  } else if (canReadHostPtr(HostPtr.get(), RequiredAlign)) {
231  MUserPtr = HostPtr.get();
232  MCreateShadowCopy = [this, RequiredAlign, HostPtr]() -> void {
233  setAlign(RequiredAlign);
236  std::memcpy(MUserPtr, HostPtr.get(), MSizeInBytes);
237  };
238  } else {
239  setAlign(RequiredAlign);
242  std::memcpy(MUserPtr, HostPtr.get(), MSizeInBytes);
243  }
244  }
245  }
246 
247  void handleHostData(const std::function<void(void *)> &CopyFromInput,
248  const size_t RequiredAlign, bool IsConstPtr) {
249  MHostPtrReadOnly = IsConstPtr;
250  setAlign(RequiredAlign);
251  if (useHostPtr())
253  "Buffer constructor from a pair of iterator values does "
254  "not support use_host_ptr property.");
255 
256  setAlign(RequiredAlign);
259 
260  CopyFromInput(MUserPtr);
261  }
262 
263  void setAlign(size_t RequiredAlign) {
264  MAllocator->setAlignment(RequiredAlign);
265  }
266 
267  static size_t getBufSizeForContext(const ContextImplPtr &Context,
268  ur_native_handle_t MemObject);
269 
271 
272  void *allocateMem(ContextImplPtr Context, bool InitFromUserData,
273  void *HostPtr, ur_event_handle_t &InteropEvent) override {
274  (void)Context;
275  (void)InitFromUserData;
276  (void)HostPtr;
277  (void)InteropEvent;
278  throw exception(make_error_code(errc::runtime), "Not implemented");
279  }
280 
281  MemObjType getType() const override { return MemObjType::Undefined; }
282 
283  ContextImplPtr getInteropContext() const override { return MInteropContext; }
284 
285  bool isInterop() const override;
286 
287  bool hasUserDataPtr() const override { return MUserPtr != nullptr; }
288 
289  bool isHostPointerReadOnly() const override { return MHostPtrReadOnly; }
290 
291  bool usesPinnedHostMemory() const override {
292  return has_property<
294  }
295 
296  void detachMemoryObject(const std::shared_ptr<SYCLMemObjT> &Self) const;
297 
298  void markAsInternal() { MIsInternal = true; }
299 
302 
306 
310  // Compare exchange loop to safely decrement MGraphUseCount
311  while (true) {
312  size_t CurrentVal = MGraphUseCount;
313  if (CurrentVal == 0) {
314  break;
315  }
316  if (MGraphUseCount.compare_exchange_strong(CurrentVal, CurrentVal - 1) ==
317  false) {
318  continue;
319  }
320  }
321  }
322 
324  bool isUsedInGraph() const { return MGraphUseCount > 0; }
325 
326  const property_list &getPropList() const { return MProps; }
327 
328 protected:
329  // An allocateMem helper that determines which host ptr to use
330  void determineHostPtr(bool InitFromUserData, void *&HostPtr,
331  bool &HostPtrReadOnly);
332 
333  // Allocator used for allocation memory on host.
334  std::unique_ptr<SYCLMemObjAllocator> MAllocator;
335  // Properties passed by user.
337  // Event passed by user to interoperability constructor.
338  // Should wait on this event before start working with such memory object.
340  // Context passed by user to interoperability constructor.
342  // Native backend memory object handle passed by user to interoperability
343  // constructor.
344  ur_mem_handle_t MInteropMemObject;
345  // Indicates whether memory object is created using interoperability
346  // constructor or not.
348  // Indicates if user provided pointer is read only.
350  // Indicates if memory object should write memory to the host on destruction.
352  // Size of memory.
353  size_t MSizeInBytes;
354  // User's pointer passed to constructor.
355  void *MUserPtr;
356  // Copy of memory passed by user to constructor.
357  void *MShadowCopy;
358  // Function which update host with final data on memory object destruction.
359  std::function<void(void)> MUploadDataFunctor;
360  // Field which holds user's shared_ptr in case of memory object is created
361  // using constructor with shared_ptr.
362  std::shared_ptr<const void> MSharedPtrStorage;
363  // Field to identify if dtor is not necessarily blocking.
364  // check for MUploadDataFunctor is not enough to define it since for case when
365  // we have read only HostPtr - MUploadDataFunctor is empty but delayed release
366  // must be not allowed.
368  // Indicates that the memory object was allocated internally. Such memory
369  // objects can be released in a deferred manner regardless of whether a host
370  // pointer was provided or not.
371  bool MIsInternal = false;
372  // The number of graphs which are currently using this memory object.
373  std::atomic<size_t> MGraphUseCount = 0;
374  // Function which creates a shadow copy of the host pointer. This is used to
375  // defer the memory allocation and copying to the point where a writable
376  // accessor is created.
377  std::function<void(void)> MCreateShadowCopy = []() -> void {};
378  bool MOwnNativeHandle = true;
379 };
380 } // namespace detail
381 } // namespace _V1
382 } // namespace sycl
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:50
const std::unique_ptr< SYCLMemObjAllocator > & get_allocator_internal() const
ContextImplPtr getInteropContext() const override
const PluginPtr & getPlugin() const
__SYCL2020_DEPRECATED("get_count() is deprecated, please use size() instead") size_t get_count() const
void detachMemoryObject(const std::shared_ptr< SYCLMemObjT > &Self) const
void determineHostPtr(bool InitFromUserData, void *&HostPtr, bool &HostPtrReadOnly)
virtual ~SYCLMemObjT()=default
bool has_property() const noexcept
void markNoLongerBeingUsedInGraph()
Decrement an internal counter for how many graphs are currently using this memory object.
size_t getSizeInBytes() const noexcept override
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)
bool needsWriteBack() const
Returns true if this memory object requires a write_back on destruction.
std::shared_ptr< const void > MSharedPtrStorage
const property_list & getPropList() const
MemObjType getType() const override
std::atomic< size_t > MGraphUseCount
bool hasUserDataPtr() const override
void releaseMem(ContextImplPtr Context, void *MemAllocation) 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)
void markBeingUsedInGraph()
Increment an internal counter for how many graphs are currently using this memory object.
bool canReadHostPtr(void *HostPtr, const size_t RequiredAlign)
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)
bool isHostPointerReadOnly() const override
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
std::function< void(void)> MCreateShadowCopy
bool isInterop() const override
static size_t getBufSizeForContext(const ContextImplPtr &Context, ur_native_handle_t MemObject)
void * allocateMem(ContextImplPtr Context, bool InitFromUserData, void *HostPtr, ur_event_handle_t &InteropEvent) override
bool usesPinnedHostMemory() const override
bool isUsedInGraph() const
Returns true if any graphs are currently using this memory object.
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)
An event object can be used to synchronize memory transfers, enqueues of kernels and signaling barrie...
Definition: event.hpp:44
Objects of the property_list class are containers for the SYCL properties.
bool has_property() const noexcept
void delete_accessor_property(const sycl::detail::PropWithDataKind &Kind)
void add_or_replace_accessor_properties(const property_list &PropertyList)
To cast(std::vector< cl_event > value)
std::shared_ptr< sycl::detail::context_impl > ContextImplPtr
Definition: event_impl.hpp:32
std::shared_ptr< event_impl > EventImplPtr
Definition: handler.hpp:183
std::shared_ptr< plugin > PluginPtr
Definition: ur.hpp:60
class __SYCL_EBO __SYCL_SPECIAL_CLASS Dimensions
std::error_code make_error_code(sycl::errc E) noexcept
Constructs an error code using e and sycl_category()
Definition: exception.cpp:65
Definition: access.hpp:18
_Abi const simd< _Tp, _Abi > & noexcept
Definition: simd.hpp:1324
C++ utilities for Unified Runtime integration.