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 <CL/sycl/backend.hpp>
19 #include <CL/sycl/detail/pi.h>
20 #include <CL/sycl/detail/pi.hpp>
21 #include <CL/sycl/exception.hpp>
24 
25 #include <algorithm>
26 #include <memory>
27 
29 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  default:
39  throw sycl::runtime_error{"Unsupported backend", PI_INVALID_OPERATION};
40  }
41 }
42 
44  const auto &Plugin = getPlugin(Backend);
45 
46  // Create PI platform first.
47  pi::PiPlatform PiPlatform = nullptr;
48  Plugin.call<PiApiKind::piextPlatformCreateWithNativeHandle>(NativeHandle,
49  &PiPlatform);
50 
51  return detail::createSyclObjFromImpl<platform>(
52  platform_impl::getOrMakePlatformImpl(PiPlatform, Plugin));
53 }
54 
55 __SYCL_EXPORT device make_device(pi_native_handle NativeHandle,
56  backend Backend) {
57  const auto &Plugin = getPlugin(Backend);
58 
59  pi::PiDevice PiDevice = nullptr;
60  Plugin.call<PiApiKind::piextDeviceCreateWithNativeHandle>(NativeHandle,
61  nullptr, &PiDevice);
62  // Construct the SYCL device from PI device.
63  return detail::createSyclObjFromImpl<device>(
64  std::make_shared<device_impl>(PiDevice, Plugin));
65 }
66 
67 __SYCL_EXPORT context make_context(pi_native_handle NativeHandle,
68  const async_handler &Handler,
69  backend Backend) {
70  const auto &Plugin = getPlugin(Backend);
71 
72  pi::PiContext PiContext = nullptr;
74  NativeHandle, 0, nullptr, false, &PiContext);
75  // Construct the SYCL context from PI context.
76  return detail::createSyclObjFromImpl<context>(
77  std::make_shared<context_impl>(PiContext, Handler, Plugin));
78 }
79 
80 queue make_queue_impl(pi_native_handle NativeHandle, const context &Context,
81  RT::PiDevice Device, bool KeepOwnership,
82  const async_handler &Handler, backend Backend) {
83  const auto &Plugin = getPlugin(Backend);
84  const auto &ContextImpl = getSyclObjImpl(Context);
85  // Create PI queue first.
86  pi::PiQueue PiQueue = nullptr;
88  NativeHandle, ContextImpl->getHandleRef(), Device, !KeepOwnership,
89  &PiQueue);
90  // Construct the SYCL queue from PI queue.
91  return detail::createSyclObjFromImpl<queue>(
92  std::make_shared<queue_impl>(PiQueue, ContextImpl, Handler));
93 }
94 
95 __SYCL_EXPORT queue make_queue(pi_native_handle NativeHandle,
96  const context &Context,
97  const async_handler &Handler, backend Backend) {
98  return make_queue_impl(NativeHandle, Context, nullptr, false, Handler,
99  Backend);
100 }
101 
102 __SYCL_EXPORT queue make_queue(pi_native_handle NativeHandle,
103  const context &Context, bool KeepOwnership,
104  const async_handler &Handler, backend Backend) {
105  return make_queue_impl(NativeHandle, Context, nullptr, KeepOwnership, Handler,
106  Backend);
107 }
108 
109 __SYCL_EXPORT queue make_queue(pi_native_handle NativeHandle,
110  const context &Context, const device &Device,
111  bool KeepOwnership, const async_handler &Handler,
112  backend Backend) {
113  const auto &DeviceImpl = getSyclObjImpl(Device);
114  return make_queue_impl(NativeHandle, Context, DeviceImpl->getHandleRef(),
115  KeepOwnership, Handler, Backend);
116 }
117 
118 __SYCL_EXPORT event make_event(pi_native_handle NativeHandle,
119  const context &Context, backend Backend) {
120  return make_event(NativeHandle, Context, false, Backend);
121 }
122 
123 __SYCL_EXPORT event make_event(pi_native_handle NativeHandle,
124  const context &Context, bool KeepOwnership,
125  backend Backend) {
126  const auto &Plugin = getPlugin(Backend);
127  const auto &ContextImpl = getSyclObjImpl(Context);
128 
129  pi::PiEvent PiEvent = nullptr;
131  NativeHandle, ContextImpl->getHandleRef(), !KeepOwnership, &PiEvent);
132 
133  return detail::createSyclObjFromImpl<event>(
134  std::make_shared<event_impl>(PiEvent, Context));
135 }
136 
137 std::shared_ptr<detail::kernel_bundle_impl>
138 make_kernel_bundle(pi_native_handle NativeHandle, const context &TargetContext,
139  bool KeepOwnership, bundle_state State, backend Backend) {
140  const auto &Plugin = getPlugin(Backend);
141  const auto &ContextImpl = getSyclObjImpl(TargetContext);
142 
143  pi::PiProgram PiProgram = nullptr;
145  NativeHandle, ContextImpl->getHandleRef(), KeepOwnership, &PiProgram);
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",
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",
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",
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 } // namespace sycl
277 } // __SYCL_INLINE_NAMESPACE(cl)
cl::sycl::backend
backend
Definition: backend_types.hpp:21
event_impl.hpp
pi.h
cl::sycl::kernel_bundle< bundle_state::executable >
context_impl.hpp
cl::sycl::opencl::make_platform
platform make_platform(pi_native_handle NativeHandle)
Definition: opencl.cpp:23
PI_INVALID_OPERATION
@ PI_INVALID_OPERATION
Definition: pi.h:88
cl::sycl::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:714
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:794
cl::sycl::opencl::make_device
device make_device(pi_native_handle NativeHandle)
Definition: opencl.cpp:29
cl::sycl::detail::getPlugin
static const plugin & getPlugin(backend Backend)
Definition: backend.cpp:32
cl::sycl::detail::pi::PiProgram
::pi_program PiProgram
Definition: pi.hpp:107
cl::sycl::kernel_bundle::begin
device_image_iterator begin() const
Definition: kernel_bundle.hpp:303
cl::sycl::detail::pi::PiKernel
::pi_kernel PiKernel
Definition: pi.hpp:108
cl::sycl::detail::device_image_plain
Definition: kernel_bundle.hpp:71
cl::sycl::detail::pi::PiDevice
::pi_device PiDevice
Definition: pi.hpp:102
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:822
sycl
Definition: invoke_simd.hpp:68
kernel_id_impl.hpp
cl::sycl::opencl::make_context
context make_context(pi_native_handle NativeHandle)
Definition: opencl.cpp:35
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:63
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:1467
cl::sycl::detail::pi::PiContext
::pi_context PiContext
Definition: pi.hpp:106
cl::sycl::queue
Encapsulates a single SYCL queue which schedules kernels on a SYCL device.
Definition: queue.hpp:103
pi.hpp
cl::sycl::bundle_state
bundle_state
Definition: kernel_bundle_enums.hpp:14
_pi_kernel
Implementation of a PI Kernel for CUDA.
Definition: pi_cuda.hpp:624
PI_PROGRAM_BINARY_TYPE_NONE
@ PI_PROGRAM_BINARY_TYPE_NONE
Definition: pi.h:164
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:872
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:1308
cl::sycl::detail::make_kernel
kernel make_kernel(pi_native_handle NativeHandle, const context &TargetContext, backend Backend)
Definition: backend.cpp:267
PI_PROGRAM_BINARY_TYPE_EXECUTABLE
@ PI_PROGRAM_BINARY_TYPE_EXECUTABLE
Definition: pi.h:168
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:1344
_pi_queue
PI queue mapping on to CUstream objects.
Definition: pi_cuda.hpp:378
cl::sycl::detail::pi::PiQueue
::pi_queue PiQueue
Definition: pi.hpp:109
platform_impl.hpp
cl::sycl::device
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:35
piProgramGetBuildInfo
pi_result piProgramGetBuildInfo(pi_program program, pi_device device, cl_program_build_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret)
Definition: pi_esimd_emulator.cpp:1331
kernel_bundle.hpp
cl::sycl::detail::make_event
event make_event(pi_native_handle NativeHandle, const context &TargetContext, backend Backend)
Definition: backend.cpp:118
cl::sycl::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:80
cl::sycl::device_image
Objects of the class represents an instance of an image in a specific state.
Definition: kernel_bundle.hpp:103
piKernelRetain
pi_result piKernelRetain(pi_kernel kernel)
Definition: pi_esimd_emulator.cpp:1381
cl
We provide new interfaces for matrix muliply in this patch:
Definition: access.hpp:13
cl::sycl::detail::pi::PiEvent
::pi_event PiEvent
Definition: pi.hpp:113
piextPlatformCreateWithNativeHandle
pi_result piextPlatformCreateWithNativeHandle(pi_native_handle nativeHandle, pi_platform *platform)
Creates PI platform object from a native handle.
Definition: pi_esimd_emulator.cpp:475
_pi_program
Implementation of PI Program on CUDA Module object.
Definition: pi_cuda.hpp:569
cl::sycl::detail::plugin
The plugin class provides a unified interface to the underlying low-level runtimes for the device-agn...
Definition: plugin.hpp:90
pi_native_handle
uintptr_t pi_native_handle
Definition: pi.h:76
cl::sycl::opencl::make_queue
queue make_queue(const context &Context, pi_native_handle InteropHandle)
Definition: opencl.cpp:52
cl::sycl::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
PI_PROGRAM_BINARY_TYPE_COMPILED_OBJECT
@ PI_PROGRAM_BINARY_TYPE_COMPILED_OBJECT
Definition: pi.h:165
PI_INVALID_VALUE
@ PI_INVALID_VALUE
Definition: pi.h:91
cl::sycl::detail::getSyclObjImpl
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: common.hpp:198
exception.hpp
cl::sycl::platform
Encapsulates a SYCL platform on which kernels may be executed.
Definition: platform.hpp:34
_pi_event
PI Event mapping to CUevent.
Definition: pi_cuda.hpp:458
backend.hpp
cl::sycl::context
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:35
kernel_bundle_impl.hpp
exception_list.hpp
common.hpp
PI_PROGRAM_INFO_DEVICES
@ PI_PROGRAM_INFO_DEVICES
Definition: pi.h:332
PI_PROGRAM_INFO_NUM_DEVICES
@ PI_PROGRAM_INFO_NUM_DEVICES
Definition: pi.h:331
PI_PROGRAM_BINARY_TYPE_LIBRARY
@ PI_PROGRAM_BINARY_TYPE_LIBRARY
Definition: pi.h:167
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:1820
cl::sycl::kernel
Provides an abstraction of a SYCL kernel.
Definition: kernel.hpp:67
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)
cl::sycl::async_handler
std::function< void(cl::sycl::exception_list)> async_handler
Definition: exception_list.hpp:53
cl::sycl::detail::pi::PiPlatform
::pi_platform PiPlatform
Definition: pi.hpp:101
PI_PROGRAM_BUILD_INFO_BINARY_TYPE
@ PI_PROGRAM_BUILD_INFO_BINARY_TYPE
Definition: pi.h:153
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:1002
PI_INVALID_PROGRAM
@ PI_INVALID_PROGRAM
Definition: pi.h:98
_pi_context
PI context mapping to a CUDA context object.
Definition: pi_cuda.hpp:150
_pi_device
PI device mapping to a CUdevice.
Definition: pi_cuda.hpp:73
__SYCL_INLINE_NAMESPACE
#define __SYCL_INLINE_NAMESPACE(X)
Definition: defines_elementary.hpp:12