diff --git a/docs/doc_sources/api_reference/dpctl/index.rst b/docs/doc_sources/api_reference/dpctl/index.rst index 11f86ecb21..94858c2681 100644 --- a/docs/doc_sources/api_reference/dpctl/index.rst +++ b/docs/doc_sources/api_reference/dpctl/index.rst @@ -61,6 +61,7 @@ has_gpu_devices has_cpu_devices has_accelerator_devices + get_composite_devices .. rubric:: Enums diff --git a/dpctl/__init__.py b/dpctl/__init__.py index e4dd710ade..3a80c68a71 100644 --- a/dpctl/__init__.py +++ b/dpctl/__init__.py @@ -35,6 +35,7 @@ SyclSubDeviceCreationError, ) from ._sycl_device_factory import ( + get_composite_devices, get_devices, get_num_devices, has_accelerator_devices, @@ -87,6 +88,7 @@ "has_gpu_devices", "has_accelerator_devices", "has_host_device", + "get_composite_devices", ] __all__ += [ "SyclEvent", diff --git a/dpctl/_backend.pxd b/dpctl/_backend.pxd index 9b41499160..27a00ef2c0 100644 --- a/dpctl/_backend.pxd +++ b/dpctl/_backend.pxd @@ -98,6 +98,8 @@ cdef extern from "syclinterface/dpctl_sycl_enum_types.h": _usm_atomic_shared_allocations 'usm_atomic_shared_allocations', _host_debuggable 'host_debuggable', _emulated 'emulated', + _is_component 'is_component', + _is_composite 'is_composite', ctypedef enum _partition_affinity_domain_type 'DPCTLPartitionAffinityDomainType': _not_applicable 'not_applicable', @@ -217,6 +219,8 @@ cdef extern from "syclinterface/dpctl_sycl_device_interface.h": cdef uint32_t DPCTLDevice_GetPartitionMaxSubDevices(const DPCTLSyclDeviceRef DRef) cdef uint32_t DPCTLDevice_GetMaxClockFrequency(const DPCTLSyclDeviceRef DRef) cdef uint64_t DPCTLDevice_GetMaxMemAllocSize(const DPCTLSyclDeviceRef DRef) + cdef DPCTLSyclDeviceRef DPCTLDevice_GetCompositeDevice(const DPCTLSyclDeviceRef DRef) + cdef DPCTLDeviceVectorRef DPCTLDevice_GetComponentDevices(const DPCTLSyclDeviceRef DRef) cdef extern from "syclinterface/dpctl_sycl_device_manager.h": @@ -238,6 +242,7 @@ cdef extern from "syclinterface/dpctl_sycl_device_manager.h": cdef DPCTLSyclContextRef DPCTLDeviceMgr_GetCachedContext( const DPCTLSyclDeviceRef DRef) cdef int64_t DPCTLDeviceMgr_GetRelativeId(const DPCTLSyclDeviceRef DRef) + cdef DPCTLDeviceVectorRef DPCTLDeviceMgr_GetCompositeDevices() cdef extern from "syclinterface/dpctl_sycl_device_selector_interface.h": @@ -316,6 +321,8 @@ cdef extern from "syclinterface/dpctl_sycl_platform_interface.h": const DPCTLSyclPlatformRef) cdef DPCTLDeviceVectorRef DPCTLPlatform_GetDevices( const DPCTLSyclPlatformRef PRef, _device_type DTy) + cdef DPCTLDeviceVectorRef DPCTLPlatform_GetCompositeDevices( + const DPCTLSyclPlatformRef PRef) cdef extern from "syclinterface/dpctl_sycl_context_interface.h": diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index f8d59a56b0..fef70b5cfb 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -32,6 +32,8 @@ from ._backend cimport ( # noqa: E211 DPCTLDevice_CreateSubDevicesEqually, DPCTLDevice_Delete, DPCTLDevice_GetBackend, + DPCTLDevice_GetComponentDevices, + DPCTLDevice_GetCompositeDevice, DPCTLDevice_GetDeviceType, DPCTLDevice_GetDriverVersion, DPCTLDevice_GetGlobalMemCacheLineSize, @@ -795,6 +797,32 @@ cdef class SyclDevice(_SyclDevice): cdef _aspect_type AT = _aspect_type._emulated return DPCTLDevice_HasAspect(self._device_ref, AT) + @property + def has_aspect_is_component(self): + """ Returns ``True`` if this device is a component device, ``False`` + otherwise. A device with this aspect will have a composite device + from which it is descended. + + Returns: + bool: + Indicates if device is a component device. + """ + cdef _aspect_type AT = _aspect_type._is_component + return DPCTLDevice_HasAspect(self._device_ref, AT) + + + @property + def has_aspect_is_composite(self): + """ Returns ``True`` if this device is a composite device, ``False`` + otherwise. A device with this aspect contains component devices. + + Returns: + bool: + Indicates if device is a composite device. + """ + cdef _aspect_type AT = _aspect_type._is_composite + return DPCTLDevice_HasAspect(self._device_ref, AT) + @property def image_2d_max_width(self): """ Returns the maximum width of a 2D image or 1D image in pixels. @@ -1520,7 +1548,7 @@ cdef class SyclDevice(_SyclDevice): Created sub-devices. Raises: - dpctl.SyclSubdeviceCreationError: + dpctl.SyclSubDeviceCreationError: if sub-devices can not be created. """ cdef DPCTLDeviceVectorRef DVRef = NULL @@ -1546,7 +1574,7 @@ cdef class SyclDevice(_SyclDevice): Created sub-devices. Raises: - dpctl.SyclSubdeviceCreationError: + dpctl.SyclSubDeviceCreationError: if sub-devices can not be created. """ cdef int ncounts = len(counts) @@ -1592,7 +1620,7 @@ cdef class SyclDevice(_SyclDevice): Created sub-devices. Raises: - dpctl.SyclSubdeviceCreationError: + dpctl.SyclSubDeviceCreationError: if sub-devices can not be created. """ cdef DPCTLDeviceVectorRef DVRef = NULL @@ -1662,7 +1690,7 @@ cdef class SyclDevice(_SyclDevice): If the ``partition`` keyword argument is not specified or the affinity domain string is not legal or is not one of the three supported options. - dpctl.SyclSubdeviceCreationError: + dpctl.SyclSubDeviceCreationError: If sub-devices can not be created. """ if "partition" not in kwargs: @@ -1728,6 +1756,43 @@ cdef class SyclDevice(_SyclDevice): return None return SyclDevice._create(pDRef) + @property + def composite_device(self): + """ The composite device for a component device, or ``None`` for a + non-component device. + + Returns: + dpctl.SyclDevice: + The composite :class:`dpctl.SyclDevice` instance for a + component device, or ``None`` for a non-component device. + """ + cdef DPCTLSyclDeviceRef CDRef = NULL + CDRef = DPCTLDevice_GetCompositeDevice(self._device_ref) + if (CDRef is NULL): + return None + return SyclDevice._create(CDRef) + + def component_devices(self): + """ Returns a list of component devices contained in this SYCL device. + + The returned list will be empty if this SYCL device is not a composite + device, i.e., if `is_composite` is ``False``. + + Returns: + List[:class:`dpctl.SyclDevice`]: + List of component devices. + + Raises: + ValueError: + If the ``DPCTLDevice_GetComponentDevices`` call returned + ``NULL`` instead of a ``DPCTLDeviceVectorRef`` object. + """ + cdef DPCTLDeviceVectorRef cDVRef = NULL + cDVRef = DPCTLDevice_GetComponentDevices(self._device_ref) + if cDVRef is NULL: + raise ValueError("Internal error: NULL device vector encountered") + return _get_devices(cDVRef) + @property def profiling_timer_resolution(self): """ Profiling timer resolution. diff --git a/dpctl/_sycl_device_factory.pxd b/dpctl/_sycl_device_factory.pxd index e5644ccdbf..6ed5de90e3 100644 --- a/dpctl/_sycl_device_factory.pxd +++ b/dpctl/_sycl_device_factory.pxd @@ -32,6 +32,7 @@ cpdef SyclDevice select_cpu_device() cpdef SyclDevice select_default_device() cpdef SyclDevice select_gpu_device() cpdef list get_devices(backend=*, device_type=*) +cpdef list get_composite_devices() cpdef int get_num_devices(backend=*, device_type=*) cpdef cpp_bool has_gpu_devices() cpdef cpp_bool has_cpu_devices() diff --git a/dpctl/_sycl_device_factory.pyx b/dpctl/_sycl_device_factory.pyx index 2d6784c878..ef2f7a4a1a 100644 --- a/dpctl/_sycl_device_factory.pyx +++ b/dpctl/_sycl_device_factory.pyx @@ -31,6 +31,7 @@ from ._backend cimport ( # noqa: E211 DPCTLCPUSelector_Create, DPCTLDefaultSelector_Create, DPCTLDevice_CreateFromSelector, + DPCTLDeviceMgr_GetCompositeDevices, DPCTLDeviceMgr_GetDevices, DPCTLDeviceMgr_GetNumDevices, DPCTLDeviceSelector_Delete, @@ -62,6 +63,7 @@ __all__ = [ "has_gpu_devices", "has_accelerator_devices", "_cached_default_device", + "get_composite_devices", ] @@ -202,6 +204,32 @@ cpdef list get_devices(backend=backend_type.all, device_type=device_type_t.all): return devices +cpdef list get_composite_devices(): + """ + Returns a list of the available composite :class:`dpctl.SyclDevice` + instances. + + Only available when `ZE_FLAT_DEVICE_HIERARCHY=COMBINED` is set in + the environment, and only for specific Level Zero devices + (i.e., those which expose multiple tiles as root devices). + + For more information, see: + https://github.com/intel/llvm/blob/sycl/sycl/doc/extensions/experimental/sycl_ext_oneapi_composite_device.asciidoc + + Returns: + list: + A list of available composite :class:`dpctl.SyclDevice` instances. + """ + cdef DPCTLDeviceVectorRef DVRef = NULL + cdef list composite_devices + + DVRef = DPCTLDeviceMgr_GetCompositeDevices() + composite_devices = _get_devices(DVRef) + DPCTLDeviceVector_Delete(DVRef) + + return composite_devices + + cpdef int get_num_devices( backend=backend_type.all, device_type=device_type_t.all ): diff --git a/dpctl/_sycl_platform.pyx b/dpctl/_sycl_platform.pyx index ab9a2c0489..c27cb63dad 100644 --- a/dpctl/_sycl_platform.pyx +++ b/dpctl/_sycl_platform.pyx @@ -37,6 +37,7 @@ from ._backend cimport ( # noqa: E211 DPCTLPlatform_CreateFromSelector, DPCTLPlatform_Delete, DPCTLPlatform_GetBackend, + DPCTLPlatform_GetCompositeDevices, DPCTLPlatform_GetDefaultContext, DPCTLPlatform_GetDevices, DPCTLPlatform_GetName, @@ -448,6 +449,38 @@ cdef class SyclPlatform(_SyclPlatform): return devices + def get_composite_devices(self): + """ + Returns the list of composite :class:`dpctl.SyclDevice` objects + associated with :class:`dpctl.SyclPlatform` instance. + + Returns: + list: + A :obj:`list` of composite :class:`dpctl.SyclDevice` objects + that belong to this platform. + + Raises: + ValueError: + If the ``DPCTLPlatform_GetCompositeDevices`` call returned + ``NULL`` instead of a ``DPCTLDeviceVectorRef`` object. + """ + cdef DPCTLDeviceVectorRef DVRef = NULL + cdef size_t num_devs + cdef size_t i + cdef DPCTLSyclDeviceRef DRef + + DVRef = DPCTLPlatform_GetCompositeDevices(self.get_platform_ref()) + if (DVRef is NULL): + raise ValueError("Internal error: NULL device vector encountered") + num_devs = DPCTLDeviceVector_Size(DVRef) + composite_devices = [] + for i in range(num_devs): + DRef = DPCTLDeviceVector_GetAt(DVRef, i) + composite_devices.append(SyclDevice._create(DRef)) + DPCTLDeviceVector_Delete(DVRef) + + return composite_devices + def lsplatform(verbosity=0): """ diff --git a/dpctl/tests/test_sycl_device.py b/dpctl/tests/test_sycl_device.py index 35fd3f03c9..0d8025c060 100644 --- a/dpctl/tests/test_sycl_device.py +++ b/dpctl/tests/test_sycl_device.py @@ -165,6 +165,8 @@ def test_equal(): "usm_atomic_host_allocations", "usm_atomic_shared_allocations", "emulated", + "is_component", + "is_composite", ] # SYCL 2020 spec aspects not presently @@ -310,3 +312,32 @@ def test_get_unpartitioned_parent_device_from_sub_device(): pytest.skip("Default device can not be partitioned") assert isinstance(sdevs, list) and len(sdevs) > 0 assert dev == sdevs[0].get_unpartitioned_parent_device() + + +def test_composite_device_method(): + """ + Test that the composite_device method returns a composite + device found in ``dpctl.get_composite_devices()`` + """ + devices = dpctl.get_devices() + composite_devices = dpctl.get_composite_devices() + for d in devices: + if d.has_aspect_is_component: + Cd = d.composite_device + assert Cd in composite_devices + + +def test_get_component_devices_from_composite(): + """ + Test that the component_devices method returns component + root devices. + """ + devices = dpctl.get_devices() + composite_devices = dpctl.get_composite_devices() + for Cd in composite_devices: + assert Cd.has_aspect_is_composite + component_devices = Cd.component_devices() + for d in component_devices: + assert d.has_aspect_is_component + # component devices are root devices + assert d in devices diff --git a/dpctl/tests/test_sycl_device_factory.py b/dpctl/tests/test_sycl_device_factory.py index 8bd9d43f0e..3317ba17fb 100644 --- a/dpctl/tests/test_sycl_device_factory.py +++ b/dpctl/tests/test_sycl_device_factory.py @@ -185,3 +185,13 @@ def test_get_devices_with_device_type_str(device_type_str): assert dev == devices[i] else: pytest.skip() + + +def test_get_composite_devices(): + devices = dpctl.get_composite_devices() + if devices: + num_devices = len(devices) + for i in range(num_devices): + assert devices[i].has_aspect_is_composite + else: + pytest.skip() diff --git a/dpctl/tests/test_sycl_platform.py b/dpctl/tests/test_sycl_platform.py index ef0a6b0e5c..66d85db13c 100644 --- a/dpctl/tests/test_sycl_platform.py +++ b/dpctl/tests/test_sycl_platform.py @@ -259,3 +259,20 @@ def test_platform_get_devices_enum_device_type(): devices = p.get_devices(device_type=dty) if len(devices): assert (d.device_type == dty for d in devices) + + +def test_platform_get_composite_devices(): + platforms = dpctl.get_platforms() + if platforms: + for p in platforms: + composite_devices = p.get_composite_devices() + if not composite_devices: + pass + devices = p.get_devices() + for Cd in composite_devices: + assert Cd.has_aspect_is_composite + component_devices = Cd.component_devices() + # all component devices are root devices + assert all(d in devices for d in component_devices) + else: + pytest.skip("No platforms available") diff --git a/libsyclinterface/helper/source/dpctl_utils_helper.cpp b/libsyclinterface/helper/source/dpctl_utils_helper.cpp index fe3bbd86cb..88c1385a26 100644 --- a/libsyclinterface/helper/source/dpctl_utils_helper.cpp +++ b/libsyclinterface/helper/source/dpctl_utils_helper.cpp @@ -218,6 +218,12 @@ std::string DPCTL_AspectToStr(aspect aspectTy) case aspect::emulated: ss << "emulated"; break; + case aspect::ext_oneapi_is_component: + ss << "is_component"; + break; + case aspect::ext_oneapi_is_composite: + ss << "is_composite"; + break; default: throw std::runtime_error("Unsupported aspect type"); } @@ -287,6 +293,12 @@ aspect DPCTL_StrToAspectType(const std::string &aspectTyStr) else if (aspectTyStr == "emulated") { aspectTy = aspect::emulated; } + else if (aspectTyStr == "is_component") { + aspectTy = aspect::ext_oneapi_is_component; + } + else if (aspectTyStr == "is_composite") { + aspectTy = aspect::ext_oneapi_is_composite; + } else { // \todo handle the error throw std::runtime_error("Unsupported aspect type"); @@ -335,6 +347,10 @@ aspect DPCTL_DPCTLAspectTypeToSyclAspect(DPCTLSyclAspectType AspectTy) return aspect::host_debuggable; case DPCTLSyclAspectType::emulated: return aspect::emulated; + case DPCTLSyclAspectType::is_component: + return aspect::ext_oneapi_is_component; + case DPCTLSyclAspectType::is_composite: + return aspect::ext_oneapi_is_composite; default: throw std::runtime_error("Unsupported aspect type"); } @@ -381,6 +397,10 @@ DPCTLSyclAspectType DPCTL_SyclAspectToDPCTLAspectType(aspect Aspect) return DPCTLSyclAspectType::host_debuggable; case aspect::emulated: return DPCTLSyclAspectType::emulated; + case aspect::ext_oneapi_is_composite: + return DPCTLSyclAspectType::is_composite; + case aspect::ext_oneapi_is_component: + return DPCTLSyclAspectType::is_component; default: throw std::runtime_error("Unsupported aspect type"); } diff --git a/libsyclinterface/include/syclinterface/dpctl_sycl_device_interface.h b/libsyclinterface/include/syclinterface/dpctl_sycl_device_interface.h index 5f940600ec..6fddb2967f 100644 --- a/libsyclinterface/include/syclinterface/dpctl_sycl_device_interface.h +++ b/libsyclinterface/include/syclinterface/dpctl_sycl_device_interface.h @@ -766,4 +766,30 @@ __dpctl_keep size_t * DPCTLDevice_GetSubGroupSizes(__dpctl_keep const DPCTLSyclDeviceRef DRef, size_t *res_len); +/*! + * @brief Wrapper over + * device.get_info + * + * @param DRef Opaque pointer to a sycl::device + * @return Returns an opaque pointer to the composite device for a + * component device, or nullptr if the device is not a component device. + */ +DPCTL_API +__dpctl_give DPCTLSyclDeviceRef +DPCTLDevice_GetCompositeDevice(__dpctl_keep const DPCTLSyclDeviceRef DRef); + +/*! + * @brief Returns a vector of component devices that are contained by the + * provided composite device. If the device is not a composite device, + * returns an empty vector. + * + * @param DRef Opaque pointer to a ``sycl::device`` + * @return A #DPCTLDeviceVectorRef containing component + * #DPCTLSyclDeviceRef objects + * @ingroup DeviceInterface + */ +DPCTL_API +__dpctl_give DPCTLDeviceVectorRef +DPCTLDevice_GetComponentDevices(__dpctl_keep const DPCTLSyclDeviceRef DRef); + DPCTL_C_EXTERN_C_END diff --git a/libsyclinterface/include/syclinterface/dpctl_sycl_device_manager.h b/libsyclinterface/include/syclinterface/dpctl_sycl_device_manager.h index 72618c1b0b..cec8ec076c 100644 --- a/libsyclinterface/include/syclinterface/dpctl_sycl_device_manager.h +++ b/libsyclinterface/include/syclinterface/dpctl_sycl_device_manager.h @@ -173,6 +173,17 @@ DPCTL_API int64_t DPCTLDeviceMgr_GetRelativeId(__dpctl_keep const DPCTLSyclDeviceRef DRef); +/*! + * @brief Returns a pointer to a std::vector + * containing the set of ::DPCTLSyclDeviceRef pointers to the + * available composite devices. + * + * @return A #DPCTLDeviceVectorRef containing #DPCTLSyclDeviceRef objects + * that are composite devices. + */ +DPCTL_API +__dpctl_give DPCTLDeviceVectorRef DPCTLDeviceMgr_GetCompositeDevices(); + /*! @} */ DPCTL_C_EXTERN_C_END diff --git a/libsyclinterface/include/syclinterface/dpctl_sycl_enum_types.h b/libsyclinterface/include/syclinterface/dpctl_sycl_enum_types.h index e98ded7849..2c2ff3bc09 100644 --- a/libsyclinterface/include/syclinterface/dpctl_sycl_enum_types.h +++ b/libsyclinterface/include/syclinterface/dpctl_sycl_enum_types.h @@ -130,7 +130,9 @@ typedef enum usm_atomic_host_allocations, usm_atomic_shared_allocations, host_debuggable, - emulated + emulated, + is_component, + is_composite } DPCTLSyclAspectType; /*! diff --git a/libsyclinterface/include/syclinterface/dpctl_sycl_platform_interface.h b/libsyclinterface/include/syclinterface/dpctl_sycl_platform_interface.h index 66b22e9663..e803e11071 100644 --- a/libsyclinterface/include/syclinterface/dpctl_sycl_platform_interface.h +++ b/libsyclinterface/include/syclinterface/dpctl_sycl_platform_interface.h @@ -193,4 +193,17 @@ __dpctl_give DPCTLDeviceVectorRef DPCTLPlatform_GetDevices(__dpctl_keep const DPCTLSyclPlatformRef PRef, DPCTLSyclDeviceType DTy); +/*! + * @brief Returns a vector of composite devices associated with sycl::platform + * referenced by DPCTLSyclPlatformRef object. + * + * @param PRef The DPCTLSyclPlatformRef pointer. + * @return A DPCTLDeviceVectorRef with composite devices associated with + * given PRef. + * @ingroup PlatformInterface + */ +DPCTL_API +__dpctl_give DPCTLDeviceVectorRef +DPCTLPlatform_GetCompositeDevices(__dpctl_keep const DPCTLSyclPlatformRef PRef); + DPCTL_C_EXTERN_C_END diff --git a/libsyclinterface/source/dpctl_sycl_device_interface.cpp b/libsyclinterface/source/dpctl_sycl_device_interface.cpp index 2f0fb63b3b..7b1e900b58 100644 --- a/libsyclinterface/source/dpctl_sycl_device_interface.cpp +++ b/libsyclinterface/source/dpctl_sycl_device_interface.cpp @@ -849,3 +849,57 @@ DPCTLDevice_GetSubGroupSizes(__dpctl_keep const DPCTLSyclDeviceRef DRef, } return sizes; } + +__dpctl_give DPCTLDeviceVectorRef +DPCTLDevice_GetComponentDevices(__dpctl_keep const DPCTLSyclDeviceRef DRef) +{ + using vecTy = std::vector; + vecTy *ComponentDevicesVectorPtr = nullptr; + if (DRef) { + auto D = unwrap(DRef); + try { + auto componentDevices = + D->get_info(); + ComponentDevicesVectorPtr = new vecTy(); + ComponentDevicesVectorPtr->reserve(componentDevices.size()); + for (const auto &cd : componentDevices) { + ComponentDevicesVectorPtr->emplace_back( + wrap(new device(cd))); + } + } catch (std::exception const &e) { + delete ComponentDevicesVectorPtr; + error_handler(e, __FILE__, __func__, __LINE__); + return nullptr; + } + } + return wrap(ComponentDevicesVectorPtr); +} + +__dpctl_give DPCTLSyclDeviceRef +DPCTLDevice_GetCompositeDevice(__dpctl_keep const DPCTLSyclDeviceRef DRef) +{ + auto D = unwrap(DRef); + if (D) { + bool is_component = false; + try { + is_component = D->has(sycl::aspect::ext_oneapi_is_component); + } catch (std::exception const &e) { + error_handler(e, __FILE__, __func__, __LINE__); + return nullptr; + } + if (!is_component) + return nullptr; + try { + const auto &compositeDevice = + D->get_info(); + return wrap(new device(compositeDevice)); + } catch (std::exception const &e) { + error_handler(e, __FILE__, __func__, __LINE__); + return nullptr; + } + } + else + return nullptr; +} diff --git a/libsyclinterface/source/dpctl_sycl_device_manager.cpp b/libsyclinterface/source/dpctl_sycl_device_manager.cpp index bac6df7ec0..e87f7dd0ab 100644 --- a/libsyclinterface/source/dpctl_sycl_device_manager.cpp +++ b/libsyclinterface/source/dpctl_sycl_device_manager.cpp @@ -112,7 +112,7 @@ struct DeviceCacheBuilder * avoid the performance overhead of context creation for every queue. * * The singleton pattern implemented here ensures that the map is - * created once in a thread-safe manner. Since, the map is ony read + * created once in a thread-safe manner. Since, the map is only read * post-creation we do not need any further protection to ensure * thread-safety. */ @@ -136,7 +136,7 @@ struct DeviceCacheBuilder try { // Per https://github.com/intel/llvm/blob/sycl/sycl/doc/ - // extensions/PlatformContext/PlatformContext.adoc + // extensions/supported/sycl_ext_oneapi_default_context.asciidoc // sycl::queue(D) would create default platform context // for capable compiler, sycl::context(D) otherwise auto Q = queue(D); @@ -357,3 +357,35 @@ int64_t DPCTLDeviceMgr_GetRelativeId(__dpctl_keep const DPCTLSyclDeviceRef DRef) return -1; } + +/*! + * Returns a list of the available composite devices, or an empty list if + * there are none. + */ +__dpctl_give DPCTLDeviceVectorRef DPCTLDeviceMgr_GetCompositeDevices() +{ + using vecTy = std::vector; + vecTy *Devices = nullptr; + + try { + Devices = new std::vector(); + } catch (std::exception const &e) { + delete Devices; + error_handler(e, __FILE__, __func__, __LINE__); + return nullptr; + } + + try { + auto composite_devices = + ext::oneapi::experimental::get_composite_devices(); + Devices->reserve(composite_devices.size()); + for (const auto &CDev : composite_devices) { + Devices->emplace_back(wrap(new device(std::move(CDev)))); + } + return wrap(Devices); + } catch (std::exception const &e) { + delete Devices; + error_handler(e, __FILE__, __func__, __LINE__); + return nullptr; + } +} diff --git a/libsyclinterface/source/dpctl_sycl_platform_interface.cpp b/libsyclinterface/source/dpctl_sycl_platform_interface.cpp index 71234d420d..f6ab657834 100644 --- a/libsyclinterface/source/dpctl_sycl_platform_interface.cpp +++ b/libsyclinterface/source/dpctl_sycl_platform_interface.cpp @@ -316,3 +316,39 @@ DPCTLPlatform_GetDevices(__dpctl_keep const DPCTLSyclPlatformRef PRef, return nullptr; } } + +__dpctl_give DPCTLDeviceVectorRef +DPCTLPlatform_GetCompositeDevices(__dpctl_keep const DPCTLSyclPlatformRef PRef) +{ + auto P = unwrap(PRef); + if (!P) { + error_handler("Cannot retrieve composite devices from " + "DPCTLSyclPlatformRef as input is a nullptr.", + __FILE__, __func__, __LINE__); + return nullptr; + } + + using vecTy = std::vector; + vecTy *DevicesVectorPtr = nullptr; + try { + DevicesVectorPtr = new vecTy(); + } catch (std::exception const &e) { + delete DevicesVectorPtr; + error_handler(e, __FILE__, __func__, __LINE__); + return nullptr; + } + + try { + auto composite_devices = P->ext_oneapi_get_composite_devices(); + DevicesVectorPtr->reserve(composite_devices.size()); + for (const auto &Dev : composite_devices) { + DevicesVectorPtr->emplace_back( + wrap(new device(std::move(Dev)))); + } + return wrap(DevicesVectorPtr); + } catch (std::exception const &e) { + delete DevicesVectorPtr; + error_handler(e, __FILE__, __func__, __LINE__); + return nullptr; + } +} diff --git a/libsyclinterface/tests/test_sycl_device_aspects.cpp b/libsyclinterface/tests/test_sycl_device_aspects.cpp index adbe867b56..8c0ffe1f16 100644 --- a/libsyclinterface/tests/test_sycl_device_aspects.cpp +++ b/libsyclinterface/tests/test_sycl_device_aspects.cpp @@ -127,7 +127,11 @@ auto build_params() std::make_pair("usm_atomic_shared_allocations", sycl::aspect::usm_atomic_shared_allocations), std::make_pair("host_debuggable", sycl::aspect::host_debuggable), - std::make_pair("emulated", sycl::aspect::emulated)); + std::make_pair("emulated", sycl::aspect::emulated), + std::make_pair("is_component", + sycl::aspect::ext_oneapi_is_component), + std::make_pair("is_composite", + sycl::aspect::ext_oneapi_is_composite)); auto pairs = build_param_pairs, diff --git a/libsyclinterface/tests/test_sycl_device_interface.cpp b/libsyclinterface/tests/test_sycl_device_interface.cpp index ee44f0b15a..49783df694 100644 --- a/libsyclinterface/tests/test_sycl_device_interface.cpp +++ b/libsyclinterface/tests/test_sycl_device_interface.cpp @@ -539,6 +539,18 @@ TEST_P(TestDPCTLSyclDeviceInterface, ChkGetGlobalMemCacheType) res == DPCTL_MEM_CACHE_TYPE_READ_WRITE)); } +TEST_P(TestDPCTLSyclDeviceInterface, ChkGetCompositeDevice) +{ + DPCTLSyclDeviceRef CDRef = nullptr; + EXPECT_NO_FATAL_FAILURE(CDRef = DPCTLDevice_GetCompositeDevice(DRef)); + if (DPCTLDevice_HasAspect(DRef, DPCTLSyclAspectType::is_component)) { + EXPECT_TRUE(CDRef != nullptr); + } + else { + EXPECT_TRUE(CDRef == nullptr); + } +} + INSTANTIATE_TEST_SUITE_P(DPCTLDeviceFns, TestDPCTLSyclDeviceInterface, ::testing::Values("opencl", @@ -898,3 +910,18 @@ TEST_F(TestDPCTLSyclDeviceNullArgs, ChkGetSubGroupSizes) ASSERT_TRUE(sg_sizes == nullptr); ASSERT_TRUE(sg_sizes_len == 0); } + +TEST_F(TestDPCTLSyclDeviceNullArgs, ChkGetComponentDevices) +{ + DPCTLDeviceVectorRef cDVRef = nullptr; + EXPECT_NO_FATAL_FAILURE(cDVRef = + DPCTLDevice_GetComponentDevices(Null_DRef)); + ASSERT_TRUE(cDVRef == nullptr); +} + +TEST_F(TestDPCTLSyclDeviceNullArgs, ChkGetCompositeDevice) +{ + DPCTLSyclDeviceRef CDRef = nullptr; + EXPECT_NO_FATAL_FAILURE(CDRef = DPCTLDevice_GetCompositeDevice(Null_DRef)); + EXPECT_TRUE(CDRef == nullptr); +} diff --git a/libsyclinterface/tests/test_sycl_device_manager.cpp b/libsyclinterface/tests/test_sycl_device_manager.cpp index f0fff04c64..0ce19124c4 100644 --- a/libsyclinterface/tests/test_sycl_device_manager.cpp +++ b/libsyclinterface/tests/test_sycl_device_manager.cpp @@ -316,3 +316,49 @@ TEST_F(TestDPCTLDeviceMgrNullReference, ChkGetPositionInDevices) EXPECT_NO_FATAL_FAILURE( DPCTLDeviceMgr_GetPositionInDevices(nullDRef, mask)); } + +struct TestDPCTLGetCompositeDevices : public ::testing::Test +{ + DPCTLDeviceVectorRef DV = nullptr; + size_t nDevices = 0; + + TestDPCTLGetCompositeDevices() + { + EXPECT_NO_FATAL_FAILURE(DV = DPCTLDeviceMgr_GetCompositeDevices()); + EXPECT_TRUE(DV != nullptr); + EXPECT_NO_FATAL_FAILURE(nDevices = DPCTLDeviceVector_Size(DV)); + } + + void SetUp() + { + if (!nDevices) { + GTEST_SKIP_("Skipping as no composite devices available"); + } + } + + ~TestDPCTLGetCompositeDevices() + { + EXPECT_NO_FATAL_FAILURE(DPCTLDeviceVector_Clear(DV)); + EXPECT_NO_FATAL_FAILURE(DPCTLDeviceVector_Delete(DV)); + } +}; + +TEST_F(TestDPCTLGetCompositeDevices, ChkGetAt) +{ + for (auto i = 0ul; i < nDevices; ++i) { + DPCTLSyclDeviceRef DRef = nullptr; + EXPECT_NO_FATAL_FAILURE(DRef = DPCTLDeviceVector_GetAt(DV, i)); + ASSERT_TRUE(DRef != nullptr); + } +} + +TEST_F(TestDPCTLGetCompositeDevices, ChkCompositeAspect) +{ + for (auto i = 0ul; i < nDevices; ++i) { + DPCTLSyclDeviceRef DRef = nullptr; + EXPECT_NO_FATAL_FAILURE(DRef = DPCTLDeviceVector_GetAt(DV, i)); + ASSERT_TRUE(DRef != nullptr); + ASSERT_TRUE( + DPCTLDevice_HasAspect(DRef, DPCTLSyclAspectType::is_composite)); + } +} diff --git a/libsyclinterface/tests/test_sycl_platform_interface.cpp b/libsyclinterface/tests/test_sycl_platform_interface.cpp index 8bd100669b..3a1b970f63 100644 --- a/libsyclinterface/tests/test_sycl_platform_interface.cpp +++ b/libsyclinterface/tests/test_sycl_platform_interface.cpp @@ -113,6 +113,28 @@ void check_platform_get_devices(__dpctl_keep const DPCTLSyclPlatformRef PRef) EXPECT_NO_FATAL_FAILURE(DPCTLDeviceVector_Delete(DVRef)); } +void check_platform_get_composite_devices( + __dpctl_keep const DPCTLSyclPlatformRef PRef) +{ + DPCTLDeviceVectorRef CDVRef = nullptr; + size_t nCDevices = 0; + + EXPECT_NO_FATAL_FAILURE(CDVRef = DPCTLPlatform_GetCompositeDevices(PRef)); + EXPECT_TRUE(CDVRef != nullptr); + EXPECT_NO_FATAL_FAILURE(nCDevices = DPCTLDeviceVector_Size(CDVRef)); + for (auto i = 0ul; i < nCDevices; ++i) { + DPCTLSyclDeviceRef CDRef = nullptr; + EXPECT_NO_FATAL_FAILURE(CDRef = DPCTLDeviceVector_GetAt(CDVRef, i)); + ASSERT_TRUE(CDRef != nullptr); + ASSERT_TRUE( + DPCTLDevice_HasAspect(CDRef, DPCTLSyclAspectType::is_composite)); + EXPECT_NO_FATAL_FAILURE(DPCTLDevice_Delete(CDRef)); + } + + EXPECT_NO_FATAL_FAILURE(DPCTLDeviceVector_Clear(CDVRef)); + EXPECT_NO_FATAL_FAILURE(DPCTLDeviceVector_Delete(CDVRef)); +} + } // namespace struct TestDPCTLSyclPlatformInterface @@ -308,6 +330,11 @@ TEST_P(TestDPCTLSyclPlatformInterface, ChkGetDevices) check_platform_get_devices(PRef); } +TEST_P(TestDPCTLSyclPlatformInterface, ChkGetCompositeDevices) +{ + check_platform_get_composite_devices(PRef); +} + TEST_F(TestDPCTLSyclDefaultPlatform, ChkGetName) { check_platform_name(PRef); } TEST_F(TestDPCTLSyclDefaultPlatform, ChkGetVendor)