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/detail/ur.hpp>
13 #include <sycl/device.hpp>
14 
15 #include <algorithm>
16 
17 namespace sycl {
18 inline namespace _V1 {
19 namespace detail {
20 
21 device_impl::device_impl(ur_native_handle_t InteropDeviceHandle,
22  const PluginPtr &Plugin)
23  : device_impl(InteropDeviceHandle, nullptr, nullptr, Plugin) {}
24 
27 device_impl::device_impl(ur_device_handle_t Device, PlatformImplPtr Platform)
28  : device_impl(0, Device, Platform, Platform->getPlugin()) {}
29 
32 device_impl::device_impl(ur_device_handle_t Device, const PluginPtr &Plugin)
33  : device_impl(0, Device, nullptr, Plugin) {}
34 
35 device_impl::device_impl(ur_native_handle_t InteropDeviceHandle,
36  ur_device_handle_t Device, PlatformImplPtr Platform,
37  const PluginPtr &Plugin)
38  : MDevice(Device), MDeviceHostBaseTime(std::make_pair(0, 0)) {
39  bool InteroperabilityConstructor = false;
40  if (Device == nullptr) {
41  assert(InteropDeviceHandle);
42  // Get UR device from the raw device handle.
43  // NOTE: this is for OpenCL interop only (and should go away).
44  // With SYCL-2020 BE generalization "make" functions are used instead.
45  Plugin->call(urDeviceCreateWithNativeHandle, InteropDeviceHandle, nullptr,
46  nullptr, &MDevice);
47  InteroperabilityConstructor = true;
48  }
49 
50  // TODO catch an exception and put it to list of asynchronous exceptions
51  Plugin->call(urDeviceGetInfo, MDevice, UR_DEVICE_INFO_TYPE,
52  sizeof(ur_device_type_t), &MType, nullptr);
53 
54  // No need to set MRootDevice when MAlwaysRootDevice is true
55  if ((Platform == nullptr) || !Platform->MAlwaysRootDevice) {
56  // TODO catch an exception and put it to list of asynchronous exceptions
57  Plugin->call(urDeviceGetInfo, MDevice, UR_DEVICE_INFO_PARENT_DEVICE,
58  sizeof(ur_device_handle_t), &MRootDevice, nullptr);
59  }
60 
61  if (!InteroperabilityConstructor) {
62  // TODO catch an exception and put it to list of asynchronous exceptions
63  // Interoperability Constructor already calls DeviceRetain in
64  // urDeviceCreateWithNativeHandle.
65  Plugin->call(urDeviceRetain, MDevice);
66  }
67 
68  // set MPlatform
69  if (!Platform) {
70  Platform = platform_impl::getPlatformFromUrDevice(MDevice, Plugin);
71  }
72  MPlatform = Platform;
73 
74  MIsAssertFailSupported =
76 }
77 
79  // TODO catch an exception and put it to list of asynchronous exceptions
80  const PluginPtr &Plugin = getPlugin();
81  ur_result_t Err = Plugin->call_nocheck(urDeviceRelease, MDevice);
83 }
84 
86  info::partition_affinity_domain AffinityDomain) const {
87  auto SupportedDomains = get_info<info::device::partition_affinity_domains>();
88  return std::find(SupportedDomains.begin(), SupportedDomains.end(),
89  AffinityDomain) != SupportedDomains.end();
90 }
91 
92 cl_device_id device_impl::get() const {
93  // TODO catch an exception and put it to list of asynchronous exceptions
94  getPlugin()->call(urDeviceRetain, MDevice);
95  return ur::cast<cl_device_id>(getNative());
96 }
97 
99  return createSyclObjFromImpl<platform>(MPlatform);
100 }
101 
102 template <typename Param>
103 typename Param::return_type device_impl::get_info() const {
104  return get_device_info<Param>(
105  MPlatform->getOrMakeDeviceImpl(MDevice, MPlatform));
106 }
107 // Explicitly instantiate all device info traits
108 #define __SYCL_PARAM_TRAITS_SPEC(DescType, Desc, ReturnT, PiCode) \
109  template ReturnT device_impl::get_info<info::device::Desc>() const;
110 
111 #define __SYCL_PARAM_TRAITS_SPEC_SPECIALIZED(DescType, Desc, ReturnT, PiCode) \
112  template ReturnT device_impl::get_info<info::device::Desc>() const;
113 
114 #include <sycl/info/device_traits.def>
115 #undef __SYCL_PARAM_TRAITS_SPEC_SPECIALIZED
116 #undef __SYCL_PARAM_TRAITS_SPEC
117 
118 #define __SYCL_PARAM_TRAITS_SPEC(Namespace, DescType, Desc, ReturnT, PiCode) \
119  template __SYCL_EXPORT ReturnT \
120  device_impl::get_info<Namespace::info::DescType::Desc>() const;
121 
122 #include <sycl/info/ext_codeplay_device_traits.def>
123 #include <sycl/info/ext_intel_device_traits.def>
124 #include <sycl/info/ext_oneapi_device_traits.def>
125 #undef __SYCL_PARAM_TRAITS_SPEC
126 
127 template <>
128 typename info::platform::version::return_type
129 device_impl::get_backend_info<info::platform::version>() const {
130  if (getBackend() != backend::opencl) {
132  "the info::platform::version info descriptor can "
133  "only be queried with an OpenCL backend");
134  }
135  return get_platform().get_info<info::platform::version>();
136 }
137 
138 template <>
139 typename info::device::version::return_type
140 device_impl::get_backend_info<info::device::version>() const {
141  if (getBackend() != backend::opencl) {
143  "the info::device::version info descriptor can only "
144  "be queried with an OpenCL backend");
145  }
146  return get_info<info::device::version>();
147 }
148 
149 template <>
150 typename info::device::backend_version::return_type
151 device_impl::get_backend_info<info::device::backend_version>() const {
152  if (getBackend() != backend::ext_oneapi_level_zero) {
154  "the info::device::backend_version info descriptor "
155  "can only be queried with a Level Zero backend");
156  }
157  return "";
158  // Currently The Level Zero backend does not define the value of this
159  // information descriptor and implementations are encouraged to return the
160  // empty string as per specification.
161 }
162 
163 bool device_impl::has_extension(const std::string &ExtensionName) const {
164  std::string AllExtensionNames =
165  get_device_info_string(UR_DEVICE_INFO_EXTENSIONS);
166  return (AllExtensionNames.find(ExtensionName) != std::string::npos);
167 }
168 
170  auto SupportedProperties = get_info<info::device::partition_properties>();
171  return std::find(SupportedProperties.begin(), SupportedProperties.end(),
172  Prop) != SupportedProperties.end();
173 }
174 
176  const ur_device_partition_properties_t *Properties,
177  size_t SubDevicesCount) const {
178  std::vector<ur_device_handle_t> SubDevices(SubDevicesCount);
179  uint32_t ReturnedSubDevices = 0;
180  const PluginPtr &Plugin = getPlugin();
181  Plugin->call<sycl::errc::invalid>(urDevicePartition, MDevice, Properties,
182  SubDevicesCount, SubDevices.data(),
183  &ReturnedSubDevices);
184  if (ReturnedSubDevices != SubDevicesCount) {
185  throw sycl::exception(
187  "Could not partition to the specified number of sub-devices");
188  }
189  // TODO: Need to describe the subdevice model. Some sub_device management
190  // may be necessary. What happens if create_sub_devices is called multiple
191  // times with the same arguments?
192  //
193  std::vector<device> res;
194  std::for_each(SubDevices.begin(), SubDevices.end(),
195  [&res, this](const ur_device_handle_t &a_ur_device) {
196  device sycl_device = detail::createSyclObjFromImpl<device>(
197  MPlatform->getOrMakeDeviceImpl(a_ur_device, MPlatform));
198  res.push_back(sycl_device);
199  });
200  return res;
201 }
202 
203 std::vector<device> device_impl::create_sub_devices(size_t ComputeUnits) const {
206  "Device does not support "
207  "sycl::info::partition_property::partition_equally.");
208  }
209  // If count exceeds the total number of compute units in the device, an
210  // exception with the errc::invalid error code must be thrown.
211  auto MaxComputeUnits = get_info<info::device::max_compute_units>();
212  if (ComputeUnits > MaxComputeUnits)
214  "Total counts exceed max compute units");
215 
216  size_t SubDevicesCount = MaxComputeUnits / ComputeUnits;
217 
218  ur_device_partition_property_t Prop{};
219  Prop.type = UR_DEVICE_PARTITION_EQUALLY;
220  Prop.value.count = static_cast<uint32_t>(ComputeUnits);
221 
222  ur_device_partition_properties_t Properties{};
223  Properties.stype = UR_STRUCTURE_TYPE_DEVICE_PARTITION_PROPERTIES;
224  Properties.PropCount = 1;
225  Properties.pProperties = &Prop;
226 
227  return create_sub_devices(&Properties, SubDevicesCount);
228 }
229 
230 std::vector<device>
231 device_impl::create_sub_devices(const std::vector<size_t> &Counts) const {
233  throw sycl::exception(
235  "Device does not support "
236  "sycl::info::partition_property::partition_by_counts.");
237  }
238 
239  std::vector<ur_device_partition_property_t> Props{};
240 
241  // Fill the properties vector with counts and validate it
242  size_t TotalCounts = 0;
243  size_t NonZeroCounts = 0;
244  for (auto Count : Counts) {
245  TotalCounts += Count;
246  NonZeroCounts += (Count != 0) ? 1 : 0;
247  Props.push_back(ur_device_partition_property_t{
248  UR_DEVICE_PARTITION_BY_COUNTS, {static_cast<uint32_t>(Count)}});
249  }
250 
251  ur_device_partition_properties_t Properties{};
252  Properties.stype = UR_STRUCTURE_TYPE_DEVICE_PARTITION_PROPERTIES;
253  Properties.pProperties = Props.data();
254  Properties.PropCount = Props.size();
255 
256  // If the number of non-zero values in counts exceeds the device’s maximum
257  // number of sub devices (as returned by info::device::
258  // partition_max_sub_devices) an exception with the errc::invalid
259  // error code must be thrown.
260  if (NonZeroCounts > get_info<info::device::partition_max_sub_devices>())
262  "Total non-zero counts exceed max sub-devices");
263 
264  // If the total of all the values in the counts vector exceeds the total
265  // number of compute units in the device (as returned by
266  // info::device::max_compute_units), an exception with the errc::invalid
267  // error code must be thrown.
268  if (TotalCounts > get_info<info::device::max_compute_units>())
270  "Total counts exceed max compute units");
271 
272  return create_sub_devices(&Properties, Counts.size());
273 }
274 
276  info::partition_affinity_domain AffinityDomain) const {
279  throw sycl::exception(
281  "Device does not support "
282  "sycl::info::partition_property::partition_by_affinity_domain.");
283  }
284  if (!is_affinity_supported(AffinityDomain)) {
286  "Device does not support " +
287  affinityDomainToString(AffinityDomain) + ".");
288  }
289 
290  ur_device_partition_property_t Prop;
291  Prop.type = UR_DEVICE_PARTITION_BY_AFFINITY_DOMAIN;
292  Prop.value.affinity_domain =
293  static_cast<ur_device_affinity_domain_flags_t>(AffinityDomain);
294 
295  ur_device_partition_properties_t Properties{};
296  Properties.stype = UR_STRUCTURE_TYPE_DEVICE_PARTITION_PROPERTIES;
297  Properties.PropCount = 1;
298  Properties.pProperties = &Prop;
299 
300  uint32_t SubDevicesCount = 0;
301  const PluginPtr &Plugin = getPlugin();
302  Plugin->call<sycl::errc::invalid>(urDevicePartition, MDevice, &Properties, 0,
303  nullptr, &SubDevicesCount);
304 
305  return create_sub_devices(&Properties, SubDevicesCount);
306 }
307 
308 std::vector<device> device_impl::create_sub_devices() const {
311  throw sycl::exception(
313  "Device does not support "
314  "sycl::info::partition_property::ext_intel_partition_by_cslice.");
315  }
316 
317  ur_device_partition_property_t Prop;
318  Prop.type = UR_DEVICE_PARTITION_BY_CSLICE;
319 
320  ur_device_partition_properties_t Properties{};
321  Properties.stype = UR_STRUCTURE_TYPE_DEVICE_PARTITION_PROPERTIES;
322  Properties.pProperties = &Prop;
323  Properties.PropCount = 1;
324 
325  uint32_t SubDevicesCount = 0;
326  const PluginPtr &Plugin = getPlugin();
327  Plugin->call(urDevicePartition, MDevice, &Properties, 0, nullptr,
328  &SubDevicesCount);
329 
330  return create_sub_devices(&Properties, SubDevicesCount);
331 }
332 
333 ur_native_handle_t device_impl::getNative() const {
334  auto Plugin = getPlugin();
335  if (getBackend() == backend::opencl)
336  Plugin->call(urDeviceRetain, getHandleRef());
337  ur_native_handle_t Handle;
338  Plugin->call(urDeviceGetNativeHandle, getHandleRef(), &Handle);
339  return Handle;
340 }
341 
342 bool device_impl::has(aspect Aspect) const {
343  size_t return_size = 0;
344 
345  switch (Aspect) {
346  case aspect::host:
347  // Deprecated
348  return false;
349  case aspect::cpu:
350  return is_cpu();
351  case aspect::gpu:
352  return is_gpu();
353  case aspect::accelerator:
354  return is_accelerator();
355  case aspect::custom:
356  return false;
357  // TODO: Implement this for FPGA emulator.
358  case aspect::emulated:
359  return false;
360  case aspect::host_debuggable:
361  return false;
362  case aspect::fp16:
363  return has_extension("cl_khr_fp16");
364  case aspect::fp64:
365  return has_extension("cl_khr_fp64");
366  case aspect::int64_base_atomics:
367  return has_extension("cl_khr_int64_base_atomics");
368  case aspect::int64_extended_atomics:
369  return has_extension("cl_khr_int64_extended_atomics");
370  case aspect::atomic64:
371  return get_info<info::device::atomic64>();
372  case aspect::image:
373  return get_info<info::device::image_support>();
374  case aspect::online_compiler:
375  return get_info<info::device::is_compiler_available>();
376  case aspect::online_linker:
377  return get_info<info::device::is_linker_available>();
378  case aspect::queue_profiling:
379  return get_info<info::device::queue_profiling>();
380  case aspect::usm_device_allocations:
381  return get_info<info::device::usm_device_allocations>();
382  case aspect::usm_host_allocations:
383  return get_info<info::device::usm_host_allocations>();
384  case aspect::ext_intel_mem_channel:
385  return get_info<info::device::ext_intel_mem_channel>();
386  case aspect::ext_oneapi_cuda_cluster_group:
387  return get_info<info::device::ext_oneapi_cuda_cluster_group>();
388  case aspect::usm_atomic_host_allocations:
389  return (get_device_info_impl<ur_device_usm_access_capability_flags_t,
390  info::device::usm_host_allocations>::
391  get(MPlatform->getDeviceImpl(MDevice)) &
392  UR_DEVICE_USM_ACCESS_CAPABILITY_FLAG_ATOMIC_CONCURRENT_ACCESS);
393  case aspect::usm_shared_allocations:
394  return get_info<info::device::usm_shared_allocations>();
395  case aspect::usm_atomic_shared_allocations:
396  return (get_device_info_impl<ur_device_usm_access_capability_flags_t,
397  info::device::usm_shared_allocations>::
398  get(MPlatform->getDeviceImpl(MDevice)) &
399  UR_DEVICE_USM_ACCESS_CAPABILITY_FLAG_ATOMIC_CONCURRENT_ACCESS);
400  case aspect::usm_restricted_shared_allocations:
401  return get_info<info::device::usm_restricted_shared_allocations>();
402  case aspect::usm_system_allocations:
403  return get_info<info::device::usm_system_allocations>();
404  case aspect::ext_intel_device_id:
405  return getPlugin()->call_nocheck(urDeviceGetInfo, MDevice,
406  UR_DEVICE_INFO_DEVICE_ID, 0, nullptr,
407  &return_size) == UR_RESULT_SUCCESS;
408  case aspect::ext_intel_pci_address:
409  return getPlugin()->call_nocheck(urDeviceGetInfo, MDevice,
410  UR_DEVICE_INFO_PCI_ADDRESS, 0, nullptr,
411  &return_size) == UR_RESULT_SUCCESS;
412  case aspect::ext_intel_gpu_eu_count:
413  return getPlugin()->call_nocheck(urDeviceGetInfo, MDevice,
414  UR_DEVICE_INFO_GPU_EU_COUNT, 0, nullptr,
415  &return_size) == UR_RESULT_SUCCESS;
416  case aspect::ext_intel_gpu_eu_simd_width:
417  return getPlugin()->call_nocheck(
418  urDeviceGetInfo, MDevice, UR_DEVICE_INFO_GPU_EU_SIMD_WIDTH, 0,
419  nullptr, &return_size) == UR_RESULT_SUCCESS;
420  case aspect::ext_intel_gpu_slices:
421  return getPlugin()->call_nocheck(urDeviceGetInfo, MDevice,
422  UR_DEVICE_INFO_GPU_EU_SLICES, 0, nullptr,
423  &return_size) == UR_RESULT_SUCCESS;
424  case aspect::ext_intel_gpu_subslices_per_slice:
425  return getPlugin()->call_nocheck(
426  urDeviceGetInfo, MDevice, UR_DEVICE_INFO_GPU_SUBSLICES_PER_SLICE,
427  0, nullptr, &return_size) == UR_RESULT_SUCCESS;
428  case aspect::ext_intel_gpu_eu_count_per_subslice:
429  return getPlugin()->call_nocheck(urDeviceGetInfo, MDevice,
430  UR_DEVICE_INFO_GPU_EU_COUNT_PER_SUBSLICE,
431  0, nullptr,
432  &return_size) == UR_RESULT_SUCCESS;
433  case aspect::ext_intel_gpu_hw_threads_per_eu:
434  return getPlugin()->call_nocheck(
435  urDeviceGetInfo, MDevice, UR_DEVICE_INFO_GPU_HW_THREADS_PER_EU,
436  0, nullptr, &return_size) == UR_RESULT_SUCCESS;
437  case aspect::ext_intel_free_memory:
438  return getPlugin()->call_nocheck(urDeviceGetInfo, MDevice,
439  UR_DEVICE_INFO_GLOBAL_MEM_FREE, 0, nullptr,
440  &return_size) == UR_RESULT_SUCCESS;
441  case aspect::ext_intel_memory_clock_rate:
442  return getPlugin()->call_nocheck(
443  urDeviceGetInfo, MDevice, UR_DEVICE_INFO_MEMORY_CLOCK_RATE, 0,
444  nullptr, &return_size) == UR_RESULT_SUCCESS;
445  case aspect::ext_intel_memory_bus_width:
446  return getPlugin()->call_nocheck(
447  urDeviceGetInfo, MDevice, UR_DEVICE_INFO_MEMORY_BUS_WIDTH, 0,
448  nullptr, &return_size) == UR_RESULT_SUCCESS;
449  case aspect::ext_intel_device_info_uuid: {
450  auto Result =
451  getPlugin()->call_nocheck(urDeviceGetInfo, MDevice, UR_DEVICE_INFO_UUID,
452  0, nullptr, &return_size);
453  if (Result != UR_RESULT_SUCCESS) {
454  return false;
455  }
456 
457  assert(return_size <= 16);
458  unsigned char UUID[16];
459 
460  return getPlugin()->call_nocheck(
461  urDeviceGetInfo, MDevice, UR_DEVICE_INFO_UUID,
462  16 * sizeof(unsigned char), UUID, nullptr) == UR_RESULT_SUCCESS;
463  }
464  case aspect::ext_intel_max_mem_bandwidth:
465  // currently not supported
466  return false;
467  case aspect::ext_oneapi_srgb:
468  return get_info<info::device::ext_oneapi_srgb>();
469  case aspect::ext_oneapi_native_assert:
470  return isAssertFailSupported();
471  case aspect::ext_oneapi_cuda_async_barrier: {
472  int async_barrier_supported;
473  bool call_successful =
474  getPlugin()->call_nocheck(
475  urDeviceGetInfo, MDevice, UR_DEVICE_INFO_ASYNC_BARRIER, sizeof(int),
476  &async_barrier_supported, nullptr) == UR_RESULT_SUCCESS;
477  return call_successful && async_barrier_supported;
478  }
479  case aspect::ext_intel_legacy_image: {
480  ur_bool_t legacy_image_support = false;
481  bool call_successful =
482  getPlugin()->call_nocheck(urDeviceGetInfo, MDevice,
483  UR_DEVICE_INFO_IMAGE_SUPPORTED,
484  sizeof(ur_bool_t), &legacy_image_support,
485  nullptr) == UR_RESULT_SUCCESS;
486  return call_successful && legacy_image_support;
487  }
488  case aspect::ext_oneapi_bindless_images: {
489  ur_bool_t support = false;
490  bool call_successful =
491  getPlugin()->call_nocheck(urDeviceGetInfo, MDevice,
492  UR_DEVICE_INFO_BINDLESS_IMAGES_SUPPORT_EXP,
493  sizeof(ur_bool_t), &support,
494  nullptr) == UR_RESULT_SUCCESS;
495  return call_successful && support;
496  }
497  case aspect::ext_oneapi_bindless_images_shared_usm: {
498  ur_bool_t support = false;
499  bool call_successful =
500  getPlugin()->call_nocheck(
501  urDeviceGetInfo, MDevice,
502  UR_DEVICE_INFO_BINDLESS_IMAGES_SHARED_USM_SUPPORT_EXP,
503  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
504  return call_successful && support;
505  }
506  case aspect::ext_oneapi_bindless_images_1d_usm: {
507  ur_bool_t support = false;
508  bool call_successful =
509  getPlugin()->call_nocheck(
510  urDeviceGetInfo, MDevice,
511  UR_DEVICE_INFO_BINDLESS_IMAGES_1D_USM_SUPPORT_EXP,
512  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
513  return call_successful && support;
514  }
515  case aspect::ext_oneapi_bindless_images_2d_usm: {
516  ur_bool_t support = false;
517  bool call_successful =
518  getPlugin()->call_nocheck(
519  urDeviceGetInfo, MDevice,
520  UR_DEVICE_INFO_BINDLESS_IMAGES_2D_USM_SUPPORT_EXP,
521  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
522  return call_successful && support;
523  }
524  case aspect::ext_oneapi_interop_memory_import: {
525  ur_bool_t support = false;
526  bool call_successful =
527  getPlugin()->call_nocheck(
528  urDeviceGetInfo, MDevice,
529  UR_DEVICE_INFO_INTEROP_MEMORY_IMPORT_SUPPORT_EXP, sizeof(ur_bool_t),
530  &support, nullptr) == UR_RESULT_SUCCESS;
531  return call_successful && support;
532  }
533  case aspect::ext_oneapi_interop_semaphore_import: {
534  ur_bool_t support = false;
535  bool call_successful =
536  getPlugin()->call_nocheck(
537  urDeviceGetInfo, MDevice,
538  UR_DEVICE_INFO_INTEROP_SEMAPHORE_IMPORT_SUPPORT_EXP,
539  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
540  return call_successful && support;
541  }
542  case aspect::ext_oneapi_mipmap: {
543  ur_bool_t support = false;
544  bool call_successful =
545  getPlugin()->call_nocheck(
546  urDeviceGetInfo, MDevice, UR_DEVICE_INFO_MIPMAP_SUPPORT_EXP,
547  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
548  return call_successful && support;
549  }
550  case aspect::ext_oneapi_mipmap_anisotropy: {
551  ur_bool_t support = false;
552  bool call_successful =
553  getPlugin()->call_nocheck(urDeviceGetInfo, MDevice,
554  UR_DEVICE_INFO_MIPMAP_ANISOTROPY_SUPPORT_EXP,
555  sizeof(ur_bool_t), &support,
556  nullptr) == UR_RESULT_SUCCESS;
557  return call_successful && support;
558  }
559  case aspect::ext_oneapi_mipmap_level_reference: {
560  ur_bool_t support = false;
561  bool call_successful =
562  getPlugin()->call_nocheck(
563  urDeviceGetInfo, MDevice,
564  UR_DEVICE_INFO_MIPMAP_LEVEL_REFERENCE_SUPPORT_EXP,
565  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
566  return call_successful && support;
567  }
568  case aspect::ext_oneapi_bindless_sampled_image_fetch_1d_usm: {
569  ur_bool_t support = false;
570  bool call_successful =
571  getPlugin()->call_nocheck(
572  urDeviceGetInfo, MDevice,
573  UR_DEVICE_INFO_BINDLESS_SAMPLED_IMAGE_FETCH_1D_USM_EXP,
574  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
575  return call_successful && support;
576  }
577  case aspect::ext_oneapi_bindless_sampled_image_fetch_1d: {
578  ur_bool_t support = false;
579  bool call_successful =
580  getPlugin()->call_nocheck(
581  urDeviceGetInfo, MDevice,
582  UR_DEVICE_INFO_BINDLESS_SAMPLED_IMAGE_FETCH_1D_EXP,
583  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
584  return call_successful && support;
585  }
586  case aspect::ext_oneapi_bindless_sampled_image_fetch_2d_usm: {
587  ur_bool_t support = false;
588  bool call_successful =
589  getPlugin()->call_nocheck(
590  urDeviceGetInfo, MDevice,
591  UR_DEVICE_INFO_BINDLESS_SAMPLED_IMAGE_FETCH_2D_USM_EXP,
592  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
593  return call_successful && support;
594  }
595  case aspect::ext_oneapi_bindless_sampled_image_fetch_2d: {
596  ur_bool_t support = false;
597  bool call_successful =
598  getPlugin()->call_nocheck(
599  urDeviceGetInfo, MDevice,
600  UR_DEVICE_INFO_BINDLESS_SAMPLED_IMAGE_FETCH_2D_EXP,
601  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
602  return call_successful && support;
603  }
604  case aspect::ext_oneapi_bindless_sampled_image_fetch_3d: {
605  ur_bool_t support = false;
606  bool call_successful =
607  getPlugin()->call_nocheck(
608  urDeviceGetInfo, MDevice,
609  UR_DEVICE_INFO_BINDLESS_SAMPLED_IMAGE_FETCH_3D_EXP,
610  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
611  return call_successful && support;
612  }
613  case aspect::ext_oneapi_cubemap: {
614  ur_bool_t support = false;
615  bool call_successful =
616  getPlugin()->call_nocheck(
617  urDeviceGetInfo, MDevice, UR_DEVICE_INFO_CUBEMAP_SUPPORT_EXP,
618  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
619  return call_successful && support;
620  }
621  case aspect::ext_oneapi_cubemap_seamless_filtering: {
622  ur_bool_t support = false;
623  bool call_successful =
624  getPlugin()->call_nocheck(
625  urDeviceGetInfo, MDevice,
626  UR_DEVICE_INFO_CUBEMAP_SEAMLESS_FILTERING_SUPPORT_EXP,
627  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
628  return call_successful && support;
629  }
630  case aspect::ext_oneapi_image_array: {
631  ur_bool_t support = false;
632  bool call_successful =
633  getPlugin()->call_nocheck(
634  urDeviceGetInfo, MDevice, UR_DEVICE_INFO_IMAGE_ARRAY_SUPPORT_EXP,
635  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
636  return call_successful && support;
637  }
638  case aspect::ext_oneapi_unique_addressing_per_dim: {
639  ur_bool_t support = false;
640  bool call_successful =
641  getPlugin()->call_nocheck(
642  urDeviceGetInfo, MDevice,
643  UR_DEVICE_INFO_BINDLESS_UNIQUE_ADDRESSING_PER_DIM_EXP,
644  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
645  return call_successful && support;
646  }
647  case aspect::ext_oneapi_bindless_images_sample_1d_usm: {
648  ur_bool_t support = false;
649  bool call_successful =
650  getPlugin()->call_nocheck(
651  urDeviceGetInfo, MDevice,
652  UR_DEVICE_INFO_BINDLESS_SAMPLED_IMAGE_FETCH_1D_USM_EXP,
653  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
654  return call_successful && support;
655  }
656  case aspect::ext_oneapi_bindless_images_sample_2d_usm: {
657  ur_bool_t support = false;
658  bool call_successful =
659  getPlugin()->call_nocheck(
660  urDeviceGetInfo, MDevice,
661  UR_DEVICE_INFO_BINDLESS_SAMPLED_IMAGE_FETCH_2D_USM_EXP,
662  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
663  return call_successful && support;
664  }
665  case aspect::ext_intel_esimd: {
666  ur_bool_t support = false;
667  bool call_successful =
668  getPlugin()->call_nocheck(
669  urDeviceGetInfo, MDevice, UR_DEVICE_INFO_ESIMD_SUPPORT,
670  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
671  return call_successful && support;
672  }
673  case aspect::ext_oneapi_ballot_group:
674  case aspect::ext_oneapi_fixed_size_group:
675  case aspect::ext_oneapi_opportunistic_group: {
676  return (this->getBackend() == backend::ext_oneapi_level_zero) ||
677  (this->getBackend() == backend::opencl) ||
679  }
680  case aspect::ext_oneapi_tangle_group: {
681  // TODO: tangle_group is not currently supported for CUDA devices. Add when
682  // implemented.
683  return (this->getBackend() == backend::ext_oneapi_level_zero) ||
684  (this->getBackend() == backend::opencl);
685  }
686  case aspect::ext_intel_matrix: {
688  const std::vector<arch> supported_archs = {
689  arch::intel_cpu_spr, arch::intel_cpu_gnr,
690  arch::intel_gpu_pvc, arch::intel_gpu_dg2_g10,
691  arch::intel_gpu_dg2_g11, arch::intel_gpu_dg2_g12};
692  try {
693  return std::any_of(
694  supported_archs.begin(), supported_archs.end(),
695  [=](const arch a) { return this->extOneapiArchitectureIs(a); });
696  } catch (const sycl::exception &) {
697  // If we're here it means the device does not support architecture
698  // querying
699  return false;
700  }
701  }
702  case aspect::ext_oneapi_is_composite: {
703  auto components = get_info<
704  sycl::ext::oneapi::experimental::info::device::component_devices>();
705  // Any device with ext_oneapi_is_composite aspect will have at least two
706  // constituent component devices.
707  return components.size() >= 2;
708  }
709  case aspect::ext_oneapi_is_component: {
710  typename sycl_to_ur<device>::type Result;
711  bool CallSuccessful =
712  getPlugin()->call_nocheck(
713  urDeviceGetInfo, getHandleRef(),
714  UrInfoCode<ext::oneapi::experimental::info::device::
715  composite_device>::value,
716  sizeof(Result), &Result, nullptr) == UR_RESULT_SUCCESS;
717 
718  return CallSuccessful && Result != nullptr;
719  }
720  case aspect::ext_oneapi_graph: {
721  bool SupportsCommandBufferUpdate = false;
722  bool CallSuccessful =
723  getPlugin()->call_nocheck(
724  urDeviceGetInfo, MDevice,
725  UR_DEVICE_INFO_COMMAND_BUFFER_UPDATE_SUPPORT_EXP,
726  sizeof(SupportsCommandBufferUpdate), &SupportsCommandBufferUpdate,
727  nullptr) == UR_RESULT_SUCCESS;
728  if (!CallSuccessful) {
729  return false;
730  }
731 
732  return has(aspect::ext_oneapi_limited_graph) && SupportsCommandBufferUpdate;
733  }
734  case aspect::ext_oneapi_limited_graph: {
735  bool SupportsCommandBuffers = false;
736  bool CallSuccessful =
737  getPlugin()->call_nocheck(
738  urDeviceGetInfo, MDevice, UR_DEVICE_INFO_COMMAND_BUFFER_SUPPORT_EXP,
739  sizeof(SupportsCommandBuffers), &SupportsCommandBuffers,
740  nullptr) == UR_RESULT_SUCCESS;
741  if (!CallSuccessful) {
742  return false;
743  }
744 
745  return SupportsCommandBuffers;
746  }
747  case aspect::ext_oneapi_private_alloca: {
748  // Extension only supported on SPIR-V targets.
749  backend be = getBackend();
750  return be == sycl::backend::ext_oneapi_level_zero ||
751  be == sycl::backend::opencl;
752  }
753  case aspect::ext_oneapi_queue_profiling_tag: {
754  ur_bool_t support = false;
755  bool call_successful =
756  getPlugin()->call_nocheck(
757  urDeviceGetInfo, MDevice,
758  UR_DEVICE_INFO_TIMESTAMP_RECORDING_SUPPORT_EXP, sizeof(ur_bool_t),
759  &support, nullptr) == UR_RESULT_SUCCESS;
760  return call_successful && support;
761  }
762  case aspect::ext_oneapi_virtual_mem: {
763  ur_bool_t support = false;
764  bool call_successful =
765  getPlugin()->call_nocheck(
766  urDeviceGetInfo, MDevice, UR_DEVICE_INFO_VIRTUAL_MEMORY_SUPPORT,
767  sizeof(ur_bool_t), &support, nullptr) == UR_RESULT_SUCCESS;
768  return call_successful && support;
769  }
770  case aspect::ext_intel_fpga_task_sequence: {
771  return is_accelerator();
772  }
773  }
774 
775  return false; // This device aspect has not been implemented yet.
776 }
777 
779  return MIsAssertFailSupported;
780 }
781 
782 std::string device_impl::getDeviceName() const {
783  std::call_once(MDeviceNameFlag,
784  [this]() { MDeviceName = get_info<info::device::name>(); });
785 
786  return MDeviceName;
787 }
788 
790  std::call_once(MDeviceArchFlag, [this]() {
791  MDeviceArch =
792  get_info<ext::oneapi::experimental::info::device::architecture>();
793  });
794 
795  return MDeviceArch;
796 }
797 
798 // On the first call this function queries for device timestamp
799 // along with host synchronized timestamp and stores it in member variable
800 // MDeviceHostBaseTime. Subsequent calls to this function would just retrieve
801 // the host timestamp, compute difference against the host timestamp in
802 // MDeviceHostBaseTime and calculate the device timestamp based on the
803 // difference.
804 //
805 // The MDeviceHostBaseTime is refreshed with new device and host timestamp
806 // after a certain interval (determined by TimeTillRefresh) to account for
807 // clock drift between host and device.
808 //
810  using namespace std::chrono;
811  uint64_t HostTime =
812  duration_cast<nanoseconds>(steady_clock::now().time_since_epoch())
813  .count();
814 
815  // To account for potential clock drift between host clock and device clock.
816  // The value set is arbitrary: 200 seconds
817  constexpr uint64_t TimeTillRefresh = 200e9;
818  assert(HostTime >= MDeviceHostBaseTime.second);
819  uint64_t Diff = HostTime - MDeviceHostBaseTime.second;
820 
821  // If getCurrentDeviceTime is called for the first time or we have to refresh.
822  if (!MDeviceHostBaseTime.second || Diff > TimeTillRefresh) {
823  const auto &Plugin = getPlugin();
824  auto Result = Plugin->call_nocheck(urDeviceGetGlobalTimestamps, MDevice,
825  &MDeviceHostBaseTime.first,
826  &MDeviceHostBaseTime.second);
827  // We have to remember base host timestamp right after UR call and it is
828  // going to be used for calculation of the device timestamp at the next
829  // getCurrentDeviceTime() call. We need to do it here because getPlugin()
830  // and urDeviceGetGlobalTimestamps calls may take significant amount of time,
831  // for example on the first call to getPlugin plugins may need to be
832  // initialized. If we use timestamp from the beginning of the function then
833  // the difference between host timestamps of the current
834  // getCurrentDeviceTime and the next getCurrentDeviceTime will be incorrect
835  // because it will include execution time of the code before we get device
836  // timestamp from urDeviceGetGlobalTimestamps.
837  HostTime =
838  duration_cast<nanoseconds>(steady_clock::now().time_since_epoch())
839  .count();
840  if (Result == UR_RESULT_ERROR_INVALID_OPERATION) {
841  // NOTE(UR port): Removed the call to GetLastError because we shouldn't
842  // be calling it after ERROR_INVALID_OPERATION: there is no
843  // adapter-specific error.
844  throw detail::set_ur_error(
847  "Device and/or backend does not support querying timestamp."),
848  UR_RESULT_ERROR_INVALID_OPERATION);
849  } else {
850  Plugin->checkUrResult<errc::feature_not_supported>(Result);
851  }
852  // Until next sync we will compute device time based on the host time
853  // returned in HostTime, so make this our base host time.
854  MDeviceHostBaseTime.second = HostTime;
855  Diff = 0;
856  }
857  return MDeviceHostBaseTime.first + Diff;
858 }
859 
861  const auto &Plugin = getPlugin();
862  uint64_t DeviceTime = 0, HostTime = 0;
863  auto Result = Plugin->call_nocheck(urDeviceGetGlobalTimestamps, MDevice,
864  &DeviceTime, &HostTime);
865  return Result != UR_RESULT_ERROR_INVALID_OPERATION;
866 }
867 
870  try {
873  } catch (sycl::exception &) {
874  return false;
875  }
876 }
877 
878 // Returns the strongest guarantee that can be provided by the host device for
879 // threads created at threadScope from a coordination scope given by
880 // coordinationScope
885  return sycl::ext::oneapi::experimental::forward_progress_guarantee::
886  weakly_parallel;
887 }
888 
889 // Returns the strongest progress guarantee that can be provided by this device
890 // for threads created at threadScope from the coordination scope given by
891 // coordinationScope.
895  ext::oneapi::experimental::execution_scope coordinationScope) const {
899  const int executionScopeSize = 4;
900  (void)coordinationScope;
901  int threadScopeNum = static_cast<int>(threadScope);
902  // we get the immediate progress guarantee that is provided by each scope
903  // between root_group and threadScope and then return the weakest of these.
904  // Counterintuitively, this corresponds to taking the max of the enum values
905  // because of how the forward_progress_guarantee enum values are declared.
906  int guaranteeNum = static_cast<int>(
907  getImmediateProgressGuarantee(execution_scope::root_group));
908  for (int currentScope = executionScopeSize - 2; currentScope > threadScopeNum;
909  --currentScope) {
910  guaranteeNum = std::max(guaranteeNum,
911  static_cast<int>(getImmediateProgressGuarantee(
912  static_cast<execution_scope>(currentScope))));
913  }
914  return static_cast<forward_progress_guarantee>(guaranteeNum);
915 }
916 
920  ext::oneapi::experimental::execution_scope coordinationScope) const {
921  using ReturnT =
922  std::vector<ext::oneapi::experimental::forward_progress_guarantee>;
923  auto guarantees = getProgressGuaranteesUpTo<ReturnT>(
924  getProgressGuarantee(threadScope, coordinationScope));
925  return std::find(guarantees.begin(), guarantees.end(), guarantee) !=
926  guarantees.end();
927 }
928 
929 // Returns the progress guarantee provided for a coordination scope
930 // given by coordination_scope for threads created at a scope
931 // immediately below coordination_scope. For example, for root_group
932 // coordination scope it returns the progress guarantee provided
933 // at root_group for threads created at work_group.
936  ext::oneapi::experimental::execution_scope coordination_scope) const {
940  if (is_cpu() && getBackend() == backend::opencl) {
941  switch (coordination_scope) {
942  case execution_scope::root_group:
943  return forward_progress_guarantee::parallel;
944  case execution_scope::work_group:
945  case execution_scope::sub_group:
946  return forward_progress_guarantee::weakly_parallel;
947  default:
948  throw sycl::exception(sycl::errc::invalid,
949  "Work item is not a valid coordination scope!");
950  }
951  } else if (is_gpu() && getBackend() == backend::ext_oneapi_level_zero) {
952  switch (coordination_scope) {
953  case execution_scope::root_group:
954  case execution_scope::work_group:
955  return forward_progress_guarantee::concurrent;
956  case execution_scope::sub_group:
957  return forward_progress_guarantee::weakly_parallel;
958  default:
959  throw sycl::exception(sycl::errc::invalid,
960  "Work item is not a valid coordination scope!");
961  }
962  }
963  return forward_progress_guarantee::weakly_parallel;
964 }
965 
966 } // namespace detail
967 } // namespace _V1
968 } // namespace sycl
ur_native_handle_t getNative() const
Gets the native handle of the SYCL device.
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.
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.
Definition: device_impl.cpp:98
bool isGetDeviceAndHostTimerSupported()
Check clGetDeviceAndHostTimer is available for fallback profiling.
std::string get_device_info_string(ur_device_info_t InfoCode) const
Get device info string.
device_impl()
Constructs a SYCL device instance as a host device.
bool is_cpu() const
Check if device is a CPU device.
Definition: device_impl.hpp:77
backend getBackend() const
Get the backend of this device.
const PluginPtr & getPlugin() const
bool is_gpu() const
Check if device is a GPU device.
Definition: device_impl.hpp:82
uint64_t getCurrentDeviceTime()
Gets the current device timestamp.
std::string getDeviceName() const
bool has_extension(const std::string &ExtensionName) const
Check SYCL extension support by device.
ur_device_handle_t & getHandleRef()
Get reference to UR device.
Definition: device_impl.hpp:65
static sycl::ext::oneapi::experimental::forward_progress_guarantee getHostProgressGuarantee(sycl::ext::oneapi::experimental::execution_scope threadScope, sycl::ext::oneapi::experimental::execution_scope coordinationScope)
sycl::ext::oneapi::experimental::forward_progress_guarantee getProgressGuarantee(ext::oneapi::experimental::execution_scope threadScope, ext::oneapi::experimental::execution_scope coordinationScope) const
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:85
cl_device_id get() const
Get instance of OpenCL device.
Definition: device_impl.cpp:92
ext::oneapi::experimental::architecture getDeviceArch() const
Get device architecture.
bool supportsForwardProgress(ext::oneapi::experimental::forward_progress_guarantee guarantee, ext::oneapi::experimental::execution_scope threadScope, ext::oneapi::experimental::execution_scope coordinationScope) const
ext::oneapi::experimental::forward_progress_guarantee getImmediateProgressGuarantee(ext::oneapi::experimental::execution_scope coordination_scope) const
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.
bool is_accelerator() const
Check if device is an accelerator device.
Definition: device_impl.hpp:87
static std::shared_ptr< platform_impl > getPlatformFromUrDevice(ur_device_handle_t UrDevice, 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
std::string affinityDomainToString(info::partition_affinity_domain AffinityDomain)
Definition: device_info.hpp:88
static const PluginPtr & getPlugin(backend Backend)
Definition: backend.cpp:32
std::shared_ptr< plugin > PluginPtr
Definition: ur.hpp:60
std::shared_ptr< detail::platform_impl > PlatformImplPtr
exception set_ur_error(exception &&e, int32_t ur_err)
Definition: exception.hpp:157
Function for_each(Group g, Ptr first, Ptr last, Function f)
bool is_source_kernel_bundle_supported(backend BE, source_language Language)
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
#define __SYCL_CHECK_OCL_CODE_NO_EXC(X)
Definition: plugin.hpp:36
bool any_of(const simd_mask< _Tp, _Abi > &) noexcept
C++ utilities for Unified Runtime integration.
#define UR_DEVICE_INFO_EXTENSION_DEVICELIB_ASSERT
Extension to denote native support of assert feature by an arbitrary device urDeviceGetInfo call shou...
Definition: ur.hpp:30