DPC++ Runtime
Runtime libraries for oneAPI DPC++
sycl_mem_obj_t.cpp
Go to the documentation of this file.
1 //==------------ sycl_mem_obj_t.cpp - 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 
10 #include <detail/event_impl.hpp>
12 #include <detail/plugin.hpp>
15 
16 namespace sycl {
17 inline namespace _V1 {
18 namespace detail {
19 
20 SYCLMemObjT::SYCLMemObjT(ur_native_handle_t MemObject,
21  const context &SyclContext, const size_t,
22  event AvailableEvent,
23  std::unique_ptr<SYCLMemObjAllocator> Allocator)
24  : SYCLMemObjT(MemObject, SyclContext, true, AvailableEvent,
25  std::move(Allocator)) {}
26 
27 SYCLMemObjT::SYCLMemObjT(ur_native_handle_t MemObject,
28  const context &SyclContext, bool OwnNativeHandle,
29  event AvailableEvent,
30  std::unique_ptr<SYCLMemObjAllocator> Allocator)
31  : MAllocator(std::move(Allocator)), MProps(),
32  MInteropEvent(detail::getSyclObjImpl(std::move(AvailableEvent))),
33  MInteropContext(detail::getSyclObjImpl(SyclContext)),
34  MOpenCLInterop(true), MHostPtrReadOnly(false), MNeedWriteBack(true),
35  MUserPtr(nullptr), MShadowCopy(nullptr), MUploadDataFunctor(nullptr),
36  MSharedPtrStorage(nullptr), MHostPtrProvided(true),
37  MOwnNativeHandle(OwnNativeHandle) {
38  ur_context_handle_t Context = nullptr;
39  const PluginPtr &Plugin = getPlugin();
40 
41  ur_mem_native_properties_t MemProperties = {
42  UR_STRUCTURE_TYPE_MEM_NATIVE_PROPERTIES, nullptr, OwnNativeHandle};
43  Plugin->call<UrApiKind::urMemBufferCreateWithNativeHandle>(
44  MemObject, MInteropContext->getHandleRef(), &MemProperties,
46 
47  // Get the size of the buffer in bytes
48  Plugin->call<UrApiKind::urMemGetInfo>(MInteropMemObject, UR_MEM_INFO_SIZE,
49  sizeof(size_t), &MSizeInBytes, nullptr);
50 
51  Plugin->call<UrApiKind::urMemGetInfo>(MInteropMemObject, UR_MEM_INFO_CONTEXT,
52  sizeof(Context), &Context, nullptr);
53 
54  if (MInteropContext->getHandleRef() != Context)
55  throw sycl::exception(
57  "Input context must be the same as the context of cl_mem");
58 
59  if (MInteropContext->getBackend() == backend::opencl)
60  Plugin->call<UrApiKind::urMemRetain>(MInteropMemObject);
61 }
62 
63 ur_mem_type_t getImageType(int Dimensions) {
64  if (Dimensions == 1)
65  return UR_MEM_TYPE_IMAGE1D;
66  if (Dimensions == 2)
67  return UR_MEM_TYPE_IMAGE2D;
68  return UR_MEM_TYPE_IMAGE3D;
69 }
70 
71 SYCLMemObjT::SYCLMemObjT(ur_native_handle_t MemObject,
72  const context &SyclContext, bool OwnNativeHandle,
73  event AvailableEvent,
74  std::unique_ptr<SYCLMemObjAllocator> Allocator,
75  ur_image_format_t Format, range<3> Range3WithOnes,
76  unsigned Dimensions, size_t ElementSize)
77  : MAllocator(std::move(Allocator)), MProps(),
78  MInteropEvent(detail::getSyclObjImpl(std::move(AvailableEvent))),
79  MInteropContext(detail::getSyclObjImpl(SyclContext)),
80  MOpenCLInterop(true), MHostPtrReadOnly(false), MNeedWriteBack(true),
81  MUserPtr(nullptr), MShadowCopy(nullptr), MUploadDataFunctor(nullptr),
82  MSharedPtrStorage(nullptr), MHostPtrProvided(true),
83  MOwnNativeHandle(OwnNativeHandle) {
84  ur_context_handle_t Context = nullptr;
85  const PluginPtr &Plugin = getPlugin();
86 
87  ur_image_desc_t Desc = {};
88  Desc.stype = UR_STRUCTURE_TYPE_IMAGE_DESC;
89  Desc.type = getImageType(Dimensions);
90  Desc.width = Range3WithOnes[0];
91  Desc.height = Range3WithOnes[1];
92  Desc.depth = Range3WithOnes[2];
93  Desc.arraySize = 0;
94  Desc.rowPitch = ElementSize * Desc.width;
95  Desc.slicePitch = Desc.rowPitch * Desc.height;
96  Desc.numMipLevel = 0;
97  Desc.numSamples = 0;
98 
99  ur_mem_native_properties_t NativeProperties = {
100  UR_STRUCTURE_TYPE_MEM_NATIVE_PROPERTIES, nullptr, OwnNativeHandle};
101 
102  Plugin->call<UrApiKind::urMemImageCreateWithNativeHandle>(
103  MemObject, MInteropContext->getHandleRef(), &Format, &Desc,
104  &NativeProperties, &MInteropMemObject);
105 
106  Plugin->call<UrApiKind::urMemGetInfo>(MInteropMemObject, UR_MEM_INFO_CONTEXT,
107  sizeof(Context), &Context, nullptr);
108 
109  if (MInteropContext->getHandleRef() != Context)
110  throw sycl::exception(
112  "Input context must be the same as the context of cl_mem");
113 
114  if (MInteropContext->getBackend() == backend::opencl)
115  Plugin->call<UrApiKind::urMemRetain>(MInteropMemObject);
116 }
117 
118 void SYCLMemObjT::releaseMem(ContextImplPtr Context, void *MemAllocation) {
119  void *Ptr = getUserPtr();
120  return MemoryManager::releaseMemObj(Context, this, MemAllocation, Ptr);
121 }
122 
123 void SYCLMemObjT::updateHostMemory(void *const Ptr) {
124  const id<3> Offset{0, 0, 0};
125  const range<3> AccessRange{MSizeInBytes, 1, 1};
126  const range<3> MemoryRange{MSizeInBytes, 1, 1};
128  SYCLMemObjI *SYCLMemObject = this;
129  const int Dims = 1;
130  const int ElemSize = 1;
131 
132  Requirement Req(Offset, AccessRange, MemoryRange, AccessMode, SYCLMemObject,
133  Dims, ElemSize, size_t(0));
134  Req.MData = Ptr;
135 
137  if (Event)
138  Event->wait(Event);
139 }
140 
142  if ((MUploadDataFunctor != nullptr) && MNeedWriteBack)
144 
145  // If we're attached to a memory record, process the deletion of the memory
146  // record. We may get detached before we do this.
147  if (MRecord) {
148  bool Result = Scheduler::getInstance().removeMemoryObject(this);
149  std::ignore = Result; // for no assert build
150  assert(
151  Result &&
152  "removeMemoryObject should not return false in mem object destructor");
153  }
155 
156  if (MOpenCLInterop) {
157  const PluginPtr &Plugin = getPlugin();
158  Plugin->call<UrApiKind::urMemRelease>(MInteropMemObject);
159  }
160 }
162  assert((MInteropContext != nullptr) &&
163  "Trying to get Plugin from SYCLMemObjT with nullptr ContextImpl.");
164  return (MInteropContext->getPlugin());
165 }
166 
168  ur_native_handle_t MemObject) {
169  size_t BufSize = 0;
170  const PluginPtr &Plugin = Context->getPlugin();
171  // TODO is there something required to support non-OpenCL backends?
172  Plugin->call<UrApiKind::urMemGetInfo>(
173  detail::ur::cast<ur_mem_handle_t>(MemObject), UR_MEM_INFO_SIZE,
174  sizeof(size_t), &BufSize, nullptr);
175  return BufSize;
176 }
177 
178 bool SYCLMemObjT::isInterop() const { return MOpenCLInterop; }
179 
181  bool InitFromUserData, void *&HostPtr,
182  bool &HostPtrReadOnly) {
183  // The data for the allocation can be provided via either the user pointer
184  // (InitFromUserData, can be read-only) or a runtime-allocated read-write
185  // HostPtr. We can have one of these scenarios:
186  // 1. The allocation is the first one and isn't on host. InitFromUserData
187  // varies based on unified host memory support and whether or not the data can
188  // be discarded.
189  // 2. The allocation is not the first one and not on host. InitFromUserData ==
190  // false, HostPtr is provided if the command is linked. The host pointer is
191  // guaranteed to be reused in this case.
192  if (!Context && !MOpenCLInterop && !MHostPtrReadOnly)
193  InitFromUserData = true;
194 
195  if (InitFromUserData) {
196  assert(!HostPtr && "Cannot init from user data and reuse host ptr provided "
197  "simultaneously");
198  HostPtr = getUserPtr();
199  HostPtrReadOnly = MHostPtrReadOnly;
200  } else
201  HostPtrReadOnly = false;
202 }
203 
205  const std::shared_ptr<SYCLMemObjT> &Self) const {
206  // Check MRecord without read lock because at this point we expect that no
207  // commands that operate on the buffer can be created. MRecord is nullptr on
208  // buffer creation and set to meaningfull
209  // value only if any operation on buffer submitted inside addCG call. addCG is
210  // called from queue::submit and buffer destruction could not overlap with it.
211  // For L0 context could be created with two ownership strategies - keep and
212  // transfer. If user keeps ownership - we could not enable deferred buffer
213  // release due to resource release conflict.
214  // MRecord->MCurContext == nullptr means that last submission to buffer is on
215  // host (host task), this execution doesn't depend on device context and fully
216  // controlled by RT. In this case deferred buffer destruction is allowed.
217  bool InteropObjectsUsed =
218  !MOwnNativeHandle ||
219  (MInteropContext && !MInteropContext->isOwnedByRuntime());
220 
221  if (MRecord &&
222  (!MRecord->MCurContext || MRecord->MCurContext->isOwnedByRuntime()) &&
223  !InteropObjectsUsed && (!MHostPtrProvided || MIsInternal)) {
224  bool okToDefer = GlobalHandler::instance().isOkToDefer();
225  if (okToDefer)
227  }
228 }
229 
231  const auto InitialUserPtr = MUserPtr;
232  {
233  std::lock_guard<std::mutex> Lock(MCreateShadowCopyMtx);
235  MCreateShadowCopy = []() -> void {};
236  }
237  if (MRecord != nullptr && MUserPtr != InitialUserPtr) {
238  for (auto &it : MRecord->MAllocaCommands) {
239  if (it->MMemAllocation == InitialUserPtr) {
240  it->MMemAllocation = MUserPtr;
241  }
242  }
243  }
244 }
245 
246 } // namespace detail
247 } // namespace _V1
248 } // namespace sycl
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:50
static GlobalHandler & instance()
static void releaseMemObj(ContextImplPtr TargetContext, SYCLMemObjI *MemObj, void *MemAllocation, void *UserPtr)
std::shared_ptr< MemObjRecord > MRecord
const PluginPtr & getPlugin() const
void detachMemoryObject(const std::shared_ptr< SYCLMemObjT > &Self) const
void determineHostPtr(const ContextImplPtr &Context, bool InitFromUserData, void *&HostPtr, bool &HostPtrReadOnly)
void releaseHostMem(void *Ptr) override
void releaseMem(ContextImplPtr Context, void *MemAllocation) override
SYCLMemObjT(const size_t SizeInBytes, const property_list &Props, std::unique_ptr< SYCLMemObjAllocator > Allocator)
std::function< void(void)> MUploadDataFunctor
std::function< void(void)> MCreateShadowCopy
bool isInterop() const override
static size_t getBufSizeForContext(const ContextImplPtr &Context, ur_native_handle_t MemObject)
EventImplPtr addCopyBack(Requirement *Req)
Registers a command group, that copies most recent memory to the memory pointed by the requirement.
Definition: scheduler.cpp:196
static Scheduler & getInstance()
Definition: scheduler.cpp:249
bool removeMemoryObject(detail::SYCLMemObjI *MemObj, bool StrictLock=true)
Removes buffer from the graph.
Definition: scheduler.cpp:267
void deferMemObjRelease(const std::shared_ptr< detail::SYCLMemObjI > &MemObj)
Definition: scheduler.cpp:474
An event object can be used to synchronize memory transfers, enqueues of kernels and signaling barrie...
Definition: event.hpp:44
decltype(Obj::impl) const & getSyclObjImpl(const Obj &SyclObject)
Definition: impl_utils.hpp:31
ur_mem_type_t getImageType(int Dimensions)
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:107
class __SYCL_EBO __SYCL_SPECIAL_CLASS Dimensions
class __SYCL_EBO __SYCL_SPECIAL_CLASS AccessMode
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