DPC++ Runtime
Runtime libraries for oneAPI DPC++
backend.cpp
Go to the documentation of this file.
1 //==------------------- backend.cpp ----------------------------------------==//
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"
13 #include "detail/platform_impl.hpp"
14 #include "detail/plugin.hpp"
15 #include "detail/queue_impl.hpp"
16 #include <sycl/backend.hpp>
17 #include <sycl/detail/common.hpp>
18 #include <sycl/detail/export.hpp>
19 #include <sycl/detail/pi.h>
20 #include <sycl/detail/pi.hpp>
21 #include <sycl/exception.hpp>
22 #include <sycl/exception_list.hpp>
23 #include <sycl/kernel_bundle.hpp>
24 
25 #include <algorithm>
26 #include <memory>
27 
28 namespace sycl {
30 namespace detail {
31 
32 static const plugin &getPlugin(backend Backend) {
33  switch (Backend) {
34  case backend::opencl:
35  return pi::getPlugin<backend::opencl>();
36  case backend::ext_oneapi_level_zero:
37  return pi::getPlugin<backend::ext_oneapi_level_zero>();
38  case backend::ext_oneapi_cuda:
39  return pi::getPlugin<backend::ext_oneapi_cuda>();
40  default:
41  throw sycl::runtime_error{"Unsupported backend",
42  PI_ERROR_INVALID_OPERATION};
43  }
44 }
45 
47  const auto &Plugin = getPlugin(Backend);
48 
49  // Create PI platform first.
50  pi::PiPlatform PiPlatform = nullptr;
51  Plugin.call<PiApiKind::piextPlatformCreateWithNativeHandle>(NativeHandle,
52  &PiPlatform);
53 
54  return detail::createSyclObjFromImpl<platform>(
55  platform_impl::getOrMakePlatformImpl(PiPlatform, Plugin));
56 }
57 
58 __SYCL_EXPORT device make_device(pi_native_handle NativeHandle,
59  backend Backend) {
60  const auto &Plugin = getPlugin(Backend);
61 
62  pi::PiDevice PiDevice = nullptr;
63  Plugin.call<PiApiKind::piextDeviceCreateWithNativeHandle>(NativeHandle,
64  nullptr, &PiDevice);
65  // Construct the SYCL device from PI device.
66  return detail::createSyclObjFromImpl<device>(
67  std::make_shared<device_impl>(PiDevice, Plugin));
68 }
69 
70 __SYCL_EXPORT context make_context(pi_native_handle NativeHandle,
71  const async_handler &Handler,
72  backend Backend) {
73  const auto &Plugin = getPlugin(Backend);
74 
75  pi::PiContext PiContext = nullptr;
77  NativeHandle, 0, nullptr, false, &PiContext);
78  // Construct the SYCL context from PI context.
79  return detail::createSyclObjFromImpl<context>(
80  std::make_shared<context_impl>(PiContext, Handler, Plugin));
81 }
82 
83 queue make_queue_impl(pi_native_handle NativeHandle, const context &Context,
84  RT::PiDevice Device, bool KeepOwnership,
85  const async_handler &Handler, backend Backend) {
86  const auto &Plugin = getPlugin(Backend);
87  const auto &ContextImpl = getSyclObjImpl(Context);
88  // Create PI queue first.
89  pi::PiQueue PiQueue = nullptr;
91  NativeHandle, ContextImpl->getHandleRef(), Device, !KeepOwnership,
92  &PiQueue);
93  // Construct the SYCL queue from PI queue.
94  return detail::createSyclObjFromImpl<queue>(
95  std::make_shared<queue_impl>(PiQueue, ContextImpl, Handler));
96 }
97 
98 __SYCL_EXPORT queue make_queue(pi_native_handle NativeHandle,
99  const context &Context, const device *Device,
100  bool KeepOwnership, const async_handler &Handler,
101  backend Backend) {
102  if (Device) {
103  const auto &DeviceImpl = getSyclObjImpl(*Device);
104  return make_queue_impl(NativeHandle, Context, DeviceImpl->getHandleRef(),
105  KeepOwnership, Handler, Backend);
106  } else {
107  return make_queue_impl(NativeHandle, Context, nullptr, KeepOwnership,
108  Handler, Backend);
109  }
110 }
111 
112 __SYCL_EXPORT event make_event(pi_native_handle NativeHandle,
113  const context &Context, backend Backend) {
114  return make_event(NativeHandle, Context, false, Backend);
115 }
116 
117 __SYCL_EXPORT event make_event(pi_native_handle NativeHandle,
118  const context &Context, bool KeepOwnership,
119  backend Backend) {
120  const auto &Plugin = getPlugin(Backend);
121  const auto &ContextImpl = getSyclObjImpl(Context);
122 
123  pi::PiEvent PiEvent = nullptr;
125  NativeHandle, ContextImpl->getHandleRef(), !KeepOwnership, &PiEvent);
126 
127  event Event = detail::createSyclObjFromImpl<event>(
128  std::make_shared<event_impl>(PiEvent, Context));
129 
130  if (Backend == backend::opencl)
131  Plugin.call<PiApiKind::piEventRetain>(PiEvent);
132  return Event;
133 }
134 
135 std::shared_ptr<detail::kernel_bundle_impl>
136 make_kernel_bundle(pi_native_handle NativeHandle, const context &TargetContext,
137  bool KeepOwnership, bundle_state State, backend Backend) {
138  const auto &Plugin = getPlugin(Backend);
139  const auto &ContextImpl = getSyclObjImpl(TargetContext);
140 
141  pi::PiProgram PiProgram = nullptr;
143  NativeHandle, ContextImpl->getHandleRef(), !KeepOwnership, &PiProgram);
144  if (Plugin.getBackend() == backend::opencl)
146 
147  std::vector<pi::PiDevice> ProgramDevices;
148  size_t NumDevices = 0;
149 
150  Plugin.call<PiApiKind::piProgramGetInfo>(
151  PiProgram, PI_PROGRAM_INFO_NUM_DEVICES, sizeof(size_t), &NumDevices,
152  nullptr);
153  ProgramDevices.resize(NumDevices);
155  sizeof(pi::PiDevice) * NumDevices,
156  ProgramDevices.data(), nullptr);
157 
158  for (const auto &Dev : ProgramDevices) {
159  size_t BinaryType = 0;
161  PiProgram, Dev, PI_PROGRAM_BUILD_INFO_BINARY_TYPE, sizeof(size_t),
162  &BinaryType, nullptr);
163  switch (BinaryType) {
165  if (State == bundle_state::object)
167  PiProgram, 1, &Dev, nullptr, 0, nullptr, nullptr, nullptr, nullptr);
168  else if (State == bundle_state::executable)
170  PiProgram, 1, &Dev, nullptr, nullptr, nullptr);
171  break;
174  if (State == bundle_state::input)
175  // TODO SYCL2020 exception
176  throw sycl::runtime_error(errc::invalid,
177  "Program and kernel_bundle state mismatch",
178  PI_ERROR_INVALID_VALUE);
179  if (State == bundle_state::executable)
181  ContextImpl->getHandleRef(), 1, &Dev, nullptr, 1, &PiProgram,
182  nullptr, nullptr, &PiProgram);
183  break;
185  if (State == bundle_state::input || State == bundle_state::object)
186  // TODO SYCL2020 exception
187  throw sycl::runtime_error(errc::invalid,
188  "Program and kernel_bundle state mismatch",
189  PI_ERROR_INVALID_VALUE);
190  break;
191  }
192  }
193 
194  std::vector<device> Devices;
195  Devices.reserve(ProgramDevices.size());
196  std::transform(
197  ProgramDevices.begin(), ProgramDevices.end(), std::back_inserter(Devices),
198  [&Plugin](const auto &Dev) {
199  auto Platform =
200  detail::platform_impl::getPlatformFromPiDevice(Dev, Plugin);
201  auto DeviceImpl = Platform->getOrMakeDeviceImpl(Dev, Platform);
202  return createSyclObjFromImpl<device>(DeviceImpl);
203  });
204 
205  // Unlike SYCL, other backends, like OpenCL or Level Zero, may not support
206  // getting kernel IDs before executable is built. The SYCL Runtime workarounds
207  // this by pre-building the device image and extracting kernel info. We can't
208  // do the same to user images, since they may contain references to undefined
209  // symbols (e.g. when kernel_bundle is supposed to be joined with another).
210  auto KernelIDs = std::make_shared<std::vector<kernel_id>>();
211  auto DevImgImpl = std::make_shared<device_image_impl>(
212  nullptr, TargetContext, Devices, State, KernelIDs, PiProgram);
213  device_image_plain DevImg{DevImgImpl};
214 
215  return std::make_shared<kernel_bundle_impl>(TargetContext, Devices, DevImg);
216 }
217 
218 // TODO: Unused. Remove when allowed.
219 std::shared_ptr<detail::kernel_bundle_impl>
220 make_kernel_bundle(pi_native_handle NativeHandle, const context &TargetContext,
221  bundle_state State, backend Backend) {
222  return make_kernel_bundle(NativeHandle, TargetContext, false, State, Backend);
223 }
224 
225 kernel make_kernel(const context &TargetContext,
226  const kernel_bundle<bundle_state::executable> &KernelBundle,
227  pi_native_handle NativeHandle, bool KeepOwnership,
228  backend Backend) {
229  const auto &Plugin = getPlugin(Backend);
230  const auto &ContextImpl = getSyclObjImpl(TargetContext);
231  const auto KernelBundleImpl = getSyclObjImpl(KernelBundle);
232 
233  // For Level-Zero expect exactly one device image in the bundle. This is
234  // natural for interop kernel to get created out of a single native
235  // program/module. This way we don't need to search the exact device image for
236  // the kernel, which may not be trivial.
237  //
238  // Other backends don't need PI program.
239  //
240  pi::PiProgram PiProgram = nullptr;
241  if (Backend == backend::ext_oneapi_level_zero) {
242  if (KernelBundleImpl->size() != 1)
243  throw sycl::runtime_error{
244  "make_kernel: kernel_bundle must have single program image",
245  PI_ERROR_INVALID_PROGRAM};
246 
247  const device_image<bundle_state::executable> &DeviceImage =
248  *KernelBundle.begin();
249  const auto &DeviceImageImpl = getSyclObjImpl(DeviceImage);
250  PiProgram = DeviceImageImpl->get_program_ref();
251  }
252 
253  // Create PI kernel first.
254  pi::PiKernel PiKernel = nullptr;
256  NativeHandle, ContextImpl->getHandleRef(), PiProgram, !KeepOwnership,
257  &PiKernel);
258 
259  if (Backend == backend::opencl)
260  Plugin.call<PiApiKind::piKernelRetain>(PiKernel);
261 
262  // Construct the SYCL queue from PI queue.
263  return detail::createSyclObjFromImpl<kernel>(
264  std::make_shared<kernel_impl>(PiKernel, ContextImpl, KernelBundleImpl));
265 }
266 
267 kernel make_kernel(pi_native_handle NativeHandle, const context &TargetContext,
268  backend Backend) {
269  return make_kernel(
270  TargetContext,
271  get_empty_interop_kernel_bundle<bundle_state::executable>(TargetContext),
272  NativeHandle, false, Backend);
273 }
274 
275 } // namespace detail
276 } // __SYCL_INLINE_VER_NAMESPACE(_V1)
277 } // namespace sycl
sycl::_V1::build
kernel_bundle< bundle_state::executable > build(const kernel_bundle< bundle_state::input > &InputBundle, const std::vector< device > &Devs, const property_list &PropList={})
Definition: kernel_bundle.hpp:723
event_impl.hpp
pi.h
sycl::_V1::backend
backend
Definition: backend_types.hpp:21
context_impl.hpp
sycl::_V1::detail::make_kernel_bundle
std::shared_ptr< detail::kernel_bundle_impl > make_kernel_bundle(pi_native_handle NativeHandle, const context &TargetContext, bundle_state State, backend Backend)
Definition: backend.cpp:220
piProgramLink
pi_result piProgramLink(pi_context context, pi_uint32 num_devices, const pi_device *device_list, const char *options, pi_uint32 num_input_programs, const pi_program *input_programs, void(*pfn_notify)(pi_program program, void *user_data), void *user_data, pi_program *ret_program)
Definition: pi_opencl.cpp:1230
__SYCL_INLINE_VER_NAMESPACE
#define __SYCL_INLINE_VER_NAMESPACE(X)
Definition: defines_elementary.hpp:11
piProgramRetain
pi_result piProgramRetain(pi_program program)
Definition: pi_esimd_emulator.cpp:1353
sycl::_V1::detail::pi::PiDevice
::pi_device PiDevice
Definition: pi.hpp:124
piProgramCompile
pi_result piProgramCompile(pi_program program, pi_uint32 num_devices, const pi_device *device_list, const char *options, pi_uint32 num_input_headers, const pi_program *input_headers, const char **header_include_names, void(*pfn_notify)(pi_program program, void *user_data), void *user_data)
piextDeviceCreateWithNativeHandle
pi_result piextDeviceCreateWithNativeHandle(pi_native_handle nativeHandle, pi_platform platform, pi_device *device)
Creates PI device object from a native handle.
Definition: pi_esimd_emulator.cpp:831
sycl::_V1::kernel_bundle::begin
device_image_iterator begin() const
Definition: kernel_bundle.hpp:327
sycl
---— Error handling, matching OpenCL plugin semantics.
Definition: access.hpp:14
kernel_id_impl.hpp
sycl::_V1::device_image
Objects of the class represents an instance of an image in a specific state.
Definition: kernel_bundle.hpp:108
sycl::_V1::detail::make_kernel
kernel make_kernel(pi_native_handle NativeHandle, const context &TargetContext, backend Backend)
Definition: backend.cpp:267
plugin.hpp
_pi_platform
A PI platform stores all known PI devices, in the CUDA plugin this is just a vector of available devi...
Definition: pi_cuda.hpp:74
sycl::_V1::detail::pi::PiPlatform
::pi_platform PiPlatform
Definition: pi.hpp:123
queue_impl.hpp
piextEventCreateWithNativeHandle
pi_result piextEventCreateWithNativeHandle(pi_native_handle nativeHandle, pi_context context, bool ownNativeHandle, pi_event *event)
Creates PI event object from a native handle.
Definition: pi_esimd_emulator.cpp:1513
pi.hpp
sycl::_V1::opencl::make_context
context make_context(pi_native_handle NativeHandle)
Definition: opencl.cpp:38
sycl::_V1::detail::getPlugin
static const plugin & getPlugin(backend Backend)
Definition: backend.cpp:32
_pi_kernel
Implementation of a PI Kernel for CUDA.
Definition: pi_cuda.hpp:816
PI_PROGRAM_BINARY_TYPE_NONE
@ PI_PROGRAM_BINARY_TYPE_NONE
Definition: pi.h:178
sycl::_V1::detail::make_queue_impl
queue make_queue_impl(pi_native_handle NativeHandle, const context &Context, RT::PiDevice Device, bool KeepOwnership, const async_handler &Handler, backend Backend)
Definition: backend.cpp:83
piextContextCreateWithNativeHandle
pi_result piextContextCreateWithNativeHandle(pi_native_handle nativeHandle, pi_uint32 numDevices, const pi_device *devices, bool pluginOwnsNativeHandle, pi_context *context)
Creates PI context object from a native handle.
Definition: pi_esimd_emulator.cpp:881
piProgramGetInfo
pi_result piProgramGetInfo(pi_program program, pi_program_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret)
Definition: pi_esimd_emulator.cpp:1325
sycl::_V1::kernel
Provides an abstraction of a SYCL kernel.
Definition: kernel.hpp:71
PI_PROGRAM_BINARY_TYPE_EXECUTABLE
@ PI_PROGRAM_BINARY_TYPE_EXECUTABLE
Definition: pi.h:181
export.hpp
piextProgramCreateWithNativeHandle
pi_result piextProgramCreateWithNativeHandle(pi_native_handle nativeHandle, pi_context context, bool pluginOwnsNativeHandle, pi_program *program)
Creates PI program object from a native handle.
Definition: pi_esimd_emulator.cpp:1361
sycl::_V1::opencl::make_queue
queue make_queue(const context &Context, pi_native_handle InteropHandle)
Definition: opencl.cpp:45
_pi_queue
PI queue mapping on to CUstream objects.
Definition: pi_cuda.hpp:395
sycl::_V1::detail::plugin
The plugin class provides a unified interface to the underlying low-level runtimes for the device-agn...
Definition: plugin.hpp:90
platform_impl.hpp
kernel_bundle.hpp
sycl::_V1::queue
Encapsulates a single SYCL queue which schedules kernels on a SYCL device.
Definition: queue.hpp:89
sycl::_V1::detail::pi::PiContext
::pi_context PiContext
Definition: pi.hpp:128
piKernelRetain
pi_result piKernelRetain(pi_kernel kernel)
Definition: pi_esimd_emulator.cpp:1398
sycl::_V1::detail::pi::PiProgram
::pi_program PiProgram
Definition: pi.hpp:130
sycl::_V1::kernel_bundle< bundle_state::executable >
common.hpp
sycl::_V1::detail::pi::PiQueue
::pi_queue PiQueue
Definition: pi.hpp:132
piextPlatformCreateWithNativeHandle
pi_result piextPlatformCreateWithNativeHandle(pi_native_handle nativeHandle, pi_platform *platform)
Creates PI platform object from a native handle.
Definition: pi_esimd_emulator.cpp:480
sycl::_V1::device
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:49
_pi_program
Implementation of PI Program on CUDA Module object.
Definition: pi_cuda.hpp:760
pi_native_handle
uintptr_t pi_native_handle
Definition: pi.h:133
sycl::_V1::detail::pi::PiKernel
::pi_kernel PiKernel
Definition: pi.hpp:131
PI_PROGRAM_BINARY_TYPE_COMPILED_OBJECT
@ PI_PROGRAM_BINARY_TYPE_COMPILED_OBJECT
Definition: pi.h:179
sycl::_V1::detail::device_image_plain
Definition: kernel_bundle.hpp:76
exception.hpp
piEventRetain
pi_result piEventRetain(pi_event event)
Definition: pi_esimd_emulator.cpp:1478
_pi_event
PI Event mapping to CUevent.
Definition: pi_cuda.hpp:632
backend.hpp
sycl::_V1::async_handler
std::function< void(sycl::exception_list)> async_handler
Definition: exception_list.hpp:54
piProgramGetBuildInfo
pi_result piProgramGetBuildInfo(pi_program program, pi_device device, _pi_program_build_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret)
Definition: pi_esimd_emulator.cpp:1348
sycl::_V1::opencl::make_device
device make_device(pi_native_handle NativeHandle)
Definition: opencl.cpp:32
sycl::_V1::opencl::make_platform
platform make_platform(pi_native_handle NativeHandle)
Definition: opencl.cpp:26
kernel_bundle_impl.hpp
exception_list.hpp
sycl::_V1::platform
Encapsulates a SYCL platform on which kernels may be executed.
Definition: platform.hpp:45
sycl::_V1::bundle_state
bundle_state
Definition: kernel_bundle_enums.hpp:14
PI_PROGRAM_INFO_DEVICES
@ PI_PROGRAM_INFO_DEVICES
Definition: pi.h:339
PI_PROGRAM_INFO_NUM_DEVICES
@ PI_PROGRAM_INFO_NUM_DEVICES
Definition: pi.h:338
PI_PROGRAM_BINARY_TYPE_LIBRARY
@ PI_PROGRAM_BINARY_TYPE_LIBRARY
Definition: pi.h:180
piextKernelCreateWithNativeHandle
pi_result piextKernelCreateWithNativeHandle(pi_native_handle nativeHandle, pi_context context, pi_program program, bool pluginOwnsNativeHandle, pi_kernel *kernel)
Creates PI kernel object from a native handle.
Definition: pi_esimd_emulator.cpp:1874
sycl::_V1::detail::make_event
event make_event(pi_native_handle NativeHandle, const context &TargetContext, backend Backend)
Definition: backend.cpp:112
piProgramBuild
pi_result piProgramBuild(pi_program program, pi_uint32 num_devices, const pi_device *device_list, const char *options, void(*pfn_notify)(pi_program program, void *user_data), void *user_data)
PI_PROGRAM_BUILD_INFO_BINARY_TYPE
@ PI_PROGRAM_BUILD_INFO_BINARY_TYPE
Definition: pi.h:167
sycl::_V1::detail::pi::PiEvent
::pi_event PiEvent
Definition: pi.hpp:136
piextQueueCreateWithNativeHandle
pi_result piextQueueCreateWithNativeHandle(pi_native_handle nativeHandle, pi_context context, pi_device device, bool pluginOwnsNativeHandle, pi_queue *queue)
Creates PI queue object from a native handle.
Definition: pi_esimd_emulator.cpp:1018
_pi_context
PI context mapping to a CUDA context object.
Definition: pi_cuda.hpp:170
sycl::_V1::detail::getSyclObjImpl
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: common.hpp:300
_pi_device
PI device mapping to a CUdevice.
Definition: pi_cuda.hpp:83
sycl::_V1::context
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:41