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(urMemBufferCreateWithNativeHandle, MemObject,
44  MInteropContext->getHandleRef(), &MemProperties,
46 
47  // Get the size of the buffer in bytes
48  Plugin->call(urMemGetInfo, MInteropMemObject, UR_MEM_INFO_SIZE,
49  sizeof(size_t), &MSizeInBytes, nullptr);
50 
51  Plugin->call(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(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(urMemImageCreateWithNativeHandle, MemObject,
103  MInteropContext->getHandleRef(), &Format, &Desc,
104  &NativeProperties, &MInteropMemObject);
105 
106  Plugin->call(urMemGetInfo, MInteropMemObject, UR_MEM_INFO_CONTEXT,
107  sizeof(Context), &Context, nullptr);
108 
109  if (MInteropContext->getHandleRef() != Context)
111  "Input context must be the same as the context of cl_mem");
112 
113  if (MInteropContext->getBackend() == backend::opencl)
114  Plugin->call(urMemRetain, MInteropMemObject);
115 }
116 
117 void SYCLMemObjT::releaseMem(ContextImplPtr Context, void *MemAllocation) {
118  void *Ptr = getUserPtr();
119  return MemoryManager::releaseMemObj(Context, this, MemAllocation, Ptr);
120 }
121 
122 void SYCLMemObjT::updateHostMemory(void *const Ptr) {
123  const id<3> Offset{0, 0, 0};
124  const range<3> AccessRange{MSizeInBytes, 1, 1};
125  const range<3> MemoryRange{MSizeInBytes, 1, 1};
127  SYCLMemObjI *SYCLMemObject = this;
128  const int Dims = 1;
129  const int ElemSize = 1;
130 
131  Requirement Req(Offset, AccessRange, MemoryRange, AccessMode, SYCLMemObject,
132  Dims, ElemSize, size_t(0));
133  Req.MData = Ptr;
134 
136  if (Event)
137  Event->wait(Event);
138 }
139 
141  if ((MUploadDataFunctor != nullptr) && MNeedWriteBack)
143 
144  // If we're attached to a memory record, process the deletion of the memory
145  // record. We may get detached before we do this.
146  if (MRecord) {
147  bool Result = Scheduler::getInstance().removeMemoryObject(this);
148  std::ignore = Result; // for no assert build
149  assert(
150  Result &&
151  "removeMemoryObject should not return false in mem object destructor");
152  }
154 
155  if (MOpenCLInterop) {
156  const PluginPtr &Plugin = getPlugin();
157  Plugin->call(urMemRelease, MInteropMemObject);
158  }
159 }
161  assert((MInteropContext != nullptr) &&
162  "Trying to get Plugin from SYCLMemObjT with nullptr ContextImpl.");
163  return (MInteropContext->getPlugin());
164 }
165 
167  ur_native_handle_t MemObject) {
168  size_t BufSize = 0;
169  const PluginPtr &Plugin = Context->getPlugin();
170  // TODO is there something required to support non-OpenCL backends?
171  Plugin->call(urMemGetInfo, detail::ur::cast<ur_mem_handle_t>(MemObject),
172  UR_MEM_INFO_SIZE, sizeof(size_t), &BufSize, nullptr);
173  return BufSize;
174 }
175 
176 bool SYCLMemObjT::isInterop() const { return MOpenCLInterop; }
177 
178 void SYCLMemObjT::determineHostPtr(bool InitFromUserData, void *&HostPtr,
179  bool &HostPtrReadOnly) {
180  // The data for the allocation can be provided via either the user pointer
181  // (InitFromUserData, can be read-only) or a runtime-allocated read-write
182  // HostPtr. We can have one of these scenarios:
183  // 1. The allocation is the first one and isn't on host. InitFromUserData
184  // varies based on unified host memory support and whether or not the data can
185  // be discarded.
186  // 2. The allocation is not the first one and not on host. InitFromUserData ==
187  // false, HostPtr is provided if the command is linked. The host pointer is
188  // guaranteed to be reused in this case.
189 
190  if (InitFromUserData) {
191  assert(!HostPtr && "Cannot init from user data and reuse host ptr provided "
192  "simultaneously");
193  HostPtr = getUserPtr();
194  HostPtrReadOnly = MHostPtrReadOnly;
195  } else
196  HostPtrReadOnly = false;
197 }
198 
200  const std::shared_ptr<SYCLMemObjT> &Self) const {
201  // Check MRecord without read lock because at this point we expect that no
202  // commands that operate on the buffer can be created. MRecord is nullptr on
203  // buffer creation and set to meaningfull
204  // value only if any operation on buffer submitted inside addCG call. addCG is
205  // called from queue::submit and buffer destruction could not overlap with it.
206  // For L0 context could be created with two ownership strategies - keep and
207  // transfer. If user keeps ownership - we could not enable deferred buffer
208  // release due to resource release conflict.
209  // MRecord->MCurContext == nullptr means that last submission to buffer is on
210  // host (host task), this execution doesn't depend on device context and fully
211  // controlled by RT. In this case deferred buffer destruction is allowed.
212  bool InteropObjectsUsed =
213  !MOwnNativeHandle ||
214  (MInteropContext && !MInteropContext->isOwnedByRuntime());
215 
216  if (MRecord &&
217  (!MRecord->MCurContext || MRecord->MCurContext->isOwnedByRuntime()) &&
218  !InteropObjectsUsed && (!MHostPtrProvided || MIsInternal)) {
219  bool okToDefer = GlobalHandler::instance().isOkToDefer();
220  if (okToDefer)
222  }
223 }
224 
226  const auto InitialUserPtr = MUserPtr;
228  MCreateShadowCopy = []() -> void {};
229  if (MRecord != nullptr && MUserPtr != InitialUserPtr) {
230  for (auto &it : MRecord->MAllocaCommands) {
231  if (it->MMemAllocation == InitialUserPtr) {
232  it->MMemAllocation = MUserPtr;
233  }
234  }
235  }
236 }
237 
238 } // namespace detail
239 } // namespace _V1
240 } // 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(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:208
static Scheduler & getInstance()
Definition: scheduler.cpp:248
bool removeMemoryObject(detail::SYCLMemObjI *MemObj, bool StrictLock=true)
Removes buffer from the graph.
Definition: scheduler.cpp:266
void deferMemObjRelease(const std::shared_ptr< detail::SYCLMemObjI > &MemObj)
Definition: scheduler.cpp:480
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:60
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