From 6781a829ec26d260d2f6549d47877e8a7a72a23f Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Fri, 3 Jan 2025 19:36:21 -0800 Subject: [PATCH 01/13] Add get_device_id method to SyclDevice --- dpctl/_sycl_device.pyx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index d395a2b8e7..9b7f707223 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -1950,9 +1950,7 @@ cdef class SyclDevice(_SyclDevice): cdef int get_overall_ordinal(self): """ If this device is a root ``sycl::device``, returns the ordinal - position of this device in the vector ``sycl::device::get_devices()`` - filtered to contain only devices with the same backend as this - device. + position of this device in the vector ``sycl::device::get_devices()``. Returns -1 if the device is a sub-device, or the device could not be found in the vector. @@ -2045,6 +2043,18 @@ cdef class SyclDevice(_SyclDevice): else: return str(relId) + def get_device_id(self): + cdef int dev_id = -1 + + if self.parent_device: + raise TypeError("This SyclDevice is not a root device") + + dev_id = self.get_overall_ordinal() + if dev_id < 0: + raise ValueError + return dev_id + + cdef api DPCTLSyclDeviceRef SyclDevice_GetDeviceRef(SyclDevice dev): """ C-API function to get opaque device reference from From ea6e061dbcafd614665b7e08e854a5f8ecd190a0 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Fri, 3 Jan 2025 19:37:05 -0800 Subject: [PATCH 02/13] Adds conversion functions for dldevice and dpctl.SyclDevice --- dpctl/tensor/__init__.py | 6 ++++ dpctl/tensor/_dldevice_conversions.py | 40 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 dpctl/tensor/_dldevice_conversions.py diff --git a/dpctl/tensor/__init__.py b/dpctl/tensor/__init__.py index dc13b6b93b..1fa4834c96 100644 --- a/dpctl/tensor/__init__.py +++ b/dpctl/tensor/__init__.py @@ -59,6 +59,10 @@ uint64, ) from dpctl.tensor._device import Device +from dpctl.tensor._dldevice_conversions import ( + dldevice_to_sycldevice, + sycldevice_to_dldevice, +) from dpctl.tensor._dlpack import from_dlpack from dpctl.tensor._indexing_functions import ( extract, @@ -388,4 +392,6 @@ "take_along_axis", "put_along_axis", "top_k", + "dldevice_to_sycldevice", + "sycldevice_to_dldevice", ] diff --git a/dpctl/tensor/_dldevice_conversions.py b/dpctl/tensor/_dldevice_conversions.py new file mode 100644 index 0000000000..0779d3eef7 --- /dev/null +++ b/dpctl/tensor/_dldevice_conversions.py @@ -0,0 +1,40 @@ +# Data Parallel Control (dpctl) +# +# Copyright 2020-2025 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dpctl + +from ._usmarray import DLDeviceType + + +def dldevice_to_sycldevice(dl_dev: tuple): + if isinstance(dl_dev, tuple): + if len(dl_dev) != 2: + raise ValueError("dldevice tuple must have length 2") + else: + raise TypeError( + f"dl_dev is expected to be a 2-tuple, got " f"{type(dl_dev)}" + ) + if dl_dev[0] != DLDeviceType.kDLOneAPI: + raise ValueError("dldevice type must be kDLOneAPI") + return dpctl.SyclDevice(str(dl_dev[1])) + + +def sycldevice_to_dldevice(dev: dpctl.SyclDevice): + if not isinstance(dev, dpctl.SyclDevice): + raise TypeError( + "dev is expected to be a dpctl.SyclDevice, got " f"{type(dev)}" + ) + return (DLDeviceType.kDLOneAPI, dev.get_device_id()) From d972d076f49cd617d6b6696cd303d9898668570d Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Tue, 7 Jan 2025 10:49:01 -0800 Subject: [PATCH 03/13] import SyclDevice directly in _dldevice_conversions Full dpctl namespace is unnecessary, as only SyclDevice is used --- dpctl/tensor/_dldevice_conversions.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dpctl/tensor/_dldevice_conversions.py b/dpctl/tensor/_dldevice_conversions.py index 0779d3eef7..ef945bcfab 100644 --- a/dpctl/tensor/_dldevice_conversions.py +++ b/dpctl/tensor/_dldevice_conversions.py @@ -14,8 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import dpctl - +from .._sycl_device import SyclDevice from ._usmarray import DLDeviceType @@ -29,12 +28,12 @@ def dldevice_to_sycldevice(dl_dev: tuple): ) if dl_dev[0] != DLDeviceType.kDLOneAPI: raise ValueError("dldevice type must be kDLOneAPI") - return dpctl.SyclDevice(str(dl_dev[1])) + return SyclDevice(str(dl_dev[1])) -def sycldevice_to_dldevice(dev: dpctl.SyclDevice): - if not isinstance(dev, dpctl.SyclDevice): +def sycldevice_to_dldevice(dev: SyclDevice): + if not isinstance(dev, SyclDevice): raise TypeError( - "dev is expected to be a dpctl.SyclDevice, got " f"{type(dev)}" + "dev is expected to be a SyclDevice, got " f"{type(dev)}" ) return (DLDeviceType.kDLOneAPI, dev.get_device_id()) From 25833831f793f16d28977cf55a93f538f7755474 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Thu, 9 Jan 2025 10:25:59 -0800 Subject: [PATCH 04/13] Add tests for dldevice and sycldevice interchange functions --- dpctl/tests/test_usm_ndarray_dlpack.py | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/dpctl/tests/test_usm_ndarray_dlpack.py b/dpctl/tests/test_usm_ndarray_dlpack.py index 1fea8ec11e..6b15edfdfc 100644 --- a/dpctl/tests/test_usm_ndarray_dlpack.py +++ b/dpctl/tests/test_usm_ndarray_dlpack.py @@ -826,3 +826,38 @@ def test_generic_container(): assert isinstance(Z, dpt.usm_ndarray) assert Z._pointer == X._pointer assert Z.device == X.device + + +def test_sycldevice_to_dldevice(all_root_devices): + for sycl_dev in all_root_devices: + dev = dpt.sycldevice_to_dldevice(sycl_dev) + assert type(dev) is tuple + assert len(dev) == 2 + assert dev[0] == device_oneAPI + assert dev[1] == all_root_devices.index(sycl_dev) + + +def test_dldevice_to_sycldevice(all_root_devices): + for sycl_dev in all_root_devices: + dldev = dpt.empty(0, device=sycl_dev).__dlpack_device__() + dev = dpt.dldevice_to_sycldevice(dldev) + assert type(dev) is dpctl.SyclDevice + assert dev == all_root_devices[dldev[1]] + + +def test_dldevice_conversion_arg_validation(): + bad_dldevice_type = (dpt.DLDeviceType.kDLCPU, 0) + with pytest.raises(ValueError): + dpt.dldevice_to_sycldevice(bad_dldevice_type) + + bad_dldevice_len = bad_dldevice_type + (0,) + with pytest.raises(ValueError): + dpt.dldevice_to_sycldevice(bad_dldevice_len) + + bad_dldevice = dict() + with pytest.raises(TypeError): + dpt.dldevice_to_sycldevice(bad_dldevice) + + bad_sycldevice = dict() + with pytest.raises(TypeError): + dpt.sycldevice_to_dldevice(bad_sycldevice) From 7d35624d3f77a6b6073ac06e8f47039085280aeb Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Thu, 9 Jan 2025 11:29:52 -0800 Subject: [PATCH 05/13] Add tests for dpctl.SyclDevice.get_device_id method --- dpctl/tests/test_sycl_device.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/dpctl/tests/test_sycl_device.py b/dpctl/tests/test_sycl_device.py index 625f1c89f6..8c2da47a5d 100644 --- a/dpctl/tests/test_sycl_device.py +++ b/dpctl/tests/test_sycl_device.py @@ -265,3 +265,35 @@ def test_cpython_api_SyclDevice_Make(): d2 = make_d_fn(d.addressof_ref()) assert d == d2 + + +def test_get_device_id_method(): + """ + Test that the get_device_id method reconstructs the same device. + """ + devices = dpctl.get_devices() + for d in devices: + dev_id = d.get_device_id() + d_r = dpctl.SyclDevice(str(dev_id)) + assert dev_id == devices.index(d) + assert d == d_r + assert hash(d) == hash(d_r) + + +def test_sub_devices_disallow_device_id(): + try: + dev = dpctl.SyclDevice() + except dpctl.SyclDeviceCreationError: + pytest.skip("No default device available") + try: + sdevs = dev.create_sub_devices(partition="next_partitionable") + except dpctl.SyclSubDeviceCreationError: + sdevs = None + try: + if sdevs is None: + sdevs = dev.create_sub_devices(partition=[1, 1]) + except dpctl.SyclSubDeviceCreationError: + pytest.skip("Default device can not be partitioned") + assert isinstance(sdevs, list) and len(sdevs) > 0 + with pytest.raises(TypeError): + sdevs[0].get_device_id() From f15778e9ad37fe0b4c2e39dc552dd6cc7ce04ac1 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Sun, 12 Jan 2025 19:41:01 -0800 Subject: [PATCH 06/13] use sycl_device instead of sycldevice in dldevice conversion functions --- dpctl/tensor/__init__.py | 8 ++++---- dpctl/tensor/_dldevice_conversions.py | 4 ++-- dpctl/tests/test_usm_ndarray_dlpack.py | 16 ++++++++-------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/dpctl/tensor/__init__.py b/dpctl/tensor/__init__.py index 1fa4834c96..ea60fa0eb7 100644 --- a/dpctl/tensor/__init__.py +++ b/dpctl/tensor/__init__.py @@ -60,8 +60,8 @@ ) from dpctl.tensor._device import Device from dpctl.tensor._dldevice_conversions import ( - dldevice_to_sycldevice, - sycldevice_to_dldevice, + dldevice_to_sycl_device, + sycl_device_to_dldevice, ) from dpctl.tensor._dlpack import from_dlpack from dpctl.tensor._indexing_functions import ( @@ -392,6 +392,6 @@ "take_along_axis", "put_along_axis", "top_k", - "dldevice_to_sycldevice", - "sycldevice_to_dldevice", + "dldevice_to_sycl_device", + "sycl_device_to_dldevice", ] diff --git a/dpctl/tensor/_dldevice_conversions.py b/dpctl/tensor/_dldevice_conversions.py index ef945bcfab..b96e127633 100644 --- a/dpctl/tensor/_dldevice_conversions.py +++ b/dpctl/tensor/_dldevice_conversions.py @@ -18,7 +18,7 @@ from ._usmarray import DLDeviceType -def dldevice_to_sycldevice(dl_dev: tuple): +def dldevice_to_sycl_device(dl_dev: tuple): if isinstance(dl_dev, tuple): if len(dl_dev) != 2: raise ValueError("dldevice tuple must have length 2") @@ -31,7 +31,7 @@ def dldevice_to_sycldevice(dl_dev: tuple): return SyclDevice(str(dl_dev[1])) -def sycldevice_to_dldevice(dev: SyclDevice): +def sycl_device_to_dldevice(dev: SyclDevice): if not isinstance(dev, SyclDevice): raise TypeError( "dev is expected to be a SyclDevice, got " f"{type(dev)}" diff --git a/dpctl/tests/test_usm_ndarray_dlpack.py b/dpctl/tests/test_usm_ndarray_dlpack.py index 6b15edfdfc..e63c37bd0b 100644 --- a/dpctl/tests/test_usm_ndarray_dlpack.py +++ b/dpctl/tests/test_usm_ndarray_dlpack.py @@ -828,19 +828,19 @@ def test_generic_container(): assert Z.device == X.device -def test_sycldevice_to_dldevice(all_root_devices): +def test_sycl_device_to_dldevice(all_root_devices): for sycl_dev in all_root_devices: - dev = dpt.sycldevice_to_dldevice(sycl_dev) + dev = dpt.sycl_device_to_dldevice(sycl_dev) assert type(dev) is tuple assert len(dev) == 2 assert dev[0] == device_oneAPI assert dev[1] == all_root_devices.index(sycl_dev) -def test_dldevice_to_sycldevice(all_root_devices): +def test_dldevice_to_sycl_device(all_root_devices): for sycl_dev in all_root_devices: dldev = dpt.empty(0, device=sycl_dev).__dlpack_device__() - dev = dpt.dldevice_to_sycldevice(dldev) + dev = dpt.dldevice_to_sycl_device(dldev) assert type(dev) is dpctl.SyclDevice assert dev == all_root_devices[dldev[1]] @@ -848,16 +848,16 @@ def test_dldevice_to_sycldevice(all_root_devices): def test_dldevice_conversion_arg_validation(): bad_dldevice_type = (dpt.DLDeviceType.kDLCPU, 0) with pytest.raises(ValueError): - dpt.dldevice_to_sycldevice(bad_dldevice_type) + dpt.dldevice_to_sycl_device(bad_dldevice_type) bad_dldevice_len = bad_dldevice_type + (0,) with pytest.raises(ValueError): - dpt.dldevice_to_sycldevice(bad_dldevice_len) + dpt.dldevice_to_sycl_device(bad_dldevice_len) bad_dldevice = dict() with pytest.raises(TypeError): - dpt.dldevice_to_sycldevice(bad_dldevice) + dpt.dldevice_to_sycl_device(bad_dldevice) bad_sycldevice = dict() with pytest.raises(TypeError): - dpt.sycldevice_to_dldevice(bad_sycldevice) + dpt.sycl_device_to_dldevice(bad_sycldevice) From 14c7dc5ed904dca1299f06d39dd41b9b869a461a Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Mon, 13 Jan 2025 16:52:46 -0800 Subject: [PATCH 07/13] Change errors throughout _sycl_device.pyx --- dpctl/_sycl_device.pyx | 24 ++++++++++++------------ dpctl/tests/test_sycl_context.py | 2 +- dpctl/tests/test_sycl_device.py | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index 9b7f707223..dd62d40733 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -292,7 +292,7 @@ cdef class SyclDevice(_SyclDevice): temporary memory. SyclDeviceCreationError: If the :class:`dpctl.SyclDevice` object creation failed. - TypeError: + ValueError: If the list of :class:`dpctl.SyclDevice` objects was empty, or the input capsule contained a null pointer or could not be renamed. @@ -363,7 +363,7 @@ cdef class SyclDevice(_SyclDevice): "Could not create a SyclDevice from default selector" ) else: - raise ValueError( + raise TypeError( "Invalid argument. Argument should be a str object specifying " "a SYCL filter selector string." ) @@ -1557,7 +1557,7 @@ cdef class SyclDevice(_SyclDevice): cdef int i if ncounts == 0: - raise TypeError( + raise ValueError( "Non-empty object representing list of counts is expected." ) counts_buff = malloc(( ncounts) * sizeof(size_t)) @@ -1659,7 +1659,7 @@ cdef class SyclDevice(_SyclDevice): Created sub-devices. Raises: - TypeError: + ValueError: 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. @@ -1695,7 +1695,7 @@ cdef class SyclDevice(_SyclDevice): _partition_affinity_domain_type._next_partitionable ) else: - raise TypeError( + raise ValueError( "Partition affinity domain {} is not understood.".format( partition ) @@ -1708,11 +1708,11 @@ cdef class SyclDevice(_SyclDevice): else: try: partition = int(partition) - return self.create_sub_devices_equally(partition) except Exception as e: raise TypeError( "Unsupported type of sub-device argument" ) from e + return self.create_sub_devices_equally(partition) @property def parent_device(self): @@ -1877,7 +1877,7 @@ cdef class SyclDevice(_SyclDevice): A Python string representing a filter selector string. Raises: - TypeError: + ValueError: If the device is a sub-device. :Example: @@ -1902,7 +1902,7 @@ cdef class SyclDevice(_SyclDevice): else: # this a sub-device, free it, and raise an exception DPCTLDevice_Delete(pDRef) - raise TypeError("This SyclDevice is not a root device") + raise ValueError("This SyclDevice is not a root device") cdef int get_backend_and_device_type_ordinal(self): """ If this device is a root ``sycl::device``, returns the ordinal @@ -1983,9 +1983,9 @@ cdef class SyclDevice(_SyclDevice): A Python string representing a filter selector string. Raises: - TypeError: - If the device is a sub-device. ValueError: + If the device is a sub-device. + If no match for the device was found in the vector returned by ``sycl::device::get_devices()`` @@ -2024,7 +2024,7 @@ cdef class SyclDevice(_SyclDevice): else: # this a sub-device, free it, and raise an exception DPCTLDevice_Delete(pDRef) - raise TypeError("This SyclDevice is not a root device") + raise ValueError("This SyclDevice is not a root device") else: if include_backend: BTy = DPCTLDevice_GetBackend(self._device_ref) @@ -2047,7 +2047,7 @@ cdef class SyclDevice(_SyclDevice): cdef int dev_id = -1 if self.parent_device: - raise TypeError("This SyclDevice is not a root device") + raise ValueError("This SyclDevice is not a root device") dev_id = self.get_overall_ordinal() if dev_id < 0: diff --git a/dpctl/tests/test_sycl_context.py b/dpctl/tests/test_sycl_context.py index 8a940ba7f3..6c496a24bb 100644 --- a/dpctl/tests/test_sycl_context.py +++ b/dpctl/tests/test_sycl_context.py @@ -263,7 +263,7 @@ def test_cpython_api_SyclContext_Make(): def test_invalid_capsule(): cap = create_invalid_capsule() - with pytest.raises(ValueError): + with pytest.raises(TypeError): dpctl.SyclContext(cap) diff --git a/dpctl/tests/test_sycl_device.py b/dpctl/tests/test_sycl_device.py index 8c2da47a5d..57dd1d9f42 100644 --- a/dpctl/tests/test_sycl_device.py +++ b/dpctl/tests/test_sycl_device.py @@ -61,12 +61,12 @@ def test_valid_filter_selectors(valid_filter, check): def test_invalid_filter_selectors(invalid_filter): """ - An invalid filter string should always be caught and a ValueError raised. + An invalid filter string should always be caught and a TypeError raised. """ exc = ( SyclDeviceCreationError if isinstance(invalid_filter, str) - else ValueError + else TypeError ) with pytest.raises(exc): dpctl.SyclDevice(invalid_filter) @@ -295,5 +295,5 @@ def test_sub_devices_disallow_device_id(): except dpctl.SyclSubDeviceCreationError: pytest.skip("Default device can not be partitioned") assert isinstance(sdevs, list) and len(sdevs) > 0 - with pytest.raises(TypeError): + with pytest.raises(ValueError): sdevs[0].get_device_id() From 55944bc789553e5b6710bacbe6407ac86298ff9f Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Mon, 13 Jan 2025 16:54:43 -0800 Subject: [PATCH 08/13] Add docstring for dpctl.SyclDevice.get_device_id --- dpctl/_sycl_device.pyx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index dd62d40733..b6ae3e93c4 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -2044,6 +2044,23 @@ cdef class SyclDevice(_SyclDevice): return str(relId) def get_device_id(self): + """ get_device_id() + For a parent device, returns the canonical index of this device in the + list of devices visible to dpctl. + Returns: + int: + The index of the device. + Raises: + ValueError: + If the device is a sub-device. + :Example: + .. code-block:: python + import dpctl + gpu_dev = dpctl.SyclDevice("gpu") + i = gpu_dev.get_device_id + devs = dpctl.get_devices() + assert devs[i] == gpu_dev + """ cdef int dev_id = -1 if self.parent_device: From d3058ac225dfe6487f99b2fbed87bc5b6b2169c2 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Tue, 14 Jan 2025 09:15:44 -0800 Subject: [PATCH 09/13] Fix incorrect SyclDevice docstring --- dpctl/_sycl_device.pyx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index b6ae3e93c4..afcebd0a75 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -283,7 +283,8 @@ cdef class SyclDevice(_SyclDevice): Args: arg (str, optional): - The argument can be a selector string or ``None``. + The argument can be a selector string, another + :class:`dpctl.SyclDevice`, or ``None``. Defaults to ``None``. Raises: @@ -292,10 +293,8 @@ cdef class SyclDevice(_SyclDevice): temporary memory. SyclDeviceCreationError: If the :class:`dpctl.SyclDevice` object creation failed. - ValueError: - If the list of :class:`dpctl.SyclDevice` objects was empty, - or the input capsule contained a null pointer or could not - be renamed. + TypeError: + If the argument is not a :class:`dpctl.SyclDevice` or string. """ @staticmethod cdef SyclDevice _create(DPCTLSyclDeviceRef dref): @@ -365,7 +364,7 @@ cdef class SyclDevice(_SyclDevice): else: raise TypeError( "Invalid argument. Argument should be a str object specifying " - "a SYCL filter selector string." + "a SYCL filter selector string or another SyclDevice." ) def print_device_info(self): From d5cbe3fef8a1029c1ed7a44d3255a42e6720b052 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Tue, 14 Jan 2025 09:17:41 -0800 Subject: [PATCH 10/13] Fix missing line breaks in get_device_id method --- dpctl/_sycl_device.pyx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index afcebd0a75..974405a9ad 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -2044,14 +2044,17 @@ cdef class SyclDevice(_SyclDevice): def get_device_id(self): """ get_device_id() - For a parent device, returns the canonical index of this device in the - list of devices visible to dpctl. + For an unpartitioned device, returns the canonical index of this device + in the list of devices visible to dpctl. + Returns: int: The index of the device. + Raises: ValueError: If the device is a sub-device. + :Example: .. code-block:: python import dpctl From 66d8025b9ef791b3170c8a4db1b47cc76411e50b Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Tue, 14 Jan 2025 10:20:45 -0800 Subject: [PATCH 11/13] Fix get_device_id example spacing --- dpctl/_sycl_device.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index 974405a9ad..f6770ed33c 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -2057,6 +2057,7 @@ cdef class SyclDevice(_SyclDevice): :Example: .. code-block:: python + import dpctl gpu_dev = dpctl.SyclDevice("gpu") i = gpu_dev.get_device_id From cda903bd92c71d455f55d6bc479fcb1a5b765113 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Tue, 14 Jan 2025 11:30:59 -0800 Subject: [PATCH 12/13] Adds get_unpartitioned_parent_device method to SyclDevice --- dpctl/_sycl_device.pyx | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index f6770ed33c..a36b78851c 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -2042,6 +2042,30 @@ cdef class SyclDevice(_SyclDevice): else: return str(relId) + def get_unpartitioned_parent_device(self): + """ get_unpartitioned_parent_device(self) + + Returns the unpartitioned parent device of this device, or None for a + root device. + + Returns: + dpctl.SyclDevice: + A parent, unpartitioned :class:`dpctl.SyclDevice` instance if + the device is a sub-device, ``None`` otherwise. + """ + cdef DPCTLSyclDeviceRef pDRef = NULL + cdef DPCTLSyclDeviceRef tDRef = NULL + pDRef = DPCTLDevice_GetParentDevice(self._device_ref) + if pDRef is NULL: + return None + else: + tDRef = DPCTLDevice_GetParentDevice(pDRef) + while tDRef is not NULL: + DPCTLDevice_Delete(pDRef) + pDRef = tDRef + tDRef = DPCTLDevice_GetParentDevice(pDRef) + return SyclDevice._create(pDRef) + def get_device_id(self): """ get_device_id() For an unpartitioned device, returns the canonical index of this device From b1a5ecd98b53a7cb98e1a8f3dc49c4820dba189f Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Wed, 15 Jan 2025 11:03:37 -0800 Subject: [PATCH 13/13] Use get_device_id to find DLpack device ID --- dpctl/_sycl_device.pyx | 25 +++++++++++++------------ dpctl/tensor/_dlpack.pxd | 2 -- dpctl/tensor/_dlpack.pyx | 27 ++------------------------- dpctl/tensor/_usmarray.pyx | 14 +++++++------- dpctl/tests/test_sycl_device.py | 19 ++++++++++++++++--- 5 files changed, 38 insertions(+), 49 deletions(-) diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index a36b78851c..f8d59a56b0 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -2043,21 +2043,23 @@ cdef class SyclDevice(_SyclDevice): return str(relId) def get_unpartitioned_parent_device(self): - """ get_unpartitioned_parent_device(self) + """ get_unpartitioned_parent_device() - Returns the unpartitioned parent device of this device, or None for a - root device. + Returns the unpartitioned parent device of this device. + + If this device is already an unpartitioned, root device, + the same device is returned. Returns: dpctl.SyclDevice: - A parent, unpartitioned :class:`dpctl.SyclDevice` instance if - the device is a sub-device, ``None`` otherwise. + A parent, unpartitioned :class:`dpctl.SyclDevice` instance, or + ``self`` if already a root device. """ cdef DPCTLSyclDeviceRef pDRef = NULL cdef DPCTLSyclDeviceRef tDRef = NULL pDRef = DPCTLDevice_GetParentDevice(self._device_ref) if pDRef is NULL: - return None + return self else: tDRef = DPCTLDevice_GetParentDevice(pDRef) while tDRef is not NULL: @@ -2077,7 +2079,7 @@ cdef class SyclDevice(_SyclDevice): Raises: ValueError: - If the device is a sub-device. + If the device could not be found. :Example: .. code-block:: python @@ -2089,13 +2091,12 @@ cdef class SyclDevice(_SyclDevice): assert devs[i] == gpu_dev """ cdef int dev_id = -1 + cdef SyclDevice dev - if self.parent_device: - raise ValueError("This SyclDevice is not a root device") - - dev_id = self.get_overall_ordinal() + dev = self.get_unpartitioned_parent_device() + dev_id = dev.get_overall_ordinal() if dev_id < 0: - raise ValueError + raise ValueError("device could not be found") return dev_id diff --git a/dpctl/tensor/_dlpack.pxd b/dpctl/tensor/_dlpack.pxd index 68e2614cc8..028c2b10c7 100644 --- a/dpctl/tensor/_dlpack.pxd +++ b/dpctl/tensor/_dlpack.pxd @@ -47,8 +47,6 @@ cpdef object to_dlpack_versioned_capsule(usm_ndarray array, bint copied) except cpdef object numpy_to_dlpack_versioned_capsule(ndarray array, bint copied) except + cpdef object from_dlpack_capsule(object dltensor) except + -cdef int get_parent_device_ordinal_id(SyclDevice dev) except * - cdef class DLPackCreationError(Exception): """ A DLPackCreateError exception is raised when constructing diff --git a/dpctl/tensor/_dlpack.pyx b/dpctl/tensor/_dlpack.pyx index 085e986142..611fe27d2a 100644 --- a/dpctl/tensor/_dlpack.pyx +++ b/dpctl/tensor/_dlpack.pyx @@ -177,28 +177,6 @@ cdef object _get_default_context(c_dpctl.SyclDevice dev): return default_context - -cdef int get_parent_device_ordinal_id(c_dpctl.SyclDevice dev) except -1: - cdef DPCTLSyclDeviceRef pDRef = NULL - cdef DPCTLSyclDeviceRef tDRef = NULL - cdef c_dpctl.SyclDevice p_dev - - pDRef = DPCTLDevice_GetParentDevice(dev.get_device_ref()) - if pDRef is not NULL: - # if dev is a sub-device, find its parent - # and return its overall ordinal id - tDRef = DPCTLDevice_GetParentDevice(pDRef) - while tDRef is not NULL: - DPCTLDevice_Delete(pDRef) - pDRef = tDRef - tDRef = DPCTLDevice_GetParentDevice(pDRef) - p_dev = c_dpctl.SyclDevice._create(pDRef) - return p_dev.get_overall_ordinal() - - # return overall ordinal id of argument device - return dev.get_overall_ordinal() - - cdef int get_array_dlpack_device_id( usm_ndarray usm_ary ) except -1: @@ -224,14 +202,13 @@ cdef int get_array_dlpack_device_id( "on non-partitioned SYCL devices on platforms where " "default_context oneAPI extension is not supported." ) - device_id = ary_sycl_device.get_overall_ordinal() else: if not usm_ary.sycl_context == default_context: raise DLPackCreationError( "to_dlpack_capsule: DLPack can only export arrays based on USM " "allocations bound to a default platform SYCL context" ) - device_id = get_parent_device_ordinal_id(ary_sycl_device) + device_id = ary_sycl_device.get_device_id() if device_id < 0: raise DLPackCreationError( @@ -1086,7 +1063,7 @@ def from_dlpack(x, /, *, device=None, copy=None): d = device.sycl_device else: d = device - dl_device = (device_OneAPI, get_parent_device_ordinal_id(d)) + dl_device = (device_OneAPI, d.get_device_id()) if dl_device is not None: if (dl_device[0] not in [device_OneAPI, device_CPU]): raise ValueError( diff --git a/dpctl/tensor/_usmarray.pyx b/dpctl/tensor/_usmarray.pyx index 667574b6de..550b733186 100644 --- a/dpctl/tensor/_usmarray.pyx +++ b/dpctl/tensor/_usmarray.pyx @@ -1304,16 +1304,16 @@ cdef class usm_ndarray: DLPackCreationError: when the ``device_id`` could not be determined. """ - cdef int dev_id = c_dlpack.get_parent_device_ordinal_id(self.sycl_device) - if dev_id < 0: + try: + dev_id = self.sycl_device.get_device_id() + except ValueError as e: raise c_dlpack.DLPackCreationError( "Could not determine id of the device where array was allocated." ) - else: - return ( - DLDeviceType.kDLOneAPI, - dev_id, - ) + return ( + DLDeviceType.kDLOneAPI, + dev_id, + ) def __eq__(self, other): return dpctl.tensor.equal(self, other) diff --git a/dpctl/tests/test_sycl_device.py b/dpctl/tests/test_sycl_device.py index 57dd1d9f42..35fd3f03c9 100644 --- a/dpctl/tests/test_sycl_device.py +++ b/dpctl/tests/test_sycl_device.py @@ -280,7 +280,21 @@ def test_get_device_id_method(): assert hash(d) == hash(d_r) -def test_sub_devices_disallow_device_id(): +def test_get_unpartitioned_parent_device_method(): + """ + Test that the get_unpartitioned_parent method returns self for root + devices. + """ + devices = dpctl.get_devices() + for d in devices: + assert d == d.get_unpartitioned_parent_device() + + +def test_get_unpartitioned_parent_device_from_sub_device(): + """ + Test that the get_unpartitioned_parent method returns the parent device + from the sub-device. + """ try: dev = dpctl.SyclDevice() except dpctl.SyclDeviceCreationError: @@ -295,5 +309,4 @@ def test_sub_devices_disallow_device_id(): except dpctl.SyclSubDeviceCreationError: pytest.skip("Default device can not be partitioned") assert isinstance(sdevs, list) and len(sdevs) > 0 - with pytest.raises(ValueError): - sdevs[0].get_device_id() + assert dev == sdevs[0].get_unpartitioned_parent_device()