diff --git a/dpctl/__init__.py b/dpctl/__init__.py index ca4ee9796f..23bddf1222 100644 --- a/dpctl/__init__.py +++ b/dpctl/__init__.py @@ -32,8 +32,12 @@ """ __author__ = "Intel Corp." -from dpctl._sycl_context import SyclContext -from dpctl._sycl_device import SyclDevice +from dpctl._sycl_context import SyclContext, SyclContextCreationError +from dpctl._sycl_device import ( + SyclDevice, + SyclDeviceCreationError, + SyclSubDeviceCreationError, +) from dpctl._sycl_device_factory import ( get_devices, get_num_devices, @@ -73,9 +77,12 @@ __all__ = [ "SyclContext", + "SyclContextCreationError", ] __all__ += [ "SyclDevice", + "SyclDeviceCreationError", + "SyclSubDeviceCreationError", ] __all__ += [ "get_devices", diff --git a/dpctl/_device_selection.py b/dpctl/_device_selection.py index 7013552f0a..3f90354f18 100644 --- a/dpctl/_device_selection.py +++ b/dpctl/_device_selection.py @@ -1,7 +1,8 @@ import collections.abc from itertools import chain -from . import SyclDevice, get_devices +from ._sycl_device import SyclDevice, SyclDeviceCreationError +from ._sycl_device_factory import get_devices def select_device_with_aspects(required_aspects, excluded_aspects=[]): @@ -66,7 +67,7 @@ def select_device_with_aspects(required_aspects, excluded_aspects=[]): selected_dev = dev if selected_dev is None: - raise ValueError( + raise SyclDeviceCreationError( f"Requested device is unavailable: " f"required_aspects={required_aspects}, " f"excluded_aspects={excluded_aspects}" diff --git a/dpctl/_sycl_context.pyx b/dpctl/_sycl_context.pyx index 247a5d0f68..556069f1a4 100644 --- a/dpctl/_sycl_context.pyx +++ b/dpctl/_sycl_context.pyx @@ -49,13 +49,25 @@ from ._backend cimport ( # noqa: E211 ) from ._sycl_device cimport SyclDevice from ._sycl_queue cimport default_async_error_handler +from ._sycl_device import SyclDeviceCreationError __all__ = [ "SyclContext", + "SyclContextCreationError", ] _logger = logging.getLogger(__name__) + +cdef class SyclContextCreationError(Exception): + """ + A SyclContextCreationError exception is raised when + SyclContext could not created. + + """ + pass + + cdef void _context_capsule_deleter(object o): cdef DPCTLSyclContextRef CRef = NULL if pycapsule.PyCapsule_IsValid(o, "SyclContextRef"): @@ -162,7 +174,8 @@ cdef class SyclContext(_SyclContext): Raises: MemoryError: If the constructor could not allocate necessary temporary memory. - ValueError: If the :class:`dpctl.SyclContext` object creation failed. + SyclContextCreationError: If the :class:`dpctl.SyclContext` object + creation failed. TypeError: If the list of :class:`dpctl.SyclDevice` objects was empty, or the input capsule contained a null pointer or could not be renamed. @@ -283,11 +296,17 @@ cdef class SyclContext(_SyclContext): ): ret = self._init_context_from_devices(arg, 0) else: - dev = SyclDevice(arg) + try: + dev = SyclDevice(arg) + except SyclDeviceCreationError as e: + raise SyclContextCreationError( + "SyclContext failed to be created because " + f"SyclDevice could not be created from the argument {arg}" + ) from e ret = self._init_context_from_one_device( dev, 0) if (ret < 0): if (ret == -1): - raise ValueError("Context failed to be created.") + raise SyclContextCreationError("Context failed to be created.") elif (ret == -2): raise TypeError( "List of devices to create context from must be non-empty." diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index ff8ceaa591..373745f22f 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -95,13 +95,22 @@ import collections import warnings __all__ = [ - "SyclDevice", + "SyclDevice", "SyclDeviceCreationError", "SyclSubDeviceCreationError", ] -cdef class SubDeviceCreationError(Exception): +cdef class SyclDeviceCreationError(Exception): """ - A SubDeviceCreationError exception is raised when + A SyclDeviceCreationError exception is raised when + SyclDevice instance could not created. + + """ + pass + + +cdef class SyclSubDeviceCreationError(Exception): + """ + A SyclSubDeviceCreationError exception is raised when sub-devices were not created. """ @@ -165,6 +174,7 @@ cdef str _device_type_to_filter_string_part(_device_type DTy): else: return "unknown" + cdef void _init_helper(_SyclDevice device, DPCTLSyclDeviceRef DRef): "Populate attributes of device from opaque device reference DRef" device._device_ref = DRef @@ -213,6 +223,20 @@ cdef class SyclDevice(_SyclDevice): gpu = dpctl.select_gpu_device(): gpu.print_device_info() + Args: + arg (optional): The argument can be a selector string or None. + Defaults to ``None``. + + Raises: + MemoryError: If the constructor could not allocate necessary + temporary memory. + SyclDeviceCreationError: If the :class:`dpctl.SyclDevice` object + creation failed. + TypeError: If the list of :class:`dpctl.SyclDevice` objects was empty, + or the input capsule contained a null pointer or could not + be renamed. + + """ @staticmethod cdef SyclDevice _create(DPCTLSyclDeviceRef dref): @@ -262,20 +286,20 @@ cdef class SyclDevice(_SyclDevice): DSRef = DPCTLFilterSelector_Create(filter_c_str) ret = self._init_from_selector(DSRef) if ret == -1: - raise ValueError( + raise SyclDeviceCreationError( "Could not create a SyclDevice with the selector string" ) elif isinstance(arg, _SyclDevice): ret = self._init_from__SyclDevice(arg) if ret == -1: - raise ValueError( + raise SyclDeviceCreationError( "Could not create a SyclDevice from _SyclDevice instance" ) elif arg is None: DSRef = DPCTLDefaultSelector_Create() ret = self._init_from_selector(DSRef) if ret == -1: - raise ValueError( + raise SyclDeviceCreationError( "Could not create a SyclDevice from default selector" ) else: @@ -746,7 +770,7 @@ cdef class SyclDevice(_SyclDevice): if count > 0: DVRef = DPCTLDevice_CreateSubDevicesEqually(self._device_ref, count) if DVRef is NULL: - raise SubDeviceCreationError( + raise SyclSubDeviceCreationError( "Sub-devices were not created." if (count > 0) else "Sub-devices were not created, " "requested compute units count was zero." @@ -785,7 +809,7 @@ cdef class SyclDevice(_SyclDevice): ) free(counts_buff) if DVRef is NULL: - raise SubDeviceCreationError( + raise SyclSubDeviceCreationError( "Sub-devices were not created." if (min_count > 0) else "Sub-devices were not created, " "sub-device execution units counts must be positive." @@ -801,7 +825,7 @@ cdef class SyclDevice(_SyclDevice): cdef DPCTLDeviceVectorRef DVRef = NULL DVRef = DPCTLDevice_CreateSubDevicesByAffinity(self._device_ref, domain) if DVRef is NULL: - raise SubDeviceCreationError("Sub-devices were not created.") + raise SyclSubDeviceCreationError("Sub-devices were not created.") return _get_devices(DVRef) def create_sub_devices(self, **kwargs): diff --git a/dpctl/_sycl_device_factory.pyx b/dpctl/_sycl_device_factory.pyx index 23b30ba7b9..48b6cd1f58 100644 --- a/dpctl/_sycl_device_factory.pyx +++ b/dpctl/_sycl_device_factory.pyx @@ -46,6 +46,7 @@ from ._backend cimport ( # noqa: E211 _device_type, ) +from ._sycl_device import SyclDeviceCreationError from .enum_types import backend_type from .enum_types import device_type as device_type_t @@ -307,15 +308,15 @@ cpdef SyclDevice select_accelerator_device(): dpctl.SyclDevice: A Python object wrapping the SYCL ``device`` returned by the SYCL ``accelerator_selector``. Raises: - ValueError: If the SYCL ``accelerator_selector`` is unable to select a - ``device``. + dpctl.SyclDeviceCreatioError: If the SYCL ``accelerator_selector`` is + unable to select a ``device``. """ cdef DPCTLSyclDeviceSelectorRef DSRef = DPCTLAcceleratorSelector_Create() cdef DPCTLSyclDeviceRef DRef = DPCTLDevice_CreateFromSelector(DSRef) # Free up the device selector DPCTLDeviceSelector_Delete(DSRef) if DRef is NULL: - raise ValueError("Device unavailable.") + raise SyclDeviceCreationError("Accelerator device is unavailable.") Device = SyclDevice._create(DRef) return Device @@ -327,15 +328,15 @@ cpdef SyclDevice select_cpu_device(): dpctl.SyclDevice: A Python object wrapping the SYCL ``device`` returned by the SYCL ``cpu_selector``. Raises: - ValueError: If the SYCL ``cpu_selector`` is unable to select a - ``device``. + dpctl.SyclDeviceCreationError: If the SYCL ``cpu_selector`` is + unable to select a ``device``. """ cdef DPCTLSyclDeviceSelectorRef DSRef = DPCTLCPUSelector_Create() cdef DPCTLSyclDeviceRef DRef = DPCTLDevice_CreateFromSelector(DSRef) # Free up the device selector DPCTLDeviceSelector_Delete(DSRef) if DRef is NULL: - raise ValueError("Device unavailable.") + raise SyclDeviceCreationError("CPU device is unavailable.") Device = SyclDevice._create(DRef) return Device @@ -347,15 +348,15 @@ cpdef SyclDevice select_default_device(): dpctl.SyclDevice: A Python object wrapping the SYCL ``device`` returned by the SYCL ``default_selector``. Raises: - ValueError: If the SYCL ``default_selector`` is unable to select a - ``device``. + dpctl.SyclDeviceCreationError: If the SYCL ``default_selector`` is + unable to select a ``device``. """ cdef DPCTLSyclDeviceSelectorRef DSRef = DPCTLDefaultSelector_Create() cdef DPCTLSyclDeviceRef DRef = DPCTLDevice_CreateFromSelector(DSRef) # Free up the device selector DPCTLDeviceSelector_Delete(DSRef) if DRef is NULL: - raise ValueError("Device unavailable.") + raise SyclDeviceCreationError("Default device is unavailable.") Device = SyclDevice._create(DRef) return Device @@ -367,15 +368,15 @@ cpdef SyclDevice select_gpu_device(): dpctl.SyclDevice: A Python object wrapping the SYCL ``device`` returned by the SYCL ``gpu_selector``. Raises: - ValueError: If the SYCL ``gpu_selector`` is unable to select a - ``device``. + dpctl.SyclDeviceCreationError: If the SYCL ``gpu_selector`` is + unable to select a ``device``. """ cdef DPCTLSyclDeviceSelectorRef DSRef = DPCTLGPUSelector_Create() cdef DPCTLSyclDeviceRef DRef = DPCTLDevice_CreateFromSelector(DSRef) # Free up the device selector DPCTLDeviceSelector_Delete(DSRef) if DRef is NULL: - raise ValueError("Device unavailable.") + raise SyclDeviceCreationError("Device unavailable.") Device = SyclDevice._create(DRef) return Device @@ -387,14 +388,14 @@ cpdef SyclDevice select_host_device(): dpctl.SyclDevice: A Python object wrapping the SYCL ``device`` returned by the SYCL ``host_selector``. Raises: - ValueError: If the SYCL ``host_selector`` is unable to select a - ``device``. + dpctl.SyclDeviceCreationError: If the SYCL ``host_selector`` is + unable to select a ``device``. """ cdef DPCTLSyclDeviceSelectorRef DSRef = DPCTLHostSelector_Create() cdef DPCTLSyclDeviceRef DRef = DPCTLDevice_CreateFromSelector(DSRef) # Free up the device selector DPCTLDeviceSelector_Delete(DSRef) if DRef is NULL: - raise ValueError("Device unavailable.") + raise SyclDeviceCreationError("Host device is unavailable.") Device = SyclDevice._create(DRef) return Device diff --git a/dpctl/tests/test_sycl_context.py b/dpctl/tests/test_sycl_context.py index 7f0bc5d5ee..590bad7640 100644 --- a/dpctl/tests/test_sycl_context.py +++ b/dpctl/tests/test_sycl_context.py @@ -50,7 +50,7 @@ def test_ctxt_creation_from_filter(valid_filter): """ try: dpctl.SyclContext(valid_filter) - except ValueError: + except dpctl.SyclContextCreationError: pytest.skip("Failed to create context with supported filter") @@ -70,11 +70,11 @@ def test_context_not_equals(): """ try: ctx_gpu = dpctl.SyclContext("gpu") - except ValueError: + except dpctl.SyclContextCreationError: pytest.skip() try: ctx_cpu = dpctl.SyclContext("cpu") - except ValueError: + except dpctl.SyclContextCreationError: pytest.skip() assert ctx_cpu != ctx_gpu assert hash(ctx_cpu) != hash(ctx_gpu) @@ -93,7 +93,7 @@ def test_context_equals(): try: ctx1 = dpctl.SyclContext("gpu") ctx0 = dpctl.SyclContext("gpu") - except ValueError: + except dpctl.SyclContextCreationError: pytest.skip() assert ctx0 == ctx1 assert hash(ctx0) == hash(ctx1) @@ -118,7 +118,7 @@ def test_repr(): def test_context_can_be_used_in_queue(valid_filter): try: ctx = dpctl.SyclContext(valid_filter) - except ValueError: + except dpctl.SyclContextCreationError: pytest.skip() devs = ctx.get_devices() assert len(devs) == ctx.device_count @@ -129,7 +129,7 @@ def test_context_can_be_used_in_queue(valid_filter): def test_context_can_be_used_in_queue2(valid_filter): try: d = dpctl.SyclDevice(valid_filter) - except ValueError: + except dpctl.SyclDeviceCreationError: pytest.skip() if d.default_selector_score < 0: # skip test for devices rejected by default selector @@ -141,7 +141,7 @@ def test_context_can_be_used_in_queue2(valid_filter): def test_context_multi_device(): try: d = dpctl.SyclDevice("cpu") - except ValueError: + except dpctl.SyclDeviceCreationError: pytest.skip() if d.default_selector_score < 0: pytest.skip() @@ -244,5 +244,5 @@ def test_invalid_capsule(): def test_multi_device_different_platforms(): devs = dpctl.get_devices() # all devices if len(devs) > 1: - with pytest.raises(ValueError): + with pytest.raises(dpctl.SyclContextCreationError): dpctl.SyclContext(devs) diff --git a/dpctl/tests/test_sycl_device.py b/dpctl/tests/test_sycl_device.py index 77e3ae85cc..cf38f687d9 100644 --- a/dpctl/tests/test_sycl_device.py +++ b/dpctl/tests/test_sycl_device.py @@ -20,7 +20,7 @@ import pytest import dpctl -from dpctl._sycl_device import SubDeviceCreationError +from dpctl import SyclDeviceCreationError, SyclSubDeviceCreationError list_of_standard_selectors = [ dpctl.select_accelerator_device, @@ -363,7 +363,7 @@ def check_create_sub_devices_equally(device): try: n = int(device.max_compute_units / 2) device.create_sub_devices(partition=n) - except SubDeviceCreationError: + except SyclSubDeviceCreationError: pytest.skip( "create_sub_devices can't create sub-devices on this device" ) @@ -382,7 +382,7 @@ def check_create_sub_devices_by_counts(device): try: n = device.max_compute_units / 2 device.create_sub_devices(partition=(n, n)) - except SubDeviceCreationError: + except SyclSubDeviceCreationError: pytest.skip( "create_sub_devices can't create sub-devices on this device" ) @@ -400,7 +400,7 @@ def check_create_sub_devices_by_counts_zeros(device): def check_create_sub_devices_by_affinity_not_applicable(device): try: device.create_sub_devices(partition="not_applicable") - except SubDeviceCreationError: + except SyclSubDeviceCreationError: pytest.skip( "create_sub_devices can't create sub-devices on this device" ) @@ -411,7 +411,7 @@ def check_create_sub_devices_by_affinity_not_applicable(device): def check_create_sub_devices_by_affinity_numa(device): try: device.create_sub_devices(partition="numa") - except SubDeviceCreationError: + except SyclSubDeviceCreationError: pytest.skip( "create_sub_devices can't create sub-devices on this device" ) @@ -422,7 +422,7 @@ def check_create_sub_devices_by_affinity_numa(device): def check_create_sub_devices_by_affinity_L4_cache(device): try: device.create_sub_devices(partition="L4_cache") - except SubDeviceCreationError: + except SyclSubDeviceCreationError: pytest.skip( "create_sub_devices can't create sub-devices on this device" ) @@ -433,7 +433,7 @@ def check_create_sub_devices_by_affinity_L4_cache(device): def check_create_sub_devices_by_affinity_L3_cache(device): try: device.create_sub_devices(partition="L3_cache") - except SubDeviceCreationError: + except SyclSubDeviceCreationError: pytest.skip( "create_sub_devices can't create sub-devices on this device" ) @@ -444,7 +444,7 @@ def check_create_sub_devices_by_affinity_L3_cache(device): def check_create_sub_devices_by_affinity_L2_cache(device): try: device.create_sub_devices(partition="L2_cache") - except SubDeviceCreationError: + except SyclSubDeviceCreationError: pytest.skip( "create_sub_devices can't create sub-devices on this device" ) @@ -455,7 +455,7 @@ def check_create_sub_devices_by_affinity_L2_cache(device): def check_create_sub_devices_by_affinity_L1_cache(device): try: device.create_sub_devices(partition="L1_cache") - except SubDeviceCreationError: + except SyclSubDeviceCreationError: pytest.skip( "create_sub_devices can't create sub-devices on this device" ) @@ -466,7 +466,7 @@ def check_create_sub_devices_by_affinity_L1_cache(device): def check_create_sub_devices_by_affinity_next_partitionable(device): try: device.create_sub_devices(partition="next_partitionable") - except SubDeviceCreationError: + except SyclSubDeviceCreationError: pytest.skip( "create_sub_devices can't create sub-devices on this device" ) @@ -582,7 +582,7 @@ def test_standard_selectors(device_selector, check): try: device = device_selector() check(device) - except ValueError: + except dpctl.SyclDeviceCreationError: pytest.skip() @@ -604,7 +604,7 @@ def test_valid_filter_selectors(valid_filter, check): device = None try: device = dpctl.SyclDevice(valid_filter) - except ValueError: + except SyclDeviceCreationError: pytest.skip("Failed to create device with supported filter") check(device) @@ -613,7 +613,12 @@ def test_invalid_filter_selectors(invalid_filter): """ An invalid filter string should always be caught and a ValueError raised. """ - with pytest.raises(ValueError): + exc = ( + SyclDeviceCreationError + if isinstance(invalid_filter, str) + else ValueError + ) + with pytest.raises(exc): dpctl.SyclDevice(invalid_filter) @@ -624,7 +629,7 @@ def test_filter_string(valid_filter): device = None try: device = dpctl.SyclDevice(valid_filter) - except ValueError: + except SyclDeviceCreationError: pytest.skip("Failed to create device with supported filter") dev_id = device.filter_string assert ( @@ -717,7 +722,7 @@ def unsupported_aspect(request): def test_supported_aspect(supported_aspect): try: dpctl.select_device_with_aspects(supported_aspect) - except ValueError: + except dpctl.SyclDeviceCreationError: # ValueError may be raised if no device with # requested aspect charateristics is available pass @@ -736,9 +741,9 @@ def test_unsupported_aspect(unsupported_aspect): def test_handle_no_device(): - with pytest.raises(ValueError): + with pytest.raises(dpctl.SyclDeviceCreationError): dpctl.select_device_with_aspects(["gpu", "cpu"]) - with pytest.raises(ValueError): + with pytest.raises(dpctl.SyclDeviceCreationError): dpctl.select_device_with_aspects("cpu", excluded_aspects="cpu") diff --git a/dpctl/tests/test_sycl_queue.py b/dpctl/tests/test_sycl_queue.py index 6ee176a726..4665a4e267 100644 --- a/dpctl/tests/test_sycl_queue.py +++ b/dpctl/tests/test_sycl_queue.py @@ -307,7 +307,7 @@ def test_standard_selectors(device_selector, check): pytest.skip() q = dpctl.SyclQueue(device) check(q.get_sycl_device()) - except ValueError: + except dpctl.SyclDeviceCreationError: pytest.skip() diff --git a/examples/python/sycl_queue.py b/examples/python/sycl_queue.py index 5dd6f535fa..a20cf31f99 100644 --- a/examples/python/sycl_queue.py +++ b/examples/python/sycl_queue.py @@ -55,7 +55,12 @@ def create_queue_from_subdevice(): Create a queue from a sub-device. """ cpu_d = dpctl.SyclDevice("opencl:cpu:0") - sub_devs = cpu_d.create_sub_devices(partition=4) + try: + sub_devs = cpu_d.create_sub_devices(partition=2) + except dpctl.SyclSubDeviceCreationError: + print("Could not create sub device.") + print(f"{cpu_d} has {cpu_d.max_compute_units} compute units") + return q = dpctl.SyclQueue(sub_devs[0]) # a single-device context is created automatically print( @@ -69,10 +74,14 @@ def create_queue_from_subdevice_multidevice_context(): Create a queue from a sub-device. """ cpu_d = dpctl.SyclDevice("opencl:cpu:0") - sub_devs = cpu_d.create_sub_devices(partition=4) + try: + sub_devs = cpu_d.create_sub_devices(partition=2) + except dpctl.SyclSubDeviceCreationError: + print("Could not create sub device.") + print(f"{cpu_d} has {cpu_d.max_compute_units} compute units") + return ctx = dpctl.SyclContext(sub_devs) - q = dpctl.SyclQueue(ctx, sub_devs[0]) - # a single-device context is created automatically + q = dpctl.SyclQueue(ctx, sub_devs[0], partition="enable_profiling") print( "Number of devices in SyclContext " "associated with the queue: ", q.sycl_context.device_count,