DPC++ Runtime
Runtime libraries for oneAPI DPC++
kernel_impl.cpp
Go to the documentation of this file.
1 //==------- kernel_impl.cpp --- SYCL kernel implementation -----------------==//
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 
11 #include <detail/kernel_impl.hpp>
12 
13 #include <memory>
14 
15 namespace sycl {
16 inline namespace _V1 {
17 namespace detail {
18 
19 kernel_impl::kernel_impl(ur_kernel_handle_t Kernel, ContextImplPtr Context,
20  KernelBundleImplPtr KernelBundleImpl,
21  const KernelArgMask *ArgMask)
22  : MKernel(Kernel), MContext(Context),
23  MProgram(ProgramManager::getInstance().getUrProgramFromUrKernel(Kernel,
24  Context)),
25  MCreatedFromSource(true), MKernelBundleImpl(std::move(KernelBundleImpl)),
26  MIsInterop(true), MKernelArgMaskPtr{ArgMask} {
27  ur_context_handle_t UrContext = nullptr;
28  // Using the plugin from the passed ContextImpl
29  getPlugin()->call(urKernelGetInfo, MKernel, UR_KERNEL_INFO_CONTEXT,
30  sizeof(UrContext), &UrContext, nullptr);
31  if (Context->getHandleRef() != UrContext)
32  throw sycl::exception(
34  "Input context must be the same as the context of cl_kernel");
35 
36  // Enable USM indirect access for interoperability kernels.
37  // Some UR Plugins (like OpenCL) require this call to enable USM
38  // For others, UR will turn this into a NOP.
39  if (Context->getPlatformImpl()->supports_usm()) {
40  bool EnableAccess = true;
41  getPlugin()->call(urKernelSetExecInfo, MKernel,
42  UR_KERNEL_EXEC_INFO_USM_INDIRECT_ACCESS,
43  sizeof(ur_bool_t), nullptr, &EnableAccess);
44  }
45 }
46 
47 kernel_impl::kernel_impl(ur_kernel_handle_t Kernel, ContextImplPtr ContextImpl,
48  DeviceImageImplPtr DeviceImageImpl,
49  KernelBundleImplPtr KernelBundleImpl,
50  const KernelArgMask *ArgMask,
51  ur_program_handle_t Program, std::mutex *CacheMutex)
52  : MKernel(Kernel), MContext(std::move(ContextImpl)), MProgram(Program),
53  MCreatedFromSource(false), MDeviceImageImpl(std::move(DeviceImageImpl)),
54  MKernelBundleImpl(std::move(KernelBundleImpl)),
55  MKernelArgMaskPtr{ArgMask}, MCacheMutex{CacheMutex} {
56  MIsInterop = MKernelBundleImpl->isInterop();
57 }
58 
60  try {
61  // TODO catch an exception and put it to list of asynchronous exceptions
62  getPlugin()->call(urKernelRelease, MKernel);
63  } catch (std::exception &e) {
64  __SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~kernel_impl", e);
65  }
66 }
67 
69  // TODO it is not clear how to understand whether the SYCL kernel is created
70  // from source code or not when the SYCL kernel is created using
71  // the interoperability constructor.
72  // Here a strange case which does not work now:
73  // context Context;
74  // program Program(Context);
75  // Program.build_with_kernel_type<class A>();
76  // kernel FirstKernel= Program.get_kernel<class A>();
77  // cl_kernel ClKernel = FirstKernel.get();
78  // kernel SecondKernel = kernel(ClKernel, Context);
79  // clReleaseKernel(ClKernel);
80  // FirstKernel.isCreatedFromSource() != FirstKernel.isCreatedFromSource();
81  return MCreatedFromSource;
82 }
83 
84 bool kernel_impl::isBuiltInKernel(const device &Device) const {
85  auto BuiltInKernels = Device.get_info<info::device::built_in_kernel_ids>();
86  if (BuiltInKernels.empty())
87  return false;
88  std::string KernelName = get_info<info::kernel::function_name>();
89  return (std::any_of(
90  BuiltInKernels.begin(), BuiltInKernels.end(),
91  [&KernelName](kernel_id &Id) { return Id.get_name() == KernelName; }));
92 }
93 
94 void kernel_impl::checkIfValidForNumArgsInfoQuery() const {
95  if (MKernelBundleImpl->isInterop())
96  return;
97  auto Devices = MKernelBundleImpl->get_devices();
98  if (std::any_of(Devices.begin(), Devices.end(),
99  [this](device &Device) { return isBuiltInKernel(Device); }))
100  return;
101 
102  throw sycl::exception(
104  "info::kernel::num_args descriptor may only be used to query a kernel "
105  "that resides in a kernel bundle constructed using a backend specific"
106  "interoperability function or to query a device built-in kernel");
107 }
108 
109 template <>
110 typename info::platform::version::return_type
111 kernel_impl::get_backend_info<info::platform::version>() const {
112  if (MContext->getBackend() != backend::opencl) {
114  "the info::platform::version info descriptor can "
115  "only be queried with an OpenCL backend");
116  }
117  auto Devices = MKernelBundleImpl->get_devices();
118  return Devices[0].get_platform().get_info<info::platform::version>();
119 }
120 
121 device select_device(DSelectorInvocableType DeviceSelectorInvocable,
122  std::vector<device> &Devices);
123 
124 template <>
125 typename info::device::version::return_type
126 kernel_impl::get_backend_info<info::device::version>() const {
127  if (MContext->getBackend() != backend::opencl) {
129  "the info::device::version info descriptor can only "
130  "be queried with an OpenCL backend");
131  }
132  auto Devices = MKernelBundleImpl->get_devices();
133  if (Devices.empty()) {
134  return "No available device";
135  }
136  // Use default selector to pick a device.
137  return select_device(default_selector_v, Devices)
138  .get_info<info::device::version>();
139 }
140 
141 template <>
142 typename info::device::backend_version::return_type
143 kernel_impl::get_backend_info<info::device::backend_version>() const {
144  if (MContext->getBackend() != backend::ext_oneapi_level_zero) {
146  "the info::device::backend_version info descriptor "
147  "can only be queried with a Level Zero backend");
148  }
149  return "";
150  // Currently The Level Zero backend does not define the value of this
151  // information descriptor and implementations are encouraged to return the
152  // empty string as per specification.
153 }
154 
155 } // namespace detail
156 } // namespace _V1
157 } // namespace sycl
bool isCreatedFromSource() const
Check if kernel was created from a program that had been created from source.
Definition: kernel_impl.cpp:68
const PluginPtr & getPlugin() const
Definition: kernel_impl.hpp:83
kernel_impl(ur_kernel_handle_t Kernel, ContextImplPtr Context, KernelBundleImplPtr KernelBundleImpl, const KernelArgMask *ArgMask=nullptr)
Constructs a SYCL kernel instance from a UrKernel.
Definition: kernel_impl.cpp:19
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:64
detail::is_device_info_desc< Param >::return_type get_info() const
Queries this SYCL device for information requested by the template parameter param.
Definition: device.hpp:215
Objects of the class identify kernel is some kernel_bundle related APIs.
#define __SYCL_REPORT_EXCEPTION_TO_STREAM(str, e)
Definition: common.hpp:367
std::shared_ptr< device_image_impl > DeviceImageImplPtr
std::vector< bool > KernelArgMask
std::shared_ptr< sycl::detail::context_impl > ContextImplPtr
Definition: event_impl.hpp:32
std::function< int(const sycl::device &)> DSelectorInvocableType
device select_device(const DSelectorInvocableType &DeviceSelectorInvocable)
std::shared_ptr< detail::kernel_bundle_impl > KernelBundleImplPtr
int default_selector_v(const device &dev)
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
bool any_of(const simd_mask< _Tp, _Abi > &) noexcept