Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Added `add_event` and `add_cleanup_event` methods and `cleanup_events` and `num_cleanup_events` properties to the order manager, for tracking the events that gate the release of objects used by offloaded tasks [gh-2359](https://github.com/IntelPython/dpctl/pull/2359)
* Added `SyclQueue_DeferRelease` C-API function, which defers a release callback until work submitted to a queue completes, and through which `dpctl::utils::keep_args_alive` keeps its arguments alive [gh-2359](https://github.com/IntelPython/dpctl/pull/2359)
* Added `dpctl::utils::defer_release` to `dpctl4pybind11.hpp`, which calls a release callback once the given events have completed [gh-2359](https://github.com/IntelPython/dpctl/pull/2359)
* Added `custom` device type to filter selector strings [gh-2420](https://github.com/IntelPython/dpctl/pull/2420)

### Changed
* Object lifetime during offload is now managed by a list of releases deferred until the events that gate them have completed, rather than by a `host_task`. `dpctl` keeps one thread for looking over the list and running the releases that have come due, started by the first release deferred and again in the child of a `fork`, which takes the GIL to do so and lets a release call into the interpreter and free USM allocations [gh-2359](https://github.com/IntelPython/dpctl/pull/2359)
* `import_dpctl()` now returns 0 on success and -1 with a Python exception set on failure, and `dpctl4pybind11.hpp` raises that exception rather than failing on the first C-API call [gh-2359](https://github.com/IntelPython/dpctl/pull/2359)
* The event returned by `dpctl.SyclQueue.keep_args_alive`, `dpctl::utils::keep_args_alive` and `dpctl.SyclQueue._submit_keep_args_alive` is now for an empty kernel that gates the deferred release rather than for a `host_task` that performs it, so its completion means that the objects are no longer in use rather than that they have been released [gh-2359](https://github.com/IntelPython/dpctl/pull/2359)
* Filter selector strings are implemented in `dpctl` instead of relying on the deprecated DPC++ `sycl_ext_oneapi_filter_selector` extension, and device numbers in a list of filters, such as `"0,1"`, now refer to the same devices as when used in separate filters [gh-2420](https://github.com/IntelPython/dpctl/pull/2420)
* `dpctl.SyclDevice.filter_string` and `dpctl.SyclDevice.get_filter_string` raise `ValueError` for backends and device types not supported in filter selector strings, instead of returning a string containing `"unknown"` [gh-2420](https://github.com/IntelPython/dpctl/pull/2420)

### Deprecated
* Deprecated `dpctl.SyclQueue._submit_keep_args_alive` in favor of `dpctl.SyclQueue.keep_args_alive`, which it now calls and which behaves identically [gh-2359](https://github.com/IntelPython/dpctl/pull/2359)
Expand All @@ -28,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Removed stale `select_host_device` and `has_host_device` names from `dpctl.__all__`, which made `from dpctl import *` fail with `AttributeError` [gh-2410](https://github.com/IntelPython/dpctl/pull/2410)
* A USM allocation that fails now drops the references held for offloaded tasks that have completed, and is attempted once more if that released anything, so that memory only waiting to be given up is not reported as unavailable [gh-2359](https://github.com/IntelPython/dpctl/pull/2359)
* `dpctl.SyclPlatform.get_devices` no longer prints Unified Runtime warnings for `device_type="custom"` on non-OpenCL platforms, where custom devices are not supported [gh-2306](https://github.com/IntelPython/dpctl/pull/2306)
* `DPCTLDeviceSelector_Score` returns correct scores for filter selectors with device numbers [gh-2420](https://github.com/IntelPython/dpctl/pull/2420)

### Maintenance
* Removed the `-fno-sycl-id-queries-fit-in-int` compile option, which none of the `dpctl` extensions need since `dpctl.tensor` moved to `dpnp` [gh-2413](https://github.com/IntelPython/dpctl/pull/2413)
Expand Down
18 changes: 10 additions & 8 deletions docs/doc_sources/api_reference/dpctl/filter_selector_string.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
Filter Selector String
======================

Filter selector string is a way to refer to unpartitioned SYCL devices
proposed in :oneapi_filter_selection:`sycl_ext_oneapi_filter_selector <>`
extension to SYCL standard.

This document captures aspects of the referenced document relevant
to :mod:`dpctl`.
Filter selector string is a way to refer to unpartitioned SYCL devices.
:mod:`dpctl` implements the syntax of the DPC++
:oneapi_filter_selection:`sycl_ext_oneapi_filter_selector <>` extension
without relying on the extension itself.

A filter selector string defines one or more filters, which must be
separated using ``","`` character. A filter is specified as a
Expand All @@ -18,15 +16,18 @@ triple of the form:

Backend:DeviceType:RelativeDeviceNumber

Every element of the triple is optional, but a filter must contain at
least one component.
Every element of the triple is optional and the elements may be given in
any order.

``Backend`` specifies the desired backend of targeted devices, while
``DeviceType`` specifies the type of targeted devices.
``RelativeDeviceNumber`` refers to the number of the device that matches
any other given requirements, starting from 0 to marking the
"first device that matches the requirements".

If several devices match, the one with the highest default selector
score is selected.

Attempting to use a non-conforming string in places where filter selector
string is expected will raise an exception.

Expand All @@ -45,6 +46,7 @@ Supported values for ``DeviceType`` are:

* - accelerator
- cpu
- custom
- gpu

Filter selector strings can be used as arguments to constructors of
Expand Down
103 changes: 61 additions & 42 deletions dpctl/_sycl_device.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ cdef tuple _to_enum_tuple(


cdef str _backend_type_to_filter_string_part(_backend_type BTy):
""" Returns the filter string part for the backend, or ``None``."""
if BTy == _backend_type._CUDA:
return "cuda"
elif BTy == _backend_type._HIP:
Expand All @@ -248,20 +249,57 @@ cdef str _backend_type_to_filter_string_part(_backend_type BTy):
elif BTy == _backend_type._OPENCL:
return "opencl"
else:
return "unknown"
return None


cdef str _device_type_to_filter_string_part(_device_type DTy):
""" Returns the filter string part for the device type, or ``None``."""
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._CUSTOM:
return "custom"
elif DTy == _device_type._GPU:
return "gpu"
else:
return "unknown"
return None


cdef str _make_filter_string(
DPCTLSyclDeviceRef DRef,
bint include_backend,
bint include_device_type,
int64_t relId,
):
""" Joins the requested parts of the filter string of a root device.

Raises ``ValueError`` if the backend or device type has no filter
string representation.
"""
cdef list parts = []
if include_backend:
be_str = _backend_type_to_filter_string_part(
DPCTLDevice_GetBackend(DRef)
)
if be_str is None:
raise ValueError(
"The backend of this SyclDevice is not supported in filter "
"strings"
)
parts.append(be_str)
if include_device_type:
dt_str = _device_type_to_filter_string_part(
DPCTLDevice_GetDeviceType(DRef)
)
if dt_str is None:
raise ValueError(
"The device type of this SyclDevice is not supported in "
"filter strings"
)
parts.append(dt_str)
parts.append(str(relId))
return ":".join(parts)


cdef void _init_helper(_SyclDevice device, DPCTLSyclDeviceRef DRef) except *:
Expand Down Expand Up @@ -317,22 +355,17 @@ cdef inline void _raise_invalid_peer_access(
]
cdef _backend_type BTy1 = DPCTLDevice_GetBackend(dev._device_ref)
cdef _backend_type BTy2 = DPCTLDevice_GetBackend(peer.get_device_ref())
be1 = _backend_type_to_filter_string_part(BTy1) or "unknown"
be2 = _backend_type_to_filter_string_part(BTy2) or "unknown"
if (BTy1 != BTy2):
raise ValueError(
f"Device with backend {_backend_type_to_filter_string_part(BTy1)} "
"cannot peer access device with backend "
f"{_backend_type_to_filter_string_part(BTy2)}"
f"Device with backend {be1} "
f"cannot peer access device with backend {be2}"
)
if (BTy1 not in _peer_access_backends):
raise ValueError(
"Peer access not supported for backend "
f"{_backend_type_to_filter_string_part(BTy1)}"
)
raise ValueError(f"Peer access not supported for backend {be1}")
if (BTy2 not in _peer_access_backends):
raise ValueError(
"Peer access not supported for backend "
f"{_backend_type_to_filter_string_part(BTy2)}"
)
raise ValueError(f"Peer access not supported for backend {be2}")
if (dev == peer):
raise ValueError(
"Peer access cannot be enabled between a device and itself"
Expand All @@ -355,20 +388,15 @@ def _cached_filter_string(d : SyclDevice):
if the device is a root (unpartitioned) device.

Raises:
ValueError: if the input device is a sub-device.
ValueError: if the input device is a sub-device, or its backend or
device type is not supported in filter strings.
"""
cdef _backend_type BTy
cdef _device_type DTy
cdef int64_t relId = -1
cdef SyclDevice cd = <SyclDevice> d
relId = DPCTLDeviceMgr_GetRelativeId(cd._device_ref)
if (relId == -1):
raise ValueError("This SyclDevice is not a root device")
BTy = DPCTLDevice_GetBackend(cd._device_ref)
br_str = _backend_type_to_filter_string_part(BTy)
DTy = DPCTLDevice_GetDeviceType(cd._device_ref)
dt_str = _device_type_to_filter_string_part(DTy)
return ":".join((br_str, dt_str, str(relId)))
return _make_filter_string(cd._device_ref, True, True, relId)


cdef class SyclDevice(_SyclDevice):
Expand All @@ -379,7 +407,7 @@ cdef class SyclDevice(_SyclDevice):

- by directly passing in a filter string to the class
constructor. The filter string needs to conform to the
:oneapi_filter_selection:`DPC++ filter selector SYCL extension <>`.
:ref:`filter selector string <filter_selector_string>` syntax.

:Example:

Expand Down Expand Up @@ -2640,6 +2668,9 @@ cdef class SyclDevice(_SyclDevice):
ValueError:
If the device is a sub-device.

If the backend or device type of the device is not
supported in filter strings.

:Example:
.. code-block:: python

Expand Down Expand Up @@ -2746,6 +2777,9 @@ cdef class SyclDevice(_SyclDevice):
If no match for the device was found in the vector
returned by ``sycl::device::get_devices()``

If the requested backend or device type of the device is
not supported in filter strings.

:Example:
.. code-block:: python

Expand All @@ -2760,8 +2794,6 @@ cdef class SyclDevice(_SyclDevice):
"""
cdef int relId = -1
cdef DPCTLSyclDeviceRef pDRef = NULL
cdef _device_type DTy
cdef _backend_type BTy

if include_backend:
if include_device_type:
Expand All @@ -2783,22 +2815,9 @@ cdef class SyclDevice(_SyclDevice):
DPCTLDevice_Delete(pDRef)
raise ValueError("This SyclDevice is not a root device")
else:
if include_backend:
BTy = DPCTLDevice_GetBackend(self._device_ref)
be_str = _backend_type_to_filter_string_part(BTy)
if include_device_type:
DTy = DPCTLDevice_GetDeviceType(self._device_ref)
dt_str = _device_type_to_filter_string_part(DTy)
return ":".join((be_str, dt_str, str(relId)))
else:
return ":".join((be_str, str(relId)))
else:
if include_device_type:
DTy = DPCTLDevice_GetDeviceType(self._device_ref)
dt_str = _device_type_to_filter_string_part(DTy)
return ":".join((dt_str, str(relId)))
else:
return str(relId)
return _make_filter_string(
self._device_ref, include_backend, include_device_type, relId
)

def get_unpartitioned_parent_device(self):
""" get_unpartitioned_parent_device()
Expand Down
6 changes: 6 additions & 0 deletions dpctl/tests/_device_attributes_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
"opencl:gpu:-1",
"cuda:cpu:0",
"abc",
"OPENCL",
"opencl:gpu:cpu",
"opencl:level_zero",
"0:1",
"opencl:gpu:0:0",
"",
1,
]

Expand Down
2 changes: 1 addition & 1 deletion libsyclinterface/helper/include/dpctl_utils_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ int64_t DPCTL_GetRelativeDeviceId(const sycl::device &Device);

/*!
* @brief Gives the filter string which would select given root device if
* used as argument to ``sycl::ext::oneapi::filter_selector``. Throws exception
* used as argument to ``DPCTLFilterSelector_Create``. Throws exception
* if filter string can not be constructed.
*
* @param Device A ``sycl::device`` object whose filter selector
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
#pragma once

#include "Support/DllExport.h"
#include <optional>
#include <string>
#include <sycl/sycl.hpp>
#include <vector>

namespace dpctl
{
Expand Down Expand Up @@ -71,14 +74,31 @@ class DPCTL_API dpctl_cpu_selector : public dpctl_device_selector
int operator()(const sycl::device &d) const override;
};

/*!
* @brief Selects devices matching a filter selector string.
*
* The string is a comma-separated list of filters, each of the form
* ``backend:device_type:device_num`` with every component optional and in
* any order. ``device_num`` counts devices from ``sycl::device::get_devices()``
* that match the filter's backend and device type. Matching devices are
* scored by ``sycl::default_selector_v``.
*
* Throws ``std::invalid_argument`` if the string is malformed.
*/
class DPCTL_API dpctl_filter_selector : public dpctl_device_selector
{
public:
dpctl_filter_selector(const std::string &fs) : _impl(fs) {}
explicit dpctl_filter_selector(const std::string &fs);
int operator()(const sycl::device &d) const override;

private:
sycl::ext::oneapi::filter_selector _impl;
struct filter
{
std::optional<sycl::backend> backend;
std::optional<sycl::info::device_type> device_type;
std::optional<sycl::device> device;
};
std::vector<filter> _filters;
};

} // namespace syclinterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ DPCTL_API
__dpctl_give DPCTLSyclDeviceSelectorRef DPCTLCPUSelector_Create(void);

/*!
* @brief Returns an opaque wrapper for sycl::ext::oneapi::filter_selector
* object based on the passed in filter string.
* @brief Returns a device selector for the passed in filter string.
*
* @param filter_str A C string providing a filter based on which to
* create a device selector.
* @return An opaque pointer to a sycl::ext::oneapi::filter_selector object.
* @return An opaque pointer to a device selector, or nullptr if the
* filter string is malformed.
* @ingroup DeviceSelectors
*/
DPCTL_API
Expand Down
Loading
Loading