diff --git a/dpctl-capi/include/dpctl_sycl_device_interface.h b/dpctl-capi/include/dpctl_sycl_device_interface.h index 98496e4794..0a2a0aa033 100644 --- a/dpctl-capi/include/dpctl_sycl_device_interface.h +++ b/dpctl-capi/include/dpctl_sycl_device_interface.h @@ -479,3 +479,15 @@ uint32_t DPCTLDevice_GetPreferredVectorWidthDouble( DPCTL_API uint32_t DPCTLDevice_GetPreferredVectorWidthHalf( __dpctl_keep const DPCTLSyclDeviceRef DRef); + +/*! + * @brief Wrapper over + * device.get_info + * + * @param DRef Opaque pointer to a sycl::device + * @return Returns an opaque pointer to the parent device for a sub-device, + * or nullptr otherwise. + */ +DPCTL_API +__dpctl_give DPCTLSyclDeviceRef +DPCTLDevice_GetParentDevice(__dpctl_keep const DPCTLSyclDeviceRef DRef); diff --git a/dpctl-capi/include/dpctl_sycl_device_manager.h b/dpctl-capi/include/dpctl_sycl_device_manager.h index 03b16ea96e..37c02e241b 100644 --- a/dpctl-capi/include/dpctl_sycl_device_manager.h +++ b/dpctl-capi/include/dpctl_sycl_device_manager.h @@ -116,4 +116,15 @@ size_t DPCTLDeviceMgr_GetNumDevices(int device_identifier); DPCTL_API void DPCTLDeviceMgr_PrintDeviceInfo(__dpctl_keep const DPCTLSyclDeviceRef DRef); +/*! + * @brief Gives the index of the given device in the vector returned get_devices + * for the platform associated with DRef for the device type of DRef. + * + * @param DRef A #DPCTLSyclDeviceRef opaque pointer. + * @ingroup DeviceManager + */ +DPCTL_API +int64_t +DPCTLDeviceMgr_GetRelativeId(__dpctl_keep const DPCTLSyclDeviceRef DRef); + DPCTL_C_EXTERN_C_END diff --git a/dpctl-capi/source/dpctl_sycl_device_interface.cpp b/dpctl-capi/source/dpctl_sycl_device_interface.cpp index f56266b02b..636f1f2292 100644 --- a/dpctl-capi/source/dpctl_sycl_device_interface.cpp +++ b/dpctl-capi/source/dpctl_sycl_device_interface.cpp @@ -549,6 +549,27 @@ uint32_t DPCTLDevice_GetPreferredVectorWidthHalf( return vector_width_half; } +__dpctl_give DPCTLSyclDeviceRef +DPCTLDevice_GetParentDevice(__dpctl_keep const DPCTLSyclDeviceRef DRef) +{ + auto D = unwrap(DRef); + if (D) { + try { + auto parent_D = D->get_info(); + return wrap(new device(parent_D)); + } catch (invalid_object_error const &ioe) { + // not a sub device + return nullptr; + } catch (runtime_error const &re) { + // \todo log error + std::cerr << re.what() << '\n'; + return nullptr; + } + } + else + return nullptr; +} + __dpctl_give DPCTLDeviceVectorRef DPCTLDevice_CreateSubDevicesEqually(__dpctl_keep const DPCTLSyclDeviceRef DRef, size_t count) diff --git a/dpctl-capi/source/dpctl_sycl_device_manager.cpp b/dpctl-capi/source/dpctl_sycl_device_manager.cpp index 3eb72fc7fd..e2c8072502 100644 --- a/dpctl-capi/source/dpctl_sycl_device_manager.cpp +++ b/dpctl-capi/source/dpctl_sycl_device_manager.cpp @@ -194,3 +194,22 @@ void DPCTLDeviceMgr_PrintDeviceInfo(__dpctl_keep const DPCTLSyclDeviceRef DRef) std::cout << "Device is not valid (NULL). Cannot print device info.\n"; } } + +int64_t DPCTLDeviceMgr_GetRelativeId(__dpctl_keep const DPCTLSyclDeviceRef DRef) +{ + auto Device = unwrap(DRef); + + if (Device) { + auto p = Device->get_platform(); + auto dt = Device->get_info(); + auto dev_vec = p.get_devices(dt); + int64_t id = 0; + for (auto &d_i : dev_vec) { + if (*Device == d_i) + return id; + ++id; + } + return -1; + } + return -1; +} diff --git a/dpctl-capi/tests/test_sycl_device_interface.cpp b/dpctl-capi/tests/test_sycl_device_interface.cpp index 6a2c3f6842..e9c9285eb2 100644 --- a/dpctl-capi/tests/test_sycl_device_interface.cpp +++ b/dpctl-capi/tests/test_sycl_device_interface.cpp @@ -330,6 +330,13 @@ TEST_P(TestDPCTLSyclDeviceInterface, Chk_GetImage3dMaxDepth) EXPECT_TRUE(image_3d_max_depth >= min_val); } +TEST_P(TestDPCTLSyclDeviceInterface, Chk_GetParentDevice) +{ + DPCTLSyclDeviceRef pDRef = nullptr; + EXPECT_NO_FATAL_FAILURE(pDRef = DPCTLDevice_GetParentDevice(DRef)); + EXPECT_TRUE(pDRef == nullptr); +} + INSTANTIATE_TEST_SUITE_P(DPCTLDevice_Fns, TestDPCTLSyclDeviceInterface, ::testing::Values("opencl", diff --git a/dpctl-capi/tests/test_sycl_device_manager.cpp b/dpctl-capi/tests/test_sycl_device_manager.cpp index cbf41c551d..0f8b172718 100644 --- a/dpctl-capi/tests/test_sycl_device_manager.cpp +++ b/dpctl-capi/tests/test_sycl_device_manager.cpp @@ -56,6 +56,13 @@ struct TestDPCTLDeviceManager : public ::testing::TestWithParam } }; +TEST_P(TestDPCTLDeviceManager, Chk_GetRelativeId) +{ + int64_t rel_id = -1; + EXPECT_NO_FATAL_FAILURE(rel_id = DPCTLDeviceMgr_GetRelativeId(DRef)); + EXPECT_FALSE(rel_id == -1); +} + TEST_P(TestDPCTLDeviceManager, Chk_PrintDeviceInfo) { EXPECT_NO_FATAL_FAILURE(DPCTLDeviceMgr_PrintDeviceInfo(DRef)); diff --git a/dpctl-capi/tests/test_sycl_device_subdevices.cpp b/dpctl-capi/tests/test_sycl_device_subdevices.cpp index 904f5d2f5c..6501973b1e 100644 --- a/dpctl-capi/tests/test_sycl_device_subdevices.cpp +++ b/dpctl-capi/tests/test_sycl_device_subdevices.cpp @@ -81,7 +81,14 @@ TEST_P(TestDPCTLSyclDeviceInterface, Chk_CreateSubDevicesEqually) EXPECT_NO_FATAL_FAILURE( DVRef = DPCTLDevice_CreateSubDevicesEqually(DRef, count)); if (DVRef) { + DPCTLSyclDeviceRef pDRef = nullptr; + DPCTLSyclDeviceRef sDRef = nullptr; EXPECT_TRUE(DPCTLDeviceVector_Size(DVRef) > 0); + EXPECT_NO_FATAL_FAILURE(sDRef = DPCTLDeviceVector_GetAt(DVRef, 0)); + EXPECT_NO_FATAL_FAILURE(pDRef = DPCTLDevice_GetParentDevice(sDRef)); + EXPECT_NO_FATAL_FAILURE(DPCTLDevice_Delete(sDRef)); + EXPECT_TRUE(DPCTLDevice_AreEq(DRef, pDRef)); + EXPECT_NO_FATAL_FAILURE(DPCTLDevice_Delete(pDRef)); EXPECT_NO_FATAL_FAILURE(DPCTLDeviceVector_Delete(DVRef)); } } diff --git a/dpctl/_backend.pxd b/dpctl/_backend.pxd index 7ad51f7a51..efc4c3d691 100644 --- a/dpctl/_backend.pxd +++ b/dpctl/_backend.pxd @@ -22,7 +22,7 @@ types defined by dpctl's C API. """ from libcpp cimport bool -from libc.stdint cimport uint32_t +from libc.stdint cimport uint32_t, int64_t cdef extern from "dpctl_error_handler_type.h": @@ -192,6 +192,7 @@ cdef extern from "dpctl_sycl_device_interface.h": cdef DPCTLDeviceVectorRef DPCTLDevice_CreateSubDevicesByAffinity( const DPCTLSyclDeviceRef DRef, DPCTLPartitionAffinityDomainType PartitionAffinityDomainTy) + cdef DPCTLSyclDeviceRef DPCTLDevice_GetParentDevice(const DPCTLSyclDeviceRef DRef) cdef extern from "dpctl_sycl_device_manager.h": @@ -209,6 +210,7 @@ cdef extern from "dpctl_sycl_device_manager.h": cdef void DPCTLDeviceMgr_PrintDeviceInfo(const DPCTLSyclDeviceRef DRef) cdef DPCTLSyclContextRef DPCTLDeviceMgr_GetCachedContext( const DPCTLSyclDeviceRef DRef) + cdef int64_t DPCTLDeviceMgr_GetRelativeId(const DPCTLSyclDeviceRef DRef) cdef extern from "dpctl_sycl_device_selector_interface.h": diff --git a/dpctl/_sycl_device.pxd b/dpctl/_sycl_device.pxd index a87b5c8196..54070cbeef 100644 --- a/dpctl/_sycl_device.pxd +++ b/dpctl/_sycl_device.pxd @@ -25,10 +25,11 @@ from ._backend cimport ( DPCTLSyclDeviceSelectorRef, _partition_affinity_domain_type ) +from libcpp cimport bool as cpp_bool cdef class _SyclDevice: - ''' Wrapper class for a Sycl Device + ''' Wrapper data owner class for a Sycl Device ''' cdef DPCTLSyclDeviceRef _device_ref cdef const char *_vendor_name @@ -48,3 +49,4 @@ cdef class SyclDevice(_SyclDevice): cdef list create_sub_devices_equally(self, size_t count) cdef list create_sub_devices_by_counts(self, object counts) cdef list create_sub_devices_by_affinity(self, _partition_affinity_domain_type domain) + cpdef cpp_bool equals(self, SyclDevice q) diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index f0fcf77bdf..8b3758455b 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -34,6 +34,7 @@ from ._backend cimport ( DPCTLDeviceVector_Delete, DPCTLDeviceVector_GetAt, DPCTLDeviceVector_Size, + DPCTLDevice_AreEq, DPCTLDevice_GetBackend, DPCTLDevice_GetDeviceType, DPCTLDevice_GetDriverInfo, @@ -49,6 +50,7 @@ from ._backend cimport ( DPCTLDevice_IsGPU, DPCTLDevice_IsHost, DPCTLDeviceMgr_PrintDeviceInfo, + DPCTLDeviceMgr_GetRelativeId, DPCTLFilterSelector_Create, DPCTLDeviceSelector_Delete, DPCTLDeviceSelector_Score, @@ -74,9 +76,10 @@ from ._backend cimport ( DPCTLDevice_CreateSubDevicesEqually, DPCTLDevice_CreateSubDevicesByCounts, DPCTLDevice_CreateSubDevicesByAffinity, + DPCTLDevice_GetParentDevice, ) from . import backend_type, device_type -from libc.stdint cimport uint32_t +from libc.stdint cimport uint32_t, int64_t from libc.stdlib cimport malloc, free import warnings import collections @@ -96,7 +99,7 @@ cdef class SubDeviceCreationError(Exception): cdef class _SyclDevice: - """ A helper metaclass to abstract a cl::sycl::device instance. + """ A helper data-owner class to abstract a cl::sycl::device instance. """ def __dealloc__(self): @@ -124,6 +127,34 @@ cdef list _get_devices(DPCTLDeviceVectorRef DVRef): return devices +cdef str _backend_type_to_filter_string_part(DPCTLSyclBackendType BTy): + if BTy == _backend_type._CUDA: + return "cuda" + elif BTy == _backend_type._HOST: + return "host" + elif BTy == _backend_type._LEVEL_ZERO: + return "level_zero" + elif BTy == _backend_type._OPENCL: + return "opencl" + else: + return "unknown" + + +cdef str _device_type_to_filter_string_part(DPCTLSyclDeviceType DTy): + if DTy == _device_type._ACCELERATOR: + return "accelerator" + elif DTy == _device_type._AUTOMATIC: + return "automatic" + elif DTy == _device_type._CPU: + return "cpu" + elif DTy == _device_type._GPU: + return "gpu" + elif DTy == _device_type._HOST_DEVICE: + return "host" + else: + return "unknown" + + cdef class SyclDevice(_SyclDevice): """ Python equivalent for cl::sycl::device class. @@ -714,3 +745,49 @@ cdef class SyclDevice(_SyclDevice): return self.create_sub_devices_equally(partition) except Exception as e: raise TypeError("Unsupported type of sub-device argument") + + @property + def parent_device(self): + """ Parent device for a sub-device, or None for a root device. + """ + cdef DPCTLSyclDeviceRef pDRef = NULL + pDRef = DPCTLDevice_GetParentDevice(self._device_ref) + if (pDRef is NULL): + return None + return SyclDevice._create(pDRef) + + cpdef cpp_bool equals(self, SyclDevice other): + """ Returns true if the SyclDevice argument has the same _device_ref + as this SyclDevice. + """ + return DPCTLDevice_AreEq(self._device_ref, other.get_device_ref()) + + def __eq__(self, other): + if isinstance(other, SyclDevice): + return self.equals( other) + else: + return False + + @property + def filter_string(self): + """ For a parent device returns a tuple (backend, device_kind, relative_id). + Raises an exception for sub-devices. + """ + cdef DPCTLSyclDeviceRef pDRef = NULL + cdef DPCTLSyclBackendType BTy + cdef DPCTLSyclDeviceType DTy + cdef int64_t relId = -1 + pDRef = DPCTLDevice_GetParentDevice(self._device_ref) + if (pDRef is NULL): + BTy = DPCTLDevice_GetBackend(self._device_ref) + DTy = DPCTLDevice_GetDeviceType(self._device_ref) + relId = DPCTLDeviceMgr_GetRelativeId(self._device_ref) + if (relId == -1): + raise TypeError("This SyclDevice is not a root device") + br_str = _backend_type_to_filter_string_part(BTy) + dt_str = _device_type_to_filter_string_part(DTy) + return ":".join((br_str, dt_str, str(relId))) + else: + # this a sub-device, free it, and raise an exception + DPCTLDevice_Delete(pDRef) + raise TypeError("This SyclDevice is not a root device")