DPC++ Runtime
Runtime libraries for oneAPI DPC++
device.cpp
Go to the documentation of this file.
1 //==------------------- device.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/config.hpp>
11 #include <detail/device_impl.hpp>
14 #include <sycl/detail/export.hpp>
15 #include <sycl/device.hpp>
16 #include <sycl/device_selector.hpp>
17 #include <sycl/info/info_desc.hpp>
18 
19 namespace sycl {
20 inline namespace _V1 {
21 namespace detail {
23  if (t == info::device_type::all) {
24  t = ft;
25  } else if (ft != info::device_type::all && t != ft) {
26  throw sycl::invalid_parameter_error("No device of forced type.",
27  PI_ERROR_INVALID_OPERATION);
28  }
29 }
30 } // namespace detail
31 
33 
34 device::device(cl_device_id DeviceId) {
35  // The implementation constructor takes ownership of the native handle so we
36  // must retain it in order to adhere to SYCL 1.2.1 spec (Rev6, section 4.3.1.)
38  auto Plugin = sycl::detail::pi::getPlugin<backend::opencl>();
40  detail::pi::cast<pi_native_handle>(DeviceId), nullptr, &Device);
41  auto Platform =
43  impl = Platform->getOrMakeDeviceImpl(Device, Platform);
44  Plugin->call<detail::PiApiKind::piDeviceRetain>(impl->getHandleRef());
45 }
46 
47 device::device(const device_selector &deviceSelector) {
48  *this = deviceSelector.select_device();
49 }
50 
51 std::vector<device> device::get_devices(info::device_type deviceType) {
52  std::vector<device> devices;
53  detail::ods_target_list *OdsTargetList =
55 
56  auto thePlatforms = platform::get_platforms();
57  for (const auto &plt : thePlatforms) {
58 
59  backend platformBackend = plt.get_backend();
60  if (OdsTargetList && !OdsTargetList->backendCompatible(platformBackend))
61  continue;
62 
63  std::vector<device> found_devices(plt.get_devices(deviceType));
64  if (!found_devices.empty())
65  devices.insert(devices.end(), found_devices.begin(), found_devices.end());
66  }
67 
68  return devices;
69 }
70 
71 cl_device_id device::get() const { return impl->get(); }
72 
73 bool device::is_host() const {
74  bool IsHost = impl->is_host();
75  assert(!IsHost && "device::is_host should not be called in implementation.");
76  return IsHost;
77 }
78 
79 bool device::is_cpu() const { return impl->is_cpu(); }
80 
81 bool device::is_gpu() const { return impl->is_gpu(); }
82 
83 bool device::is_accelerator() const { return impl->is_accelerator(); }
84 
85 platform device::get_platform() const { return impl->get_platform(); }
86 
87 template <info::partition_property prop>
88 std::vector<device> device::create_sub_devices(size_t ComputeUnits) const {
89  return impl->create_sub_devices(ComputeUnits);
90 }
91 
92 template __SYCL_EXPORT std::vector<device>
93 device::create_sub_devices<info::partition_property::partition_equally>(
94  size_t ComputeUnits) const;
95 
96 template <info::partition_property prop>
97 std::vector<device>
98 device::create_sub_devices(const std::vector<size_t> &Counts) const {
99  return impl->create_sub_devices(Counts);
100 }
101 
102 template __SYCL_EXPORT std::vector<device>
103 device::create_sub_devices<info::partition_property::partition_by_counts>(
104  const std::vector<size_t> &Counts) const;
105 
106 template <info::partition_property prop>
107 std::vector<device> device::create_sub_devices(
108  info::partition_affinity_domain AffinityDomain) const {
109  return impl->create_sub_devices(AffinityDomain);
110 }
111 
112 template __SYCL_EXPORT std::vector<device> device::create_sub_devices<
114  info::partition_affinity_domain AffinityDomain) const;
115 
116 template <info::partition_property prop>
117 std::vector<device> device::create_sub_devices() const {
118  return impl->create_sub_devices();
119 }
120 
121 template __SYCL_EXPORT std::vector<device> device::create_sub_devices<
123 
124 bool device::has_extension(const std::string &extension_name) const {
125  return impl->has_extension(extension_name);
126 }
127 
128 template <typename Param>
130 device::get_info_impl() const {
131  return detail::convert_to_abi_neutral(impl->template get_info<Param>());
132 }
133 
134 // Explicit override. Not fulfilled by #include device_traits.def below.
135 template <>
136 __SYCL_EXPORT device
137 device::get_info_impl<info::device::parent_device>() const {
138  // With ONEAPI_DEVICE_SELECTOR the impl.MRootDevice is preset and may be
139  // overridden (ie it may be nullptr on a sub-device) The PI of the sub-devices
140  // have parents, but we don't want to return them. They must pretend to be
141  // parentless root devices.
142  if (impl->isRootDevice())
143  throw invalid_object_error(
144  "No parent for device because it is not a subdevice",
145  PI_ERROR_INVALID_DEVICE);
146  else
147  return impl->template get_info<info::device::parent_device>();
148 }
149 
150 template <>
151 __SYCL_EXPORT std::vector<sycl::aspect>
152 device::get_info_impl<info::device::aspects>() const {
153  std::vector<sycl::aspect> DeviceAspects{
154 #define __SYCL_ASPECT(ASPECT, ID) aspect::ASPECT,
155 #include <sycl/info/aspects.def>
156 #undef __SYCL_ASPECT
157  };
158 
159  auto UnsupportedAspects = std::remove_if(
160  DeviceAspects.begin(), DeviceAspects.end(), [&](aspect Aspect) {
161  try {
162  return !impl->has(Aspect);
163  } catch (const runtime_error &ex) {
164  if (ex.get_cl_code() == PI_ERROR_INVALID_DEVICE)
165  return true;
166  throw;
167  }
168  });
169 
170  DeviceAspects.erase(UnsupportedAspects, DeviceAspects.end());
171 
172  return DeviceAspects;
173 }
174 
175 template <>
176 __SYCL_EXPORT bool device::get_info_impl<info::device::image_support>() const {
177  // Explicit specialization is needed due to the class of info handle. The
178  // implementation is done in get_device_info_impl.
179  return impl->template get_info<info::device::image_support>();
180 }
181 
182 #define __SYCL_PARAM_TRAITS_SPEC(DescType, Desc, ReturnT, PiCode) \
183  template __SYCL_EXPORT detail::ABINeutralT_t<ReturnT> \
184  device::get_info_impl<info::device::Desc>() const;
185 
186 #define __SYCL_PARAM_TRAITS_SPEC_SPECIALIZED(DescType, Desc, ReturnT, PiCode)
187 
188 #include <sycl/info/device_traits.def>
189 #undef __SYCL_PARAM_TRAITS_SPEC_SPECIALIZED
190 #undef __SYCL_PARAM_TRAITS_SPEC
191 
192 #define __SYCL_PARAM_TRAITS_SPEC(Namespace, DescType, Desc, ReturnT, PiCode) \
193  template __SYCL_EXPORT detail::ABINeutralT_t<ReturnT> \
194  device::get_info_impl<Namespace::info::DescType::Desc>() const;
195 
196 #include <sycl/info/ext_codeplay_device_traits.def>
197 #include <sycl/info/ext_intel_device_traits.def>
198 #include <sycl/info/ext_oneapi_device_traits.def>
199 #undef __SYCL_PARAM_TRAITS_SPEC
200 
201 template <typename Param>
202 typename detail::is_backend_info_desc<Param>::return_type
203 device::get_backend_info() const {
204  return impl->get_backend_info<Param>();
205 }
206 
207 #define __SYCL_PARAM_TRAITS_SPEC(DescType, Desc, ReturnT, Picode) \
208  template __SYCL_EXPORT ReturnT \
209  device::get_backend_info<info::DescType::Desc>() const;
210 
211 #include <sycl/info/sycl_backend_traits.def>
212 
213 #undef __SYCL_PARAM_TRAITS_SPEC
214 
215 backend device::get_backend() const noexcept { return impl->getBackend(); }
216 
217 pi_native_handle device::getNative() const { return impl->getNative(); }
218 
219 bool device::has(aspect Aspect) const { return impl->has(Aspect); }
220 
221 void device::ext_oneapi_enable_peer_access(const device &peer) {
222  const sycl::detail::pi::PiDevice Device = impl->getHandleRef();
223  const sycl::detail::pi::PiDevice Peer = peer.impl->getHandleRef();
224  if (Device != Peer) {
225  auto Plugin = impl->getPlugin();
226  Plugin->call<detail::PiApiKind::piextEnablePeerAccess>(Device, Peer);
227  }
228 }
229 
230 void device::ext_oneapi_disable_peer_access(const device &peer) {
231  const sycl::detail::pi::PiDevice Device = impl->getHandleRef();
232  const sycl::detail::pi::PiDevice Peer = peer.impl->getHandleRef();
233  if (Device != Peer) {
234  auto Plugin = impl->getPlugin();
235  Plugin->call<detail::PiApiKind::piextDisablePeerAccess>(Device, Peer);
236  }
237 }
238 
239 bool device::ext_oneapi_can_access_peer(const device &peer,
241  const sycl::detail::pi::PiDevice Device = impl->getHandleRef();
242  const sycl::detail::pi::PiDevice Peer = peer.impl->getHandleRef();
243 
244  if (Device == Peer) {
245  return true;
246  }
247 
248  size_t returnSize;
249  int value;
250 
251  sycl::detail::pi::PiPeerAttr PiAttr = [&]() {
252  switch (attr) {
253  case ext::oneapi::peer_access::access_supported:
255  case ext::oneapi::peer_access::atomics_supported:
257  }
258  throw sycl::exception(make_error_code(errc::invalid),
259  "Unrecognized peer access attribute.");
260  }();
261  auto Plugin = impl->getPlugin();
263  Device, Peer, PiAttr, sizeof(int), &value, &returnSize);
264 
265  return value == 1;
266 }
267 
268 bool device::ext_oneapi_architecture_is(
270  return impl->extOneapiArchitectureIs(arch);
271 }
272 
273 bool device::ext_oneapi_architecture_is(
275  return impl->extOneapiArchitectureIs(category);
276 }
277 
278 // kernel_compiler extension methods
279 bool device::ext_oneapi_can_compile(
281  return impl->extOneapiCanCompile(Language);
282 }
283 
284 bool device::ext_oneapi_supports_cl_c_feature(const std::string &Feature) {
285  const detail::pi::PiDevice Device = impl->getHandleRef();
286  auto Plugin = impl->getPlugin();
287  uint32_t ipVersion = 0;
288  auto res = Plugin->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
289  Device, PI_EXT_ONEAPI_DEVICE_INFO_IP_VERSION, sizeof(uint32_t),
290  &ipVersion, nullptr);
291  if (res != PI_SUCCESS)
292  return false;
293 
295  Feature, ipVersion);
296 }
297 
298 bool device::ext_oneapi_supports_cl_c_version(
299  const ext::oneapi::experimental::cl_version &Version) const {
300  const detail::pi::PiDevice Device = impl->getHandleRef();
301  auto Plugin = impl->getPlugin();
302  uint32_t ipVersion = 0;
303  auto res = Plugin->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
304  Device, PI_EXT_ONEAPI_DEVICE_INFO_IP_VERSION, sizeof(uint32_t),
305  &ipVersion, nullptr);
306  if (res != PI_SUCCESS)
307  return false;
308 
310  ipVersion);
311 }
312 
313 bool device::ext_oneapi_supports_cl_extension(
314  const std::string &Name,
315  ext::oneapi::experimental::cl_version *VersionPtr) const {
316  const detail::pi::PiDevice Device = impl->getHandleRef();
317  auto Plugin = impl->getPlugin();
318  uint32_t ipVersion = 0;
319  auto res = Plugin->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
320  Device, PI_EXT_ONEAPI_DEVICE_INFO_IP_VERSION, sizeof(uint32_t),
321  &ipVersion, nullptr);
322  if (res != PI_SUCCESS)
323  return false;
324 
326  Name, VersionPtr, ipVersion);
327 }
328 
329 std::string device::ext_oneapi_cl_profile() const {
330  const detail::pi::PiDevice Device = impl->getHandleRef();
331  auto Plugin = impl->getPlugin();
332  uint32_t ipVersion = 0;
333  auto res = Plugin->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
334  Device, PI_EXT_ONEAPI_DEVICE_INFO_IP_VERSION, sizeof(uint32_t),
335  &ipVersion, nullptr);
336  if (res != PI_SUCCESS)
337  return "";
338 
340 }
341 
342 } // namespace _V1
343 } // namespace sycl
static const char * get()
Definition: config.hpp:115
bool backendCompatible(backend Backend)
static std::shared_ptr< platform_impl > getPlatformFromPiDevice(sycl::detail::pi::PiDevice PiDevice, const PluginPtr &Plugin)
Queries the cache for the specified platform based on an input device.
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:64
bool is_accelerator() const
Check if device is an accelerator device.
Definition: device.cpp:83
bool is_gpu() const
Check if device is a GPU device.
Definition: device.cpp:81
bool has_extension(const std::string &extension_name) const
Check SYCL extension support by device.
Definition: device.cpp:124
static std::vector< device > get_devices(info::device_type deviceType=info::device_type::all)
Query available SYCL devices.
Definition: device.cpp:51
bool is_cpu() const
Check if device is a CPU device.
Definition: device.cpp:79
std::vector< device > create_sub_devices() const
Partition device into sub devices.
Definition: device.cpp:117
device()
Constructs a SYCL device instance using the default device.
Definition: device.cpp:32
platform get_platform() const
Get associated SYCL platform.
Definition: device.cpp:85
Encapsulates a SYCL platform on which kernels may be executed.
Definition: platform.hpp:99
static std::vector< platform > get_platforms()
Returns all available SYCL platforms in the system.
Definition: platform.cpp:53
class __SYCL2020_DEPRECATED("Host device is no longer supported.") host_selector int default_selector_v(const device &dev)
Selects SYCL host device.
constexpr tuple_element< I, tuple< Types... > >::type & get(sycl::detail::tuple< Types... > &Arg) noexcept
Definition: tuple.hpp:198
auto convert_to_abi_neutral(ParamT &&Info)
Definition: platform.hpp:58
typename ABINeutralT< T >::type ABINeutralT_t
Definition: util.hpp:85
void force_type(info::device_type &t, const info::device_type &ft)
Definition: device.cpp:22
bool OpenCLC_Feature_Available(const std::string &Feature, uint32_t IPVersion)
bool OpenCLC_Supports_Extension(const std::string &Name, ext::oneapi::experimental::cl_version *VersionPtr, uint32_t IPVersion)
bool OpenCLC_Supports_Version(const ext::oneapi::experimental::cl_version &Version, uint32_t IPVersion)
std::error_code make_error_code(sycl::errc E) noexcept
Constructs an error code using e and sycl_category()
Definition: exception.cpp:87
Definition: access.hpp:18
pi_result piextDisablePeerAccess(pi_device command_device, pi_device peer_device)
Definition: pi_cuda.cpp:1258
pi_result piextEnablePeerAccess(pi_device command_device, pi_device peer_device)
Definition: pi_cuda.cpp:1252
uintptr_t pi_native_handle
Definition: pi.h:217
@ PI_EXT_ONEAPI_DEVICE_INFO_IP_VERSION
Definition: pi.h:392
pi_result piDeviceGetInfo(pi_device device, pi_device_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret)
Returns requested info for provided native device Return PI_DEVICE_INFO_EXTENSION_DEVICELIB_ASSERT fo...
Definition: pi_cuda.cpp:78
pi_result piextDeviceCreateWithNativeHandle(pi_native_handle nativeHandle, pi_platform platform, pi_device *device)
Creates PI device object from a native handle.
Definition: pi_cuda.cpp:106
pi_result piDeviceRetain(pi_device device)
Definition: pi_cuda.cpp:70
pi_result piextPeerAccessGetInfo(pi_device command_device, pi_device peer_device, pi_peer_attr attr, size_t param_value_size, void *param_value, size_t *param_value_size_ret)
Definition: pi_cuda.cpp:1264
_pi_peer_attr
Definition: pi.h:1185
@ PI_PEER_ACCESS_SUPPORTED
returns a uint32_t: 1 if P2P Access is supported otherwise P2P Access is not supported.
Definition: pi.h:1186
@ PI_PEER_ATOMICS_SUPPORTED
returns a uint32_t: 1 if Atomic operations are supported over the P2P link, otherwise such operations...
Definition: pi.h:1189
_Abi const simd< _Tp, _Abi > & noexcept
Definition: simd.hpp:1324