DPC++ Runtime
Runtime libraries for oneAPI DPC++
context_impl.cpp
Go to the documentation of this file.
1 //==---------------- context_impl.cpp - SYCL context -----------*- C++ -*---==//
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/context_info.hpp>
11 #include <detail/platform_impl.hpp>
12 #include <sycl/detail/common.hpp>
14 #include <sycl/detail/pi.hpp>
15 #include <sycl/device.hpp>
16 #include <sycl/exception.hpp>
17 #include <sycl/exception_list.hpp>
18 #include <sycl/info/info_desc.hpp>
19 #include <sycl/platform.hpp>
21 #include <sycl/property_list.hpp>
22 #include <sycl/stl.hpp>
23 
24 namespace sycl {
26 namespace detail {
27 
28 context_impl::context_impl(const device &Device, async_handler AsyncHandler,
29  const property_list &PropList)
30  : MAsyncHandler(AsyncHandler), MDevices(1, Device), MContext(nullptr),
31  MPlatform(), MPropList(PropList),
32  MHostContext(detail::getSyclObjImpl(Device)->is_host()),
33  MSupportBufferLocationByDevices(NotChecked) {
34  MKernelProgramCache.setContextPtr(this);
35 }
36 
37 context_impl::context_impl(const std::vector<sycl::device> Devices,
38  async_handler AsyncHandler,
39  const property_list &PropList)
40  : MAsyncHandler(AsyncHandler), MDevices(Devices), MContext(nullptr),
41  MPlatform(), MPropList(PropList), MHostContext(false),
42  MSupportBufferLocationByDevices(NotChecked) {
43  MPlatform = detail::getSyclObjImpl(MDevices[0].get_platform());
44  std::vector<RT::PiDevice> DeviceIds;
45  for (const auto &D : MDevices) {
46  DeviceIds.push_back(getSyclObjImpl(D)->getHandleRef());
47  }
48 
49  const auto Backend = getPlugin().getBackend();
50  if (Backend == backend::ext_oneapi_cuda) {
51  const bool UseCUDAPrimaryContext = MPropList.has_property<
53  const pi_context_properties Props[] = {
54  static_cast<pi_context_properties>(
56  static_cast<pi_context_properties>(UseCUDAPrimaryContext), 0};
57 
59  Props, DeviceIds.size(), DeviceIds.data(), nullptr, nullptr, &MContext);
60  } else {
61  getPlugin().call<PiApiKind::piContextCreate>(nullptr, DeviceIds.size(),
62  DeviceIds.data(), nullptr,
63  nullptr, &MContext);
64  }
65 
66  MKernelProgramCache.setContextPtr(this);
67 }
68 
70  const plugin &Plugin)
71  : MAsyncHandler(AsyncHandler), MDevices(), MContext(PiContext), MPlatform(),
72  MHostContext(false), MSupportBufferLocationByDevices(NotChecked) {
73 
74  std::vector<RT::PiDevice> DeviceIds;
75  size_t DevicesNum = 0;
76  // TODO catch an exception and put it to list of asynchronous exceptions
78  MContext, PI_CONTEXT_INFO_NUM_DEVICES, sizeof(DevicesNum), &DevicesNum,
79  nullptr);
80  DeviceIds.resize(DevicesNum);
81  // TODO catch an exception and put it to list of asynchronous exceptions
83  sizeof(RT::PiDevice) * DevicesNum,
84  &DeviceIds[0], nullptr);
85 
86  if (!DeviceIds.empty()) {
87  std::shared_ptr<detail::platform_impl> Platform =
88  platform_impl::getPlatformFromPiDevice(DeviceIds[0], Plugin);
89  for (RT::PiDevice Dev : DeviceIds) {
90  MDevices.emplace_back(createSyclObjFromImpl<device>(
91  Platform->getOrMakeDeviceImpl(Dev, Platform)));
92  }
93  MPlatform = Platform;
94  }
95  // TODO catch an exception and put it to list of asynchronous exceptions
96  // getPlugin() will be the same as the Plugin passed. This should be taken
97  // care of when creating device object.
98  //
99  // TODO: Move this backend-specific retain of the context to SYCL-2020 style
100  // make_context<backend::opencl> interop, when that is created.
101  if (getPlugin().getBackend() == sycl::backend::opencl) {
103  }
104  MKernelProgramCache.setContextPtr(this);
105 }
106 
107 cl_context context_impl::get() const {
108  if (MHostContext) {
109  throw invalid_object_error(
110  "This instance of context doesn't support OpenCL interoperability.",
111  PI_ERROR_INVALID_CONTEXT);
112  }
113  // TODO catch an exception and put it to list of asynchronous exceptions
115  return pi::cast<cl_context>(MContext);
116 }
117 
118 bool context_impl::is_host() const { return MHostContext; }
119 
121  for (auto LibProg : MCachedLibPrograms) {
122  assert(LibProg.second && "Null program must not be kept in the cache");
123  getPlugin().call<PiApiKind::piProgramRelease>(LibProg.second);
124  }
125  if (!MHostContext) {
126  // TODO catch an exception and put it to list of asynchronous exceptions
128  }
129 }
130 
132  return MAsyncHandler;
133 }
134 
135 template <>
136 uint32_t context_impl::get_info<info::context::reference_count>() const {
137  if (is_host())
138  return 0;
139  return get_context_info<info::context::reference_count>(this->getHandleRef(),
140  this->getPlugin());
141 }
142 template <> platform context_impl::get_info<info::context::platform>() const {
143  if (is_host())
144  return createSyclObjFromImpl<platform>(
146  return createSyclObjFromImpl<platform>(MPlatform);
147 }
148 template <>
149 std::vector<sycl::device>
150 context_impl::get_info<info::context::devices>() const {
151  return MDevices;
152 }
153 template <>
154 std::vector<sycl::memory_order>
155 context_impl::get_info<info::context::atomic_memory_order_capabilities>()
156  const {
157  if (is_host())
158  return {sycl::memory_order::relaxed, sycl::memory_order::acquire,
159  sycl::memory_order::release, sycl::memory_order::acq_rel,
160  sycl::memory_order::seq_cst};
161 
164  MContext,
165  PiInfoCode<info::context::atomic_memory_order_capabilities>::value,
166  sizeof(Result), &Result, nullptr);
167  return readMemoryOrderBitfield(Result);
168 }
169 template <>
170 std::vector<sycl::memory_scope>
171 context_impl::get_info<info::context::atomic_memory_scope_capabilities>()
172  const {
173  if (is_host())
174  return {sycl::memory_scope::work_item, sycl::memory_scope::sub_group,
175  sycl::memory_scope::work_group, sycl::memory_scope::device,
176  sycl::memory_scope::system};
177 
180  MContext,
181  PiInfoCode<info::context::atomic_memory_scope_capabilities>::value,
182  sizeof(Result), &Result, nullptr);
183  return readMemoryScopeBitfield(Result);
184 }
185 
187 const RT::PiContext &context_impl::getHandleRef() const { return MContext; }
188 
190  return MKernelProgramCache;
191 }
192 
194  std::shared_ptr<detail::device_impl> Device) const {
195  for (auto D : MDevices)
196  if (getSyclObjImpl(D) == Device)
197  return true;
198  return false;
199 }
200 
203  for (device D : MDevices)
204  if (getSyclObjImpl(D)->getHandleRef() == DevicePI)
205  return getSyclObjImpl(D);
206 
207  return nullptr;
208 }
209 
211  auto Plugin = getPlugin();
212  if (Plugin.getBackend() == backend::opencl)
214  pi_native_handle Handle;
215  Plugin.call<PiApiKind::piextContextGetNativeHandle>(getHandleRef(), &Handle);
216  return Handle;
217 }
218 
220  if (MSupportBufferLocationByDevices != NotChecked)
221  return MSupportBufferLocationByDevices == Supported ? true : false;
222  // Check that devices within context have support of buffer location
223  MSupportBufferLocationByDevices = Supported;
224  for (auto &Device : MDevices) {
225  if (!Device.has_extension("cl_intel_mem_alloc_buffer_location")) {
226  MSupportBufferLocationByDevices = NotSupported;
227  break;
228  }
229  }
230  return MSupportBufferLocationByDevices == Supported ? true : false;
231 }
232 
233 } // namespace detail
234 } // __SYCL_INLINE_VER_NAMESPACE(_V1)
235 } // namespace sycl
void setContextPtr(const ContextPtr &AContext)
bool hasDevice(std::shared_ptr< detail::device_impl > Device) const
Returns true if and only if context contains the given device.
context_impl(const device &Device, async_handler AsyncHandler, const property_list &PropList)
Constructs a context_impl using a single SYCL devices.
KernelProgramCache & getKernelProgramCache() const
pi_native_handle getNative() const
Gets the native handle of the SYCL context.
const plugin & getPlugin() const
DeviceImplPtr findMatchingDeviceImpl(RT::PiDevice &DevicePI) const
Given a PiDevice, returns the matching shared_ptr<device_impl> within this context.
bool is_host() const
Checks if this context is a host context.
cl_context get() const
Gets OpenCL interoperability context handle.
const async_handler & get_async_handler() const
Gets asynchronous exception handler.
RT::PiContext & getHandleRef()
Gets the underlying context object (if any) without reference count modification.
static std::shared_ptr< platform_impl > getHostPlatformImpl()
Static functions that help maintain platform uniquess and equality of comparison.
static std::shared_ptr< platform_impl > getPlatformFromPiDevice(RT::PiDevice PiDevice, const plugin &Plugin)
Queries the cache for the specified platform based on an input device.
The plugin class provides a unified interface to the underlying low-level runtimes for the device-agn...
Definition: plugin.hpp:90
void call(ArgsT... Args) const
Calls the API, traces the call, checks the result.
Definition: plugin.hpp:217
backend getBackend(void) const
Definition: plugin.hpp:229
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:49
Encapsulates a SYCL platform on which kernels may be executed.
Definition: platform.hpp:47
Objects of the property_list class are containers for the SYCL properties.
bool has_property() const noexcept
#define __SYCL_PI_CONTEXT_PROPERTIES_CUDA_PRIMARY
#define __SYCL_INLINE_VER_NAMESPACE(X)
::pi_device PiDevice
Definition: pi.hpp:110
::pi_context PiContext
Definition: pi.hpp:114
std::vector< memory_scope > readMemoryScopeBitfield(pi_memory_scope_capabilities bits)
static const plugin & getPlugin(backend Backend)
Definition: backend.cpp:32
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: common.hpp:248
std::shared_ptr< device_impl > DeviceImplPtr
std::vector< memory_order > readMemoryOrderBitfield(pi_memory_order_capabilities bits)
std::function< void(sycl::exception_list)> async_handler
---— Error handling, matching OpenCL plugin semantics.
Definition: access.hpp:14
uintptr_t pi_native_handle
Definition: pi.h:111
pi_result piProgramRelease(pi_program program)
pi_result piContextRetain(pi_context context)
intptr_t pi_context_properties
Definition: pi.h:510
pi_result piContextCreate(const pi_context_properties *properties, pi_uint32 num_devices, const pi_device *devices, void(*pfn_notify)(const char *errinfo, const void *private_info, size_t cb, void *user_data), void *user_data, pi_context *ret_context)
pi_result piextContextGetNativeHandle(pi_context context, pi_native_handle *nativeHandle)
Gets the native handle of a PI context object.
pi_bitfield pi_memory_scope_capabilities
Definition: pi.h:531
@ PI_CONTEXT_INFO_NUM_DEVICES
Definition: pi.h:322
@ PI_CONTEXT_INFO_DEVICES
Definition: pi.h:320
pi_result piContextRelease(pi_context context)
pi_result piContextGetInfo(pi_context context, pi_context_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret)
pi_bitfield pi_memory_order_capabilities
Definition: pi.h:524
C++ wrapper of extern "C" PI interfaces.
@ Device