DPC++ Runtime
Runtime libraries for oneAPI DPC++
device_impl.cpp
Go to the documentation of this file.
1 //==----------------- device_impl.cpp - SYCL device ------------------------==//
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 
9 #include <detail/device_impl.hpp>
10 #include <detail/device_info.hpp>
11 #include <detail/platform_impl.hpp>
12 #include <sycl/device.hpp>
13 
14 #include <algorithm>
15 
16 namespace sycl {
17 inline namespace _V1 {
18 namespace detail {
19 
21  : MIsHostDevice(true), MPlatform(platform_impl::getHostPlatformImpl()),
22  // assert is natively supported by host
23  MIsAssertFailSupported(true) {}
24 
26  const PluginPtr &Plugin)
27  : device_impl(InteropDeviceHandle, nullptr, nullptr, Plugin) {}
28 
30  PlatformImplPtr Platform)
31  : device_impl(reinterpret_cast<pi_native_handle>(nullptr), Device, Platform,
32  Platform->getPlugin()) {}
33 
35  const PluginPtr &Plugin)
36  : device_impl(reinterpret_cast<pi_native_handle>(nullptr), Device, nullptr,
37  Plugin) {}
38 
39 device_impl::device_impl(pi_native_handle InteropDeviceHandle,
41  PlatformImplPtr Platform, const PluginPtr &Plugin)
42  : MDevice(Device), MIsHostDevice(false),
43  MDeviceHostBaseTime(std::make_pair(0, 0)) {
44 
45  bool InteroperabilityConstructor = false;
46  if (Device == nullptr) {
47  assert(InteropDeviceHandle);
48  // Get PI device from the raw device handle.
49  // NOTE: this is for OpenCL interop only (and should go away).
50  // With SYCL-2020 BE generalization "make" functions are used instead.
52  InteropDeviceHandle, nullptr, &MDevice);
53  InteroperabilityConstructor = true;
54  }
55 
56  // TODO catch an exception and put it to list of asynchronous exceptions
57  Plugin->call<PiApiKind::piDeviceGetInfo>(
59  &MType, nullptr);
60 
61  // No need to set MRootDevice when MAlwaysRootDevice is true
62  if ((Platform == nullptr) || !Platform->MAlwaysRootDevice) {
63  // TODO catch an exception and put it to list of asynchronous exceptions
64  Plugin->call<PiApiKind::piDeviceGetInfo>(
66  sizeof(sycl::detail::pi::PiDevice), &MRootDevice, nullptr);
67  }
68 
69  if (!InteroperabilityConstructor) {
70  // TODO catch an exception and put it to list of asynchronous exceptions
71  // Interoperability Constructor already calls DeviceRetain in
72  // piextDeviceFromNative.
73  Plugin->call<PiApiKind::piDeviceRetain>(MDevice);
74  }
75 
76  // set MPlatform
77  if (!Platform) {
78  Platform = platform_impl::getPlatformFromPiDevice(MDevice, Plugin);
79  }
80  MPlatform = Platform;
81 
82  MIsAssertFailSupported =
84 }
85 
87  if (!MIsHostDevice) {
88  // TODO catch an exception and put it to list of asynchronous exceptions
89  const PluginPtr &Plugin = getPlugin();
91  Plugin->call_nocheck<PiApiKind::piDeviceRelease>(MDevice);
93  }
94 }
95 
97  info::partition_affinity_domain AffinityDomain) const {
98  auto SupportedDomains = get_info<info::device::partition_affinity_domains>();
99  return std::find(SupportedDomains.begin(), SupportedDomains.end(),
100  AffinityDomain) != SupportedDomains.end();
101 }
102 
103 cl_device_id device_impl::get() const {
104  if (MIsHostDevice) {
105  throw invalid_object_error(
106  "This instance of device doesn't support OpenCL interoperability.",
107  PI_ERROR_INVALID_DEVICE);
108  }
109  // TODO catch an exception and put it to list of asynchronous exceptions
110  getPlugin()->call<PiApiKind::piDeviceRetain>(MDevice);
111  return pi::cast<cl_device_id>(getNative());
112 }
113 
115  return createSyclObjFromImpl<platform>(MPlatform);
116 }
117 
118 template <typename Param>
119 typename Param::return_type device_impl::get_info() const {
120  if (is_host()) {
121  return get_device_info_host<Param>();
122  }
123  return get_device_info<Param>(
124  MPlatform->getOrMakeDeviceImpl(MDevice, MPlatform));
125 }
126 // Explicitly instantiate all device info traits
127 #define __SYCL_PARAM_TRAITS_SPEC(DescType, Desc, ReturnT, PiCode) \
128  template ReturnT device_impl::get_info<info::device::Desc>() const;
129 
130 #define __SYCL_PARAM_TRAITS_SPEC_SPECIALIZED(DescType, Desc, ReturnT, PiCode) \
131  template ReturnT device_impl::get_info<info::device::Desc>() const;
132 
133 #include <sycl/info/device_traits.def>
134 #undef __SYCL_PARAM_TRAITS_SPEC_SPECIALIZED
135 #undef __SYCL_PARAM_TRAITS_SPEC
136 
137 #define __SYCL_PARAM_TRAITS_SPEC(Namespace, DescType, Desc, ReturnT, PiCode) \
138  template __SYCL_EXPORT ReturnT \
139  device_impl::get_info<Namespace::info::DescType::Desc>() const;
140 
141 #include <sycl/info/ext_codeplay_device_traits.def>
142 #include <sycl/info/ext_intel_device_traits.def>
143 #include <sycl/info/ext_oneapi_device_traits.def>
144 #undef __SYCL_PARAM_TRAITS_SPEC
145 
146 template <>
147 typename info::platform::version::return_type
148 device_impl::get_backend_info<info::platform::version>() const {
149  if (getBackend() != backend::opencl) {
151  "the info::platform::version info descriptor can "
152  "only be queried with an OpenCL backend");
153  }
154  return get_platform().get_info<info::platform::version>();
155 }
156 
157 template <>
158 typename info::device::version::return_type
159 device_impl::get_backend_info<info::device::version>() const {
160  if (getBackend() != backend::opencl) {
162  "the info::device::version info descriptor can only "
163  "be queried with an OpenCL backend");
164  }
165  return get_info<info::device::version>();
166 }
167 
168 template <>
169 typename info::device::backend_version::return_type
170 device_impl::get_backend_info<info::device::backend_version>() const {
171  if (getBackend() != backend::ext_oneapi_level_zero) {
173  "the info::device::backend_version info descriptor "
174  "can only be queried with a Level Zero backend");
175  }
176  return "";
177  // Currently The Level Zero backend does not define the value of this
178  // information descriptor and implementations are encouraged to return the
179  // empty string as per specification.
180 }
181 
182 bool device_impl::has_extension(const std::string &ExtensionName) const {
183  if (MIsHostDevice)
184  // TODO: implement extension management for host device;
185  return false;
186  std::string AllExtensionNames =
188  return (AllExtensionNames.find(ExtensionName) != std::string::npos);
189 }
190 
192  auto SupportedProperties = get_info<info::device::partition_properties>();
193  return std::find(SupportedProperties.begin(), SupportedProperties.end(),
194  Prop) != SupportedProperties.end();
195 }
196 
197 std::vector<device>
198 device_impl::create_sub_devices(const cl_device_partition_property *Properties,
199  size_t SubDevicesCount) const {
200 
201  std::vector<sycl::detail::pi::PiDevice> SubDevices(SubDevicesCount);
202  pi_uint32 ReturnedSubDevices = 0;
203  const PluginPtr &Plugin = getPlugin();
204  Plugin->call<sycl::errc::invalid, PiApiKind::piDevicePartition>(
205  MDevice, Properties, SubDevicesCount, SubDevices.data(),
206  &ReturnedSubDevices);
207  if (ReturnedSubDevices != SubDevicesCount) {
208  throw sycl::exception(
210  "Could not partition to the specified number of sub-devices");
211  }
212  // TODO: Need to describe the subdevice model. Some sub_device management
213  // may be necessary. What happens if create_sub_devices is called multiple
214  // times with the same arguments?
215  //
216  std::vector<device> res;
217  std::for_each(SubDevices.begin(), SubDevices.end(),
218  [&res, this](const sycl::detail::pi::PiDevice &a_pi_device) {
219  device sycl_device = detail::createSyclObjFromImpl<device>(
220  MPlatform->getOrMakeDeviceImpl(a_pi_device, MPlatform));
221  res.push_back(sycl_device);
222  });
223  return res;
224 }
225 
226 std::vector<device> device_impl::create_sub_devices(size_t ComputeUnits) const {
227  assert(!MIsHostDevice && "Partitioning is not supported on host.");
228 
230  throw sycl::feature_not_supported(
231  "Device does not support "
232  "sycl::info::partition_property::partition_equally.",
233  PI_ERROR_INVALID_OPERATION);
234  }
235  // If count exceeds the total number of compute units in the device, an
236  // exception with the errc::invalid error code must be thrown.
237  auto MaxComputeUnits = get_info<info::device::max_compute_units>();
238  if (ComputeUnits > MaxComputeUnits)
240  "Total counts exceed max compute units");
241 
242  size_t SubDevicesCount = MaxComputeUnits / ComputeUnits;
243  const pi_device_partition_property Properties[3] = {
245  0};
246  return create_sub_devices(Properties, SubDevicesCount);
247 }
248 
249 std::vector<device>
250 device_impl::create_sub_devices(const std::vector<size_t> &Counts) const {
251  assert(!MIsHostDevice && "Partitioning is not supported on host.");
252 
254  throw sycl::feature_not_supported(
255  "Device does not support "
256  "sycl::info::partition_property::partition_by_counts.",
257  PI_ERROR_INVALID_OPERATION);
258  }
259  static const pi_device_partition_property P[] = {
261  std::vector<pi_device_partition_property> Properties(P, P + 3);
262 
263  // Fill the properties vector with counts and validate it
264  auto It = Properties.begin() + 1;
265  size_t TotalCounts = 0;
266  size_t NonZeroCounts = 0;
267  for (auto Count : Counts) {
268  TotalCounts += Count;
269  NonZeroCounts += (Count != 0) ? 1 : 0;
270  It = Properties.insert(It, Count);
271  }
272 
273  // If the number of non-zero values in counts exceeds the device’s maximum
274  // number of sub devices (as returned by info::device::
275  // partition_max_sub_devices) an exception with the errc::invalid
276  // error code must be thrown.
277  if (NonZeroCounts > get_info<info::device::partition_max_sub_devices>())
279  "Total non-zero counts exceed max sub-devices");
280 
281  // If the total of all the values in the counts vector exceeds the total
282  // number of compute units in the device (as returned by
283  // info::device::max_compute_units), an exception with the errc::invalid
284  // error code must be thrown.
285  if (TotalCounts > get_info<info::device::max_compute_units>())
287  "Total counts exceed max compute units");
288 
289  return create_sub_devices(Properties.data(), Counts.size());
290 }
291 
293  info::partition_affinity_domain AffinityDomain) const {
294  assert(!MIsHostDevice && "Partitioning is not supported on host.");
295 
298  throw sycl::feature_not_supported(
299  "Device does not support "
300  "sycl::info::partition_property::partition_by_affinity_domain.",
301  PI_ERROR_INVALID_OPERATION);
302  }
303  if (!is_affinity_supported(AffinityDomain)) {
304  throw sycl::feature_not_supported(
305  "Device does not support " + affinityDomainToString(AffinityDomain) +
306  ".",
307  PI_ERROR_INVALID_VALUE);
308  }
309  const pi_device_partition_property Properties[3] = {
311  (pi_device_partition_property)AffinityDomain, 0};
312 
313  pi_uint32 SubDevicesCount = 0;
314  const PluginPtr &Plugin = getPlugin();
315  Plugin->call<sycl::errc::invalid, PiApiKind::piDevicePartition>(
316  MDevice, Properties, 0, nullptr, &SubDevicesCount);
317 
318  return create_sub_devices(Properties, SubDevicesCount);
319 }
320 
321 std::vector<device> device_impl::create_sub_devices() const {
322  assert(!MIsHostDevice && "Partitioning is not supported on host.");
323 
326  throw sycl::feature_not_supported(
327  "Device does not support "
328  "sycl::info::partition_property::ext_intel_partition_by_cslice.",
329  PI_ERROR_INVALID_OPERATION);
330  }
331 
332  const pi_device_partition_property Properties[2] = {
334 
335  pi_uint32 SubDevicesCount = 0;
336  const PluginPtr &Plugin = getPlugin();
337  Plugin->call<sycl::errc::invalid, PiApiKind::piDevicePartition>(
338  MDevice, Properties, 0, nullptr, &SubDevicesCount);
339 
340  return create_sub_devices(Properties, SubDevicesCount);
341 }
342 
344  auto Plugin = getPlugin();
345  if (getBackend() == backend::opencl)
346  Plugin->call<PiApiKind::piDeviceRetain>(getHandleRef());
347  pi_native_handle Handle;
348  Plugin->call<PiApiKind::piextDeviceGetNativeHandle>(getHandleRef(), &Handle);
349  return Handle;
350 }
351 
352 bool device_impl::has(aspect Aspect) const {
353  size_t return_size = 0;
354 
355  switch (Aspect) {
356  case aspect::host:
357  return is_host();
358  case aspect::cpu:
359  return is_cpu();
360  case aspect::gpu:
361  return is_gpu();
362  case aspect::accelerator:
363  return is_accelerator();
364  case aspect::custom:
365  return false;
366  // TODO: Implement this for FPGA and ESIMD emulators.
367  case aspect::emulated:
368  return false;
369  case aspect::host_debuggable:
370  return false;
371  case aspect::fp16:
372  return has_extension("cl_khr_fp16");
373  case aspect::fp64:
374  return has_extension("cl_khr_fp64");
375  case aspect::ext_oneapi_bfloat16_math_functions:
376  return get_info<info::device::ext_oneapi_bfloat16_math_functions>();
377  case aspect::int64_base_atomics:
378  return has_extension("cl_khr_int64_base_atomics");
379  case aspect::int64_extended_atomics:
380  return has_extension("cl_khr_int64_extended_atomics");
381  case aspect::atomic64:
382  return get_info<info::device::atomic64>();
383  case aspect::image:
384  return get_info<info::device::image_support>();
385  case aspect::online_compiler:
386  return get_info<info::device::is_compiler_available>();
387  case aspect::online_linker:
388  return get_info<info::device::is_linker_available>();
389  case aspect::queue_profiling:
390  return get_info<info::device::queue_profiling>();
391  case aspect::usm_device_allocations:
392  return get_info<info::device::usm_device_allocations>();
393  case aspect::usm_host_allocations:
394  return get_info<info::device::usm_host_allocations>();
395  case aspect::ext_intel_mem_channel:
396  return get_info<info::device::ext_intel_mem_channel>();
397  case aspect::usm_atomic_host_allocations:
398  return is_host() ||
400  info::device::usm_host_allocations>::
401  get(MPlatform->getDeviceImpl(MDevice)) &
403  case aspect::usm_shared_allocations:
404  return get_info<info::device::usm_shared_allocations>();
405  case aspect::usm_atomic_shared_allocations:
406  return is_host() ||
408  info::device::usm_shared_allocations>::
409  get(MPlatform->getDeviceImpl(MDevice)) &
411  case aspect::usm_restricted_shared_allocations:
412  return get_info<info::device::usm_restricted_shared_allocations>();
413  case aspect::usm_system_allocations:
414  return get_info<info::device::usm_system_allocations>();
415  case aspect::ext_intel_device_id:
416  return getPlugin()->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
417  MDevice, PI_DEVICE_INFO_DEVICE_ID, 0, nullptr, &return_size) ==
418  PI_SUCCESS;
419  case aspect::ext_intel_pci_address:
420  return getPlugin()->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
421  MDevice, PI_DEVICE_INFO_PCI_ADDRESS, 0, nullptr, &return_size) ==
422  PI_SUCCESS;
423  case aspect::ext_intel_gpu_eu_count:
424  return getPlugin()->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
425  MDevice, PI_DEVICE_INFO_GPU_EU_COUNT, 0, nullptr,
426  &return_size) == PI_SUCCESS;
427  case aspect::ext_intel_gpu_eu_simd_width:
428  return getPlugin()->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
429  MDevice, PI_DEVICE_INFO_GPU_EU_SIMD_WIDTH, 0, nullptr,
430  &return_size) == PI_SUCCESS;
431  case aspect::ext_intel_gpu_slices:
432  return getPlugin()->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
433  MDevice, PI_DEVICE_INFO_GPU_SLICES, 0, nullptr, &return_size) ==
434  PI_SUCCESS;
435  case aspect::ext_intel_gpu_subslices_per_slice:
436  return getPlugin()->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
437  MDevice, PI_DEVICE_INFO_GPU_SUBSLICES_PER_SLICE, 0, nullptr,
438  &return_size) == PI_SUCCESS;
439  case aspect::ext_intel_gpu_eu_count_per_subslice:
440  return getPlugin()->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
441  MDevice, PI_DEVICE_INFO_GPU_EU_COUNT_PER_SUBSLICE, 0, nullptr,
442  &return_size) == PI_SUCCESS;
443  case aspect::ext_intel_gpu_hw_threads_per_eu:
444  return getPlugin()->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
445  MDevice, PI_DEVICE_INFO_GPU_HW_THREADS_PER_EU, 0, nullptr,
446  &return_size) == PI_SUCCESS;
447  case aspect::ext_intel_free_memory:
448  return getPlugin()->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
449  MDevice, PI_EXT_INTEL_DEVICE_INFO_FREE_MEMORY, 0, nullptr,
450  &return_size) == PI_SUCCESS;
451  case aspect::ext_intel_memory_clock_rate:
452  return getPlugin()->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
453  MDevice, PI_EXT_INTEL_DEVICE_INFO_MEMORY_CLOCK_RATE, 0, nullptr,
454  &return_size) == PI_SUCCESS;
455  case aspect::ext_intel_memory_bus_width:
456  return getPlugin()->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
457  MDevice, PI_EXT_INTEL_DEVICE_INFO_MEMORY_BUS_WIDTH, 0, nullptr,
458  &return_size) == PI_SUCCESS;
459  case aspect::ext_intel_device_info_uuid: {
460  auto Result = getPlugin()->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
461  MDevice, PI_DEVICE_INFO_UUID, 0, nullptr, &return_size);
462  if (Result != PI_SUCCESS) {
463  return false;
464  }
465 
466  assert(return_size <= 16);
467  unsigned char UUID[16];
468 
469  return getPlugin()->call_nocheck<detail::PiApiKind::piDeviceGetInfo>(
470  MDevice, PI_DEVICE_INFO_UUID, 16 * sizeof(unsigned char), UUID,
471  nullptr) == PI_SUCCESS;
472  }
473  case aspect::ext_intel_max_mem_bandwidth:
474  // currently not supported
475  return false;
476  case aspect::ext_oneapi_srgb:
477  return get_info<info::device::ext_oneapi_srgb>();
478  case aspect::ext_oneapi_native_assert:
479  return isAssertFailSupported();
480  case aspect::ext_oneapi_cuda_async_barrier: {
481  int async_barrier_supported;
482  bool call_successful =
484  MDevice, PI_EXT_ONEAPI_DEVICE_INFO_CUDA_ASYNC_BARRIER, sizeof(int),
485  &async_barrier_supported, nullptr) == PI_SUCCESS;
486  return call_successful && async_barrier_supported;
487  }
488  case aspect::ext_intel_legacy_image: {
489  pi_bool legacy_image_support = PI_FALSE;
490  bool call_successful =
492  MDevice, PI_DEVICE_INFO_IMAGE_SUPPORT, sizeof(pi_bool),
493  &legacy_image_support, nullptr) == PI_SUCCESS;
494  return call_successful && legacy_image_support;
495  }
496  case aspect::ext_oneapi_bindless_images: {
497  pi_bool support = PI_FALSE;
498  bool call_successful =
501  sizeof(pi_bool), &support, nullptr) == PI_SUCCESS;
502  return call_successful && support;
503  }
504  case aspect::ext_oneapi_bindless_images_shared_usm: {
505  pi_bool support = PI_FALSE;
506  bool call_successful =
508  MDevice,
510  sizeof(pi_bool), &support, nullptr) == PI_SUCCESS;
511  return call_successful && support;
512  }
513  case aspect::ext_oneapi_bindless_images_1d_usm: {
514  pi_bool support = PI_FALSE;
515  bool call_successful =
518  sizeof(pi_bool), &support, nullptr) == PI_SUCCESS;
519  return call_successful && support;
520  }
521  case aspect::ext_oneapi_bindless_images_2d_usm: {
522  pi_bool support = PI_FALSE;
523  bool call_successful =
526  sizeof(pi_bool), &support, nullptr) == PI_SUCCESS;
527  return call_successful && support;
528  }
529  case aspect::ext_oneapi_interop_memory_import: {
530  pi_bool support = PI_FALSE;
531  bool call_successful =
534  sizeof(pi_bool), &support, nullptr) == PI_SUCCESS;
535  return call_successful && support;
536  }
537  case aspect::ext_oneapi_interop_memory_export: {
538  pi_bool support = PI_FALSE;
539  bool call_successful =
542  sizeof(pi_bool), &support, nullptr) == PI_SUCCESS;
543  return call_successful && support;
544  }
545  case aspect::ext_oneapi_interop_semaphore_import: {
546  pi_bool support = PI_FALSE;
547  bool call_successful =
550  sizeof(pi_bool), &support, nullptr) == PI_SUCCESS;
551  return call_successful && support;
552  }
553  case aspect::ext_oneapi_interop_semaphore_export: {
554  pi_bool support = PI_FALSE;
555  bool call_successful =
558  sizeof(pi_bool), &support, nullptr) == PI_SUCCESS;
559  return call_successful && support;
560  }
561  case aspect::ext_oneapi_mipmap: {
562  pi_bool support = PI_FALSE;
563  bool call_successful =
566  &support, nullptr) == PI_SUCCESS;
567  return call_successful && support;
568  }
569  case aspect::ext_oneapi_mipmap_anisotropy: {
570  pi_bool support = PI_FALSE;
571  bool call_successful =
574  sizeof(pi_bool), &support, nullptr) == PI_SUCCESS;
575  return call_successful && support;
576  }
577  case aspect::ext_oneapi_mipmap_level_reference: {
578  pi_bool support = PI_FALSE;
579  bool call_successful =
582  sizeof(pi_bool), &support, nullptr) == PI_SUCCESS;
583  return call_successful && support;
584  }
585  case aspect::ext_oneapi_cubemap: {
586  pi_bool support = PI_FALSE;
587  bool call_successful =
590  &support, nullptr) == PI_SUCCESS;
591  return call_successful && support;
592  }
593  case aspect::ext_oneapi_cubemap_seamless_filtering: {
594  pi_bool support = PI_FALSE;
595  bool call_successful =
597  MDevice,
599  sizeof(pi_bool), &support, nullptr) == PI_SUCCESS;
600  return call_successful && support;
601  }
602  case aspect::ext_intel_esimd: {
603  pi_bool support = PI_FALSE;
604  bool call_successful =
607  &support, nullptr) == PI_SUCCESS;
608  return call_successful && support;
609  }
610  case aspect::ext_oneapi_ballot_group:
611  case aspect::ext_oneapi_fixed_size_group:
612  case aspect::ext_oneapi_opportunistic_group: {
613  return (this->getBackend() == backend::ext_oneapi_level_zero) ||
614  (this->getBackend() == backend::opencl) ||
616  }
617  case aspect::ext_oneapi_tangle_group: {
618  // TODO: tangle_group is not currently supported for CUDA devices. Add when
619  // implemented.
620  return (this->getBackend() == backend::ext_oneapi_level_zero) ||
621  (this->getBackend() == backend::opencl);
622  }
623  case aspect::ext_intel_matrix: {
625  const std::vector<arch> supported_archs = {
626  arch::intel_cpu_spr, arch::intel_gpu_pvc, arch::intel_gpu_dg2_g10,
627  arch::intel_gpu_dg2_g11, arch::intel_gpu_dg2_g12};
628  try {
629  return std::any_of(
630  supported_archs.begin(), supported_archs.end(),
631  [=](const arch a) { return this->extOneapiArchitectureIs(a); });
632  } catch (const sycl::exception &) {
633  // If we're here it means the device does not support architecture
634  // querying
635  return false;
636  }
637  }
638  case aspect::ext_oneapi_is_composite: {
639  auto components = get_info<
640  sycl::ext::oneapi::experimental::info::device::component_devices>();
641  // Any device with ext_oneapi_is_composite aspect will have at least two
642  // constituent component devices.
643  return components.size() >= 2;
644  }
645  case aspect::ext_oneapi_is_component: {
647  return false;
648 
649  typename sycl_to_pi<device>::type Result;
651  getHandleRef(),
652  PiInfoCode<
653  ext::oneapi::experimental::info::device::composite_device>::value,
654  sizeof(Result), &Result, nullptr);
655 
656  return Result != nullptr;
657  }
658  case aspect::ext_oneapi_graph: {
659  pi_bool SupportsCommandBufferUpdate = false;
660  bool CallSuccessful =
661  getPlugin()->call_nocheck<PiApiKind::piDeviceGetInfo>(
663  sizeof(SupportsCommandBufferUpdate), &SupportsCommandBufferUpdate,
664  nullptr) == PI_SUCCESS;
665  if (!CallSuccessful) {
666  return PI_FALSE;
667  }
668 
669  return has(aspect::ext_oneapi_limited_graph) && SupportsCommandBufferUpdate;
670  }
671  case aspect::ext_oneapi_limited_graph: {
672  pi_bool SupportsCommandBuffers = false;
673  bool CallSuccessful =
674  getPlugin()->call_nocheck<PiApiKind::piDeviceGetInfo>(
676  sizeof(SupportsCommandBuffers), &SupportsCommandBuffers,
677  nullptr) == PI_SUCCESS;
678  if (!CallSuccessful) {
679  return PI_FALSE;
680  }
681 
682  return SupportsCommandBuffers;
683  }
684  case aspect::ext_intel_fpga_task_sequence: {
685  return is_accelerator();
686  }
687  case aspect::ext_oneapi_private_alloca: {
688  // Extension only supported on SPIR-V targets.
689  backend be = getBackend();
690  return be == sycl::backend::ext_oneapi_level_zero ||
691  be == sycl::backend::opencl;
692  }
693  }
694  throw runtime_error("This device aspect has not been implemented yet.",
695  PI_ERROR_INVALID_DEVICE);
696 }
697 
698 std::shared_ptr<device_impl> device_impl::getHostDeviceImpl() {
699  static std::shared_ptr<device_impl> HostImpl =
700  std::make_shared<device_impl>();
701 
702  return HostImpl;
703 }
704 
706  return MIsAssertFailSupported;
707 }
708 
709 std::string device_impl::getDeviceName() const {
710  std::call_once(MDeviceNameFlag,
711  [this]() { MDeviceName = get_info<info::device::name>(); });
712 
713  return MDeviceName;
714 }
715 
717  std::call_once(MDeviceArchFlag, [this]() {
718  MDeviceArch =
719  get_info<ext::oneapi::experimental::info::device::architecture>();
720  });
721 
722  return MDeviceArch;
723 }
724 
725 // On the first call this function queries for device timestamp
726 // along with host synchronized timestamp and stores it in member variable
727 // MDeviceHostBaseTime. Subsequent calls to this function would just retrieve
728 // the host timestamp, compute difference against the host timestamp in
729 // MDeviceHostBaseTime and calculate the device timestamp based on the
730 // difference.
731 //
732 // The MDeviceHostBaseTime is refreshed with new device and host timestamp
733 // after a certain interval (determined by TimeTillRefresh) to account for
734 // clock drift between host and device.
735 //
737  using namespace std::chrono;
738  uint64_t HostTime =
739  duration_cast<nanoseconds>(steady_clock::now().time_since_epoch())
740  .count();
741  if (MIsHostDevice) {
742  return HostTime;
743  }
744 
745  // To account for potential clock drift between host clock and device clock.
746  // The value set is arbitrary: 200 seconds
747  constexpr uint64_t TimeTillRefresh = 200e9;
748  assert(HostTime >= MDeviceHostBaseTime.second);
749  uint64_t Diff = HostTime - MDeviceHostBaseTime.second;
750 
751  // If getCurrentDeviceTime is called for the first time or we have to refresh.
752  if (!MDeviceHostBaseTime.second || Diff > TimeTillRefresh) {
753  const auto &Plugin = getPlugin();
754  auto Result =
755  Plugin->call_nocheck<detail::PiApiKind::piGetDeviceAndHostTimer>(
756  MDevice, &MDeviceHostBaseTime.first, &MDeviceHostBaseTime.second);
757  // We have to remember base host timestamp right after PI call and it is
758  // going to be used for calculation of the device timestamp at the next
759  // getCurrentDeviceTime() call. We need to do it here because getPlugin()
760  // and piGetDeviceAndHostTimer calls may take significant amount of time,
761  // for example on the first call to getPlugin plugins may need to be
762  // initialized. If we use timestamp from the beginning of the function then
763  // the difference between host timestamps of the current
764  // getCurrentDeviceTime and the next getCurrentDeviceTime will be incorrect
765  // because it will include execution time of the code before we get device
766  // timestamp from piGetDeviceAndHostTimer.
767  HostTime =
768  duration_cast<nanoseconds>(steady_clock::now().time_since_epoch())
769  .count();
770  if (Result == PI_ERROR_INVALID_OPERATION) {
771  char *p = nullptr;
772  Plugin->call_nocheck<detail::PiApiKind::piPluginGetLastError>(&p);
773  std::string errorMsg(p ? p : "");
774  throw sycl::feature_not_supported(
775  "Device and/or backend does not support querying timestamp: " +
776  errorMsg,
777  Result);
778  } else {
779  Plugin->checkPiResult(Result);
780  }
781  // Until next sync we will compute device time based on the host time
782  // returned in HostTime, so make this our base host time.
783  MDeviceHostBaseTime.second = HostTime;
784  Diff = 0;
785  }
786  return MDeviceHostBaseTime.first + Diff;
787 }
788 
790  const auto &Plugin = getPlugin();
791  uint64_t DeviceTime = 0, HostTime = 0;
792  auto Result =
793  Plugin->call_nocheck<detail::PiApiKind::piGetDeviceAndHostTimer>(
794  MDevice, &DeviceTime, &HostTime);
795  return Result != PI_ERROR_INVALID_OPERATION;
796 }
797 
800  try {
801  return is_source_kernel_bundle_supported(getBackend(), Language);
802  } catch (sycl::exception &) {
803  return false;
804  }
805 }
806 
807 } // namespace detail
808 } // namespace _V1
809 } // namespace sycl
std::vector< device > create_sub_devices() const
Partition device into sub devices.
bool has(aspect Aspect) const
Indicates if the SYCL device has the given feature.
bool is_host() const
Check if SYCL device is a host device.
Definition: device_impl.hpp:90
Param::return_type get_info() const
Queries this SYCL device for information requested by the template parameter param.
platform get_platform() const
Get associated SYCL platform.
bool isGetDeviceAndHostTimerSupported()
Check clGetDeviceAndHostTimer is available for fallback profiling.
std::string get_device_info_string(sycl::detail::pi::PiDeviceInfo InfoCode) const
Get device info string.
device_impl()
Constructs a SYCL device instance as a host device.
Definition: device_impl.cpp:20
bool is_cpu() const
Check if device is a CPU device.
Definition: device_impl.hpp:95
backend getBackend() const
Get the backend of this device.
const PluginPtr & getPlugin() const
pi_native_handle getNative() const
Gets the native handle of the SYCL device.
bool is_gpu() const
Check if device is a GPU device.
uint64_t getCurrentDeviceTime()
Gets the current device timestamp.
std::string getDeviceName() const
sycl::detail::pi::PiDevice & getHandleRef()
Get reference to PI device.
Definition: device_impl.hpp:66
bool has_extension(const std::string &ExtensionName) const
Check SYCL extension support by device.
bool is_affinity_supported(info::partition_affinity_domain AffinityDomain) const
Check if affinity partitioning by specified domain is supported by device.
Definition: device_impl.cpp:96
cl_device_id get() const
Get instance of OpenCL device.
ext::oneapi::experimental::architecture getDeviceArch() const
Get device architecture.
bool extOneapiCanCompile(ext::oneapi::experimental::source_language Language)
bool is_partition_supported(info::partition_property Prop) const
Check if desired partition property supported by device.
static std::shared_ptr< device_impl > getHostDeviceImpl()
Gets the single instance of the Host Device.
bool is_accelerator() const
Check if device is an accelerator device.
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
Encapsulates a SYCL platform on which kernels may be executed.
Definition: platform.hpp:99
#define __SYCL_CHECK_OCL_CODE_NO_EXC(X)
Definition: common.hpp:239
::pi_device PiDevice
Definition: pi.hpp:131
::pi_device_type PiDeviceType
Definition: pi.hpp:132
std::string affinityDomainToString(info::partition_affinity_domain AffinityDomain)
Definition: device_info.hpp:86
static const PluginPtr & getPlugin(backend Backend)
Definition: backend.cpp:32
std::shared_ptr< plugin > PluginPtr
Definition: pi.hpp:48
std::shared_ptr< detail::platform_impl > PlatformImplPtr
Function for_each(Group g, Ptr first, Ptr last, Function f)
bool is_source_kernel_bundle_supported(backend BE, source_language Language)
Definition: access.hpp:18
#define PI_DEVICE_INFO_EXTENSION_DEVICELIB_ASSERT
Extension to denote native support of assert feature by an arbitrary device piDeviceGetInfo call shou...
Definition: pi.h:981
uintptr_t pi_native_handle
Definition: pi.h:217
pi_result piextDeviceGetNativeHandle(pi_device device, pi_native_handle *nativeHandle)
Gets the native handle of a PI device object.
Definition: pi_cuda.cpp:100
_pi_result
Definition: pi.h:224
pi_uint32 pi_bool
Definition: pi.h:215
static constexpr pi_device_partition_property PI_EXT_INTEL_DEVICE_PARTITION_BY_CSLICE
Definition: pi.h:863
_pi_usm_capabilities pi_usm_capabilities
Definition: pi.h:1980
@ PI_DEVICE_INFO_GPU_SLICES
Definition: pi.h:397
@ PI_EXT_ONEAPI_DEVICE_INFO_INTEROP_MEMORY_IMPORT_SUPPORT
Definition: pi.h:447
@ PI_EXT_ONEAPI_DEVICE_INFO_CUBEMAP_SUPPORT
Definition: pi.h:463
@ PI_EXT_ONEAPI_DEVICE_INFO_COMMAND_BUFFER_UPDATE_SUPPORT
Definition: pi.h:460
@ PI_EXT_INTEL_DEVICE_INFO_ESIMD_SUPPORT
Definition: pi.h:432
@ PI_DEVICE_INFO_GPU_EU_COUNT
Definition: pi.h:395
@ PI_DEVICE_INFO_IMAGE_SUPPORT
Definition: pi.h:332
@ PI_EXT_INTEL_DEVICE_INFO_FREE_MEMORY
Definition: pi.h:404
@ PI_EXT_ONEAPI_DEVICE_INFO_INTEROP_MEMORY_EXPORT_SUPPORT
Definition: pi.h:448
@ PI_DEVICE_INFO_UUID
Definition: pi.h:390
@ PI_EXT_ONEAPI_DEVICE_INFO_MIPMAP_SUPPORT
Definition: pi.h:443
@ PI_EXT_ONEAPI_DEVICE_INFO_MIPMAP_ANISOTROPY_SUPPORT
Definition: pi.h:444
@ PI_DEVICE_INFO_PARENT_DEVICE
Definition: pi.h:376
@ PI_DEVICE_INFO_GPU_EU_SIMD_WIDTH
Definition: pi.h:396
@ PI_EXT_ONEAPI_DEVICE_INFO_BINDLESS_IMAGES_SUPPORT
Definition: pi.h:435
@ PI_DEVICE_INFO_GPU_HW_THREADS_PER_EU
Definition: pi.h:417
@ PI_EXT_ONEAPI_DEVICE_INFO_CUBEMAP_SEAMLESS_FILTERING_SUPPORT
Definition: pi.h:464
@ PI_DEVICE_INFO_DEVICE_ID
Definition: pi.h:393
@ PI_EXT_ONEAPI_DEVICE_INFO_INTEROP_SEMAPHORE_EXPORT_SUPPORT
Definition: pi.h:450
@ PI_DEVICE_INFO_PCI_ADDRESS
Definition: pi.h:394
@ PI_EXT_ONEAPI_DEVICE_INFO_CUDA_ASYNC_BARRIER
Definition: pi.h:425
@ PI_DEVICE_INFO_GPU_EU_COUNT_PER_SUBSLICE
Definition: pi.h:399
@ PI_EXT_ONEAPI_DEVICE_INFO_MIPMAP_LEVEL_REFERENCE_SUPPORT
Definition: pi.h:446
@ PI_EXT_INTEL_DEVICE_INFO_MEMORY_CLOCK_RATE
Definition: pi.h:407
@ PI_EXT_ONEAPI_DEVICE_INFO_INTEROP_SEMAPHORE_IMPORT_SUPPORT
Definition: pi.h:449
@ PI_EXT_ONEAPI_DEVICE_INFO_BINDLESS_IMAGES_SHARED_USM_SUPPORT
Definition: pi.h:436
@ PI_EXT_ONEAPI_DEVICE_INFO_BINDLESS_IMAGES_1D_USM_SUPPORT
Definition: pi.h:437
@ PI_EXT_INTEL_DEVICE_INFO_MEMORY_BUS_WIDTH
Definition: pi.h:410
@ PI_DEVICE_INFO_TYPE
Definition: pi.h:305
@ PI_EXT_ONEAPI_DEVICE_INFO_BINDLESS_IMAGES_2D_USM_SUPPORT
Definition: pi.h:438
@ PI_EXT_ONEAPI_DEVICE_INFO_COMMAND_BUFFER_SUPPORT
Definition: pi.h:459
@ PI_DEVICE_INFO_GPU_SUBSLICES_PER_SLICE
Definition: pi.h:398
static constexpr pi_device_partition_property PI_DEVICE_PARTITION_BY_COUNTS
Definition: pi.h:856
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_USM_CONCURRENT_ATOMIC_ACCESS
Definition: pi.h:1955
static constexpr pi_device_partition_property PI_DEVICE_PARTITION_BY_COUNTS_LIST_END
Definition: pi.h:859
static constexpr pi_device_partition_property PI_DEVICE_PARTITION_EQUALLY
Definition: pi.h:854
const pi_bool PI_FALSE
Definition: pi.h:685
uint32_t pi_uint32
Definition: pi.h:213
static constexpr pi_device_partition_property PI_DEVICE_PARTITION_BY_AFFINITY_DOMAIN
Definition: pi.h:861
pi_result piPluginGetLastError(char **message)
API to get Plugin specific warning and error messages.
Definition: pi_cuda.cpp:52
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 piDeviceRelease(pi_device device)
Definition: pi_cuda.cpp:74
pi_result piGetDeviceAndHostTimer(pi_device Device, uint64_t *DeviceTime, uint64_t *HostTime)
Queries device for it's global timestamp in nanoseconds, and updates HostTime with the value of the h...
Definition: pi_cuda.cpp:1247
intptr_t pi_device_partition_property
Definition: pi.h:853
pi_result piDevicePartition(pi_device device, const pi_device_partition_property *properties, pi_uint32 num_devices, pi_device *out_devices, pi_uint32 *out_num_devices)
Definition: pi_cuda.cpp:85
bool any_of(const simd_mask< _Tp, _Abi > &) noexcept