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(pi_native_handle MemObject, const context &SyclContext,
21  const size_t, event AvailableEvent,
22  std::unique_ptr<SYCLMemObjAllocator> Allocator)
23  : SYCLMemObjT(MemObject, SyclContext, true, AvailableEvent,
24  std::move(Allocator)) {}
25 
26 SYCLMemObjT::SYCLMemObjT(pi_native_handle MemObject, const context &SyclContext,
27  bool OwnNativeHandle, event AvailableEvent,
28  std::unique_ptr<SYCLMemObjAllocator> Allocator)
29  : MAllocator(std::move(Allocator)), MProps(),
30  MInteropEvent(detail::getSyclObjImpl(std::move(AvailableEvent))),
31  MInteropContext(detail::getSyclObjImpl(SyclContext)),
32  MOpenCLInterop(true), MHostPtrReadOnly(false), MNeedWriteBack(true),
33  MUserPtr(nullptr), MShadowCopy(nullptr), MUploadDataFunctor(nullptr),
34  MSharedPtrStorage(nullptr), MHostPtrProvided(true),
35  MOwnNativeHandle(OwnNativeHandle) {
36  if (MInteropContext->is_host())
37  throw sycl::invalid_parameter_error(
38  "Creation of interoperability memory object using host context is "
39  "not allowed",
40  PI_ERROR_INVALID_CONTEXT);
41 
42  sycl::detail::pi::PiContext Context = nullptr;
43  const PluginPtr &Plugin = getPlugin();
44 
46  MemObject, MInteropContext->getHandleRef(), OwnNativeHandle,
48 
49  // Get the size of the buffer in bytes
50  Plugin->call<detail::PiApiKind::piMemGetInfo>(
51  MInteropMemObject, PI_MEM_SIZE, sizeof(size_t), &MSizeInBytes, nullptr);
52 
54  sizeof(Context), &Context, nullptr);
55 
56  if (MInteropContext->getHandleRef() != Context)
57  throw sycl::invalid_parameter_error(
58  "Input context must be the same as the context of cl_mem",
59  PI_ERROR_INVALID_CONTEXT);
60 
61  if (MInteropContext->getBackend() == backend::opencl)
63 }
64 
66  if (Dimensions == 1)
67  return PI_MEM_TYPE_IMAGE1D;
68  if (Dimensions == 2)
69  return PI_MEM_TYPE_IMAGE2D;
70  return PI_MEM_TYPE_IMAGE3D;
71 }
72 
73 SYCLMemObjT::SYCLMemObjT(pi_native_handle MemObject, const context &SyclContext,
74  bool OwnNativeHandle, event AvailableEvent,
75  std::unique_ptr<SYCLMemObjAllocator> Allocator,
78  range<3> Range3WithOnes, unsigned Dimensions,
79  size_t ElementSize)
80  : MAllocator(std::move(Allocator)), MProps(),
81  MInteropEvent(detail::getSyclObjImpl(std::move(AvailableEvent))),
82  MInteropContext(detail::getSyclObjImpl(SyclContext)),
83  MOpenCLInterop(true), MHostPtrReadOnly(false), MNeedWriteBack(true),
84  MUserPtr(nullptr), MShadowCopy(nullptr), MUploadDataFunctor(nullptr),
85  MSharedPtrStorage(nullptr), MHostPtrProvided(true),
86  MOwnNativeHandle(OwnNativeHandle) {
87  if (MInteropContext->is_host())
88  throw sycl::invalid_parameter_error(
89  "Creation of interoperability memory object using host context is "
90  "not allowed",
91  PI_ERROR_INVALID_CONTEXT);
92 
93  sycl::detail::pi::PiContext Context = nullptr;
94  const PluginPtr &Plugin = getPlugin();
95 
96  sycl::detail::pi::PiMemImageFormat Format{Order, Type};
99  Desc.image_width = Range3WithOnes[0];
100  Desc.image_height = Range3WithOnes[1];
101  Desc.image_depth = Range3WithOnes[2];
102  Desc.image_array_size = 0;
103  Desc.image_row_pitch = ElementSize * Desc.image_width;
105  Desc.num_mip_levels = 0;
106  Desc.num_samples = 0;
107  Desc.buffer = nullptr;
108 
110  MemObject, MInteropContext->getHandleRef(), OwnNativeHandle, &Format,
111  &Desc, &MInteropMemObject);
112 
114  sizeof(Context), &Context, nullptr);
115 
116  if (MInteropContext->getHandleRef() != Context)
117  throw sycl::invalid_parameter_error(
118  "Input context must be the same as the context of cl_mem",
119  PI_ERROR_INVALID_CONTEXT);
120 
121  if (MInteropContext->getBackend() == backend::opencl)
123 }
124 
125 void SYCLMemObjT::releaseMem(ContextImplPtr Context, void *MemAllocation) {
126  void *Ptr = getUserPtr();
127  return MemoryManager::releaseMemObj(Context, this, MemAllocation, Ptr);
128 }
129 
130 void SYCLMemObjT::updateHostMemory(void *const Ptr) {
131  const id<3> Offset{0, 0, 0};
132  const range<3> AccessRange{MSizeInBytes, 1, 1};
133  const range<3> MemoryRange{MSizeInBytes, 1, 1};
135  SYCLMemObjI *SYCLMemObject = this;
136  const int Dims = 1;
137  const int ElemSize = 1;
138 
139  Requirement Req(Offset, AccessRange, MemoryRange, AccessMode, SYCLMemObject,
140  Dims, ElemSize, size_t(0));
141  Req.MData = Ptr;
142 
144  if (Event)
145  Event->wait(Event);
146 }
147 
149  if ((MUploadDataFunctor != nullptr) && MNeedWriteBack)
151 
152  // If we're attached to a memory record, process the deletion of the memory
153  // record. We may get detached before we do this.
154  if (MRecord) {
155  bool Result = Scheduler::getInstance().removeMemoryObject(this);
156  std::ignore = Result; // for no assert build
157  assert(
158  Result &&
159  "removeMemoryObject should not return false in mem object destructor");
160  }
162 
163  if (MOpenCLInterop) {
164  const PluginPtr &Plugin = getPlugin();
165  Plugin->call<PiApiKind::piMemRelease>(
166  pi::cast<sycl::detail::pi::PiMem>(MInteropMemObject));
167  }
168 }
170  assert((MInteropContext != nullptr) &&
171  "Trying to get Plugin from SYCLMemObjT with nullptr ContextImpl.");
172  return (MInteropContext->getPlugin());
173 }
174 
176  pi_native_handle MemObject) {
177  size_t BufSize = 0;
178  const PluginPtr &Plugin = Context->getPlugin();
179  // TODO is there something required to support non-OpenCL backends?
180  Plugin->call<detail::PiApiKind::piMemGetInfo>(
181  detail::pi::cast<sycl::detail::pi::PiMem>(MemObject), PI_MEM_SIZE,
182  sizeof(size_t), &BufSize, nullptr);
183  return BufSize;
184 }
185 
186 bool SYCLMemObjT::isInterop() const { return MOpenCLInterop; }
187 
189  bool InitFromUserData, void *&HostPtr,
190  bool &HostPtrReadOnly) {
191  // The data for the allocation can be provided via either the user pointer
192  // (InitFromUserData, can be read-only) or a runtime-allocated read-write
193  // HostPtr. We can have one of these scenarios:
194  // 1. The allocation is the first one and on host. InitFromUserData == true.
195  // 2. The allocation is the first one and isn't on host. InitFromUserData
196  // varies based on unified host memory support and whether or not the data can
197  // be discarded.
198  // 3. The allocation is not the first one and is on host. InitFromUserData ==
199  // false, HostPtr == nullptr. This can only happen if the allocation command
200  // is not linked since it would be a no-op otherwise. Attempt to reuse the
201  // user pointer if it's read-write, but do not copy its contents if it's not.
202  // 4. The allocation is not the first one and not on host. InitFromUserData ==
203  // false, HostPtr is provided if the command is linked. The host pointer is
204  // guaranteed to be reused in this case.
205  if (Context->is_host() && !MOpenCLInterop && !MHostPtrReadOnly)
206  InitFromUserData = true;
207 
208  if (InitFromUserData) {
209  assert(!HostPtr && "Cannot init from user data and reuse host ptr provided "
210  "simultaneously");
211  HostPtr = getUserPtr();
212  HostPtrReadOnly = MHostPtrReadOnly;
213  } else
214  HostPtrReadOnly = false;
215 }
216 
218  const std::shared_ptr<SYCLMemObjT> &Self) const {
219  // Check MRecord without read lock because at this point we expect that no
220  // commands that operate on the buffer can be created. MRecord is nullptr on
221  // buffer creation and set to meaningfull
222  // value only if any operation on buffer submitted inside addCG call. addCG is
223  // called from queue::submit and buffer destruction could not overlap with it.
224  // For L0 context could be created with two ownership strategies - keep and
225  // transfer. If user keeps ownership - we could not enable deferred buffer
226  // release due to resource release conflict.
227  bool InteropObjectsUsed =
228  !MOwnNativeHandle ||
229  (MInteropContext && !MInteropContext->isOwnedByRuntime());
230 
231  if (MRecord && MRecord->MCurContext->isOwnedByRuntime() &&
232  !InteropObjectsUsed && (!MHostPtrProvided || MIsInternal))
234 }
235 
237  const auto InitialUserPtr = MUserPtr;
239  MCreateShadowCopy = []() -> void {};
240  if (MRecord != nullptr && MUserPtr != InitialUserPtr) {
241  for (auto &it : MRecord->MAllocaCommands) {
242  if (it->MMemAllocation == InitialUserPtr) {
243  it->MMemAllocation = MUserPtr;
244  }
245  }
246  }
247 }
248 
249 } // namespace detail
250 } // namespace _V1
251 } // namespace sycl
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:51
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
sycl::detail::pi::PiMem MInteropMemObject
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, pi_native_handle MemObject)
EventImplPtr addCopyBack(Requirement *Req)
Registers a command group, that copies most recent memory to the memory pointed by the requirement.
Definition: scheduler.cpp:223
static Scheduler & getInstance()
Definition: scheduler.cpp:261
bool removeMemoryObject(detail::SYCLMemObjI *MemObj, bool StrictLock=true)
Removes buffer from the graph.
Definition: scheduler.cpp:279
void deferMemObjRelease(const std::shared_ptr< detail::SYCLMemObjI > &MemObj)
Definition: scheduler.cpp:501
An event object can be used to synchronize memory transfers, enqueues of kernels and signaling barrie...
Definition: event.hpp:44
std::shared_ptr< sycl::detail::context_impl > ContextImplPtr
Definition: event_impl.hpp:32
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: impl_utils.hpp:30
sycl::detail::pi::PiMemObjectType getImageType(int Dimensions)
std::shared_ptr< event_impl > EventImplPtr
Definition: cg.hpp:43
std::shared_ptr< plugin > PluginPtr
Definition: pi.hpp:48
class __SYCL_EBO __SYCL_SPECIAL_CLASS __SYCL_TYPE(local_accessor) local_accessor class __SYCL_EBO __SYCL_SPECIAL_CLASS Dimensions
Definition: accessor.hpp:3233
class __SYCL_EBO __SYCL_SPECIAL_CLASS __SYCL_TYPE(local_accessor) local_accessor class __SYCL_EBO __SYCL_SPECIAL_CLASS AccessMode
Definition: accessor.hpp:3233
Definition: access.hpp:18
uintptr_t pi_native_handle
Definition: pi.h:217
_pi_image_channel_type
Definition: pi.h:658
pi_result piMemGetInfo(pi_mem mem, pi_mem_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret)
Definition: pi_cuda.cpp:217
_pi_image_channel_order
Definition: pi.h:640
pi_result piMemRetain(pi_mem mem)
Definition: pi_cuda.cpp:223
pi_result piMemRelease(pi_mem mem)
Definition: pi_cuda.cpp:225
_pi_mem_type
Definition: pi.h:588
@ PI_MEM_TYPE_IMAGE1D
Definition: pi.h:593
@ PI_MEM_TYPE_IMAGE2D
Definition: pi.h:590
@ PI_MEM_TYPE_IMAGE3D
Definition: pi.h:591
pi_result piextMemCreateWithNativeHandle(pi_native_handle nativeHandle, pi_context context, bool ownNativeHandle, pi_mem *mem)
Creates PI mem object from a native handle.
Definition: pi_cuda.cpp:241
@ PI_MEM_SIZE
Definition: pi.h:1183
@ PI_MEM_CONTEXT
Definition: pi.h:1183
pi_result piextMemImageCreateWithNativeHandle(pi_native_handle nativeHandle, pi_context context, bool ownNativeHandle, const pi_image_format *ImageFormat, const pi_image_desc *ImageDesc, pi_mem *img)
Creates PI image object from a native handle.
Definition: pi_cuda.cpp:264
size_t image_slice_pitch
Definition: pi.h:1174
pi_uint32 num_mip_levels
Definition: pi.h:1175
size_t image_height
Definition: pi.h:1170
size_t image_row_pitch
Definition: pi.h:1173
pi_uint32 num_samples
Definition: pi.h:1176
size_t image_depth
Definition: pi.h:1171
pi_mem buffer
Definition: pi.h:1177
size_t image_width
Definition: pi.h:1169
pi_mem_type image_type
Definition: pi.h:1168
size_t image_array_size
Definition: pi.h:1172