From 1524e5089ef77d12c85c964d81ca0e1dec9c89c7 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Mon, 5 Apr 2021 09:51:08 -0500 Subject: [PATCH 1/6] Added DPCTLDevice_GetParentDevice --- .../include/dpctl_sycl_device_interface.h | 12 +++++++++++ .../source/dpctl_sycl_device_interface.cpp | 21 +++++++++++++++++++ .../tests/test_sycl_device_interface.cpp | 7 +++++++ .../tests/test_sycl_device_subdevices.cpp | 7 +++++++ 4 files changed, 47 insertions(+) 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/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/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_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)); } } From f10dc20099e093e7ea26986d0a97312f1f10ba59 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Mon, 5 Apr 2021 10:57:01 -0500 Subject: [PATCH 2/6] DPCTL_GetParentDevice added to _backend.pxd --- dpctl/_backend.pxd | 1 + 1 file changed, 1 insertion(+) diff --git a/dpctl/_backend.pxd b/dpctl/_backend.pxd index 7ad51f7a51..a24013b24a 100644 --- a/dpctl/_backend.pxd +++ b/dpctl/_backend.pxd @@ -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": From 0f4f61e43a50be80adb6629ff94b01baeb20f25c Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Mon, 5 Apr 2021 10:57:51 -0500 Subject: [PATCH 3/6] Added property parent_device This returns None for root devices, but returns a SyclDevice for a sub-device. Added cpdef method equals, and Python method __eq__ ``` Python 3.7.9 (default, Mar 10 2021, 05:18:00) Type 'copyright', 'credits' or 'license' for more information IPython 7.22.0 -- An enhanced Interactive Python. Type '?' for help. In [1]: import dpctl In [2]: cpu_device = dpctl.SyclDevice("cpu") In [3]: cpu_device == cpu_device Out[3]: True In [4]: cpu_device2 = dpctl.SyclDevice("cpu") In [5]: cpu_device == cpu_device2 Out[5]: True In [6]: [d1, d2, d3 ] =cpu_device.create_sub_devices(partition=4) In [7]: d1.parent_device == cpu_device Out[7]: True In [8]: d2.parent_device == cpu_device Out[8]: True In [9]: d3.parent_device == cpu_device Out[9]: True ``` --- dpctl/_sycl_device.pxd | 4 +++- dpctl/_sycl_device.pyx | 24 +++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) 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..eba18a9500 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, @@ -74,6 +75,7 @@ from ._backend cimport ( DPCTLDevice_CreateSubDevicesEqually, DPCTLDevice_CreateSubDevicesByCounts, DPCTLDevice_CreateSubDevicesByAffinity, + DPCTLDevice_GetParentDevice, ) from . import backend_type, device_type from libc.stdint cimport uint32_t @@ -96,7 +98,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): @@ -714,3 +716,23 @@ 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): + 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 From 103635c2eda140c580d479dc22c1c8dc9c5ca433 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Mon, 5 Apr 2021 12:03:00 -0500 Subject: [PATCH 4/6] Added DPCTLDeviceMgr_GetRelativeId(DRef) This computes the relative id (position in the vector) inside p.get_devices( sycl_device_type(DRef) ). Returns -1 is the device was not found (expected to happen for sub-devices). --- .../include/dpctl_sycl_device_manager.h | 11 +++++++++++ .../source/dpctl_sycl_device_manager.cpp | 19 +++++++++++++++++++ dpctl-capi/tests/test_sycl_device_manager.cpp | 7 +++++++ 3 files changed, 37 insertions(+) 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_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_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)); From 7bddc4bc4c4b5fa3f51a581b966054d4aa011abd Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Mon, 5 Apr 2021 12:25:39 -0500 Subject: [PATCH 5/6] exported DPCTLDeviceMgr_GetRelativeId --- dpctl/_backend.pxd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dpctl/_backend.pxd b/dpctl/_backend.pxd index a24013b24a..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": @@ -210,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": From f2c900c9278e486619f623c47df4fc585b8fc15d Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Mon, 5 Apr 2021 12:26:48 -0500 Subject: [PATCH 6/6] Added device_filter_string ``` In [1]: import dpctl In [2]: dpctl.SyclDevice("cpu").filter_string Out[2]: 'opencl:cpu:0' In [3]: dpctl.SyclDevice("gpu").filter_string Out[3]: 'level_zero:gpu:0' In [4]: dpctl.SyclDevice("opencl:gpu").filter_string Out[4]: 'opencl:gpu:0' In [5]: dpctl.SyclDevice().filter_string Out[5]: 'level_zero:gpu:0' In [6]: dpctl.SyclDevice("0").filter_string Out[6]: 'opencl:accelerator:0' In [7]: dpctl.SyclDevice("1").filter_string Out[7]: 'opencl:cpu:0' In [8]: dpctl.SyclDevice("2").filter_string Out[8]: 'opencl:cpu:0' In [9]: dpctl.SyclDevice("3").filter_string Out[9]: 'opencl:gpu:0' In [10]: dpctl.SyclDevice("4").filter_string Out[10]: 'level_zero:gpu:0' ``` --- dpctl/_sycl_device.pyx | 57 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index eba18a9500..8b3758455b 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -50,6 +50,7 @@ from ._backend cimport ( DPCTLDevice_IsGPU, DPCTLDevice_IsHost, DPCTLDeviceMgr_PrintDeviceInfo, + DPCTLDeviceMgr_GetRelativeId, DPCTLFilterSelector_Create, DPCTLDeviceSelector_Delete, DPCTLDeviceSelector_Score, @@ -78,7 +79,7 @@ from ._backend cimport ( 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 @@ -126,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. @@ -719,6 +748,8 @@ cdef class SyclDevice(_SyclDevice): @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): @@ -736,3 +767,27 @@ cdef class SyclDevice(_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")