@@ -25,12 +25,15 @@ from ._backend cimport ( # noqa: E211
2525 DPCTLCString_Delete,
2626 DPCTLDefaultSelector_Create,
2727 DPCTLDevice_AreEq,
28+ DPCTLDevice_CanAccessPeer,
2829 DPCTLDevice_Copy,
2930 DPCTLDevice_CreateFromSelector,
3031 DPCTLDevice_CreateSubDevicesByAffinity,
3132 DPCTLDevice_CreateSubDevicesByCounts,
3233 DPCTLDevice_CreateSubDevicesEqually,
3334 DPCTLDevice_Delete,
35+ DPCTLDevice_DisablePeerAccess,
36+ DPCTLDevice_EnablePeerAccess,
3437 DPCTLDevice_GetBackend,
3538 DPCTLDevice_GetComponentDevices,
3639 DPCTLDevice_GetCompositeDevice,
@@ -103,6 +106,7 @@ from ._backend cimport ( # noqa: E211
103106 _device_type,
104107 _global_mem_cache_type,
105108 _partition_affinity_domain_type,
109+ _peer_access,
106110)
107111
108112from .enum_types import backend_type, device_type, global_mem_cache_type
@@ -213,14 +217,73 @@ cdef void _init_helper(_SyclDevice device, DPCTLSyclDeviceRef DRef) except *:
213217 raise RuntimeError (" Descriptor 'max_work_item_sizes3d' not available" )
214218
215219
220+ cdef inline bint _check_peer_access(SyclDevice dev, SyclDevice peer) except * :
221+ """
222+ Check peer access ahead of time to avoid errors from unified runtime or
223+ compiler implementation.
224+ """
225+ cdef list _peer_access_backends = [
226+ _backend_type._CUDA,
227+ _backend_type._HIP,
228+ _backend_type._LEVEL_ZERO
229+ ]
230+ cdef _backend_type BTy1 = DPCTLDevice_GetBackend(dev._device_ref)
231+ cdef _backend_type BTy2 = DPCTLDevice_GetBackend(peer.get_device_ref())
232+ if (
233+ BTy1 == BTy2 and
234+ BTy1 in _peer_access_backends and
235+ BTy2 in _peer_access_backends and
236+ dev != peer
237+ ):
238+ return True
239+ return False
240+
241+
242+ cdef inline void _raise_invalid_peer_access(
243+ SyclDevice dev,
244+ SyclDevice peer,
245+ ) except * :
246+ """
247+ Check peer access ahead of time and raise errors for invalid cases.
248+ """
249+ cdef list _peer_access_backends = [
250+ _backend_type._CUDA,
251+ _backend_type._HIP,
252+ _backend_type._LEVEL_ZERO
253+ ]
254+ cdef _backend_type BTy1 = DPCTLDevice_GetBackend(dev._device_ref)
255+ cdef _backend_type BTy2 = DPCTLDevice_GetBackend(peer.get_device_ref())
256+ if (BTy1 != BTy2):
257+ raise ValueError (
258+ f" Device with backend {_backend_type_to_filter_string_part(BTy1)} "
259+ " cannot peer access device with backend "
260+ f" {_backend_type_to_filter_string_part(BTy2)}"
261+ )
262+ if (BTy1 not in _peer_access_backends):
263+ raise ValueError (
264+ " Peer access not supported for backend "
265+ f" {_backend_type_to_filter_string_part(BTy1)}"
266+ )
267+ if (BTy2 not in _peer_access_backends):
268+ raise ValueError (
269+ " Peer access not supported for backend "
270+ f" {_backend_type_to_filter_string_part(BTy2)}"
271+ )
272+ if (dev == peer):
273+ raise ValueError (
274+ " Peer access cannot be enabled between a device and itself"
275+ )
276+ return
277+
278+
216279@ functools.lru_cache (maxsize = None )
217280def _cached_filter_string (d : SyclDevice ):
218281 """
219282 Internal utility to compute filter_string of input SyclDevice
220283 and cached with `functools.cache`.
221284
222285 Args:
223- d (dpctl.SyclDevice):
286+ d (:class:` dpctl.SyclDevice` ):
224287 A device for which to compute the filter string.
225288 Returns:
226289 out(str):
@@ -1792,6 +1855,150 @@ cdef class SyclDevice(_SyclDevice):
17921855 raise ValueError (" Internal error: NULL device vector encountered" )
17931856 return _get_devices(cDVRef)
17941857
1858+ def can_access_peer (self , peer , value = " access_supported" ):
1859+ """ Returns ``True`` if this device (``self``) can enable peer access
1860+ to USM device memory on ``peer``, ``False`` otherwise.
1861+
1862+ If peer access is supported, it may be enabled by calling
1863+ :meth:`.enable_peer_access`.
1864+
1865+ For details, see
1866+ :oneapi_peer_access:`DPC++ peer access SYCL extension <>`.
1867+
1868+ Args:
1869+ peer (:class:`dpctl.SyclDevice`):
1870+ The :class:`dpctl.SyclDevice` instance to check for peer access
1871+ by this device.
1872+ value (str, optional):
1873+ Specifies the kind of peer access being queried.
1874+
1875+ The supported values are
1876+
1877+ - ``"access_supported"``
1878+ Returns ``True`` if it is possible for this device to
1879+ enable peer access to USM device memory on ``peer``.
1880+
1881+ - ``"atomics_supported"``
1882+ Returns ``True`` if it is possible for this device to
1883+ concurrently access and atomically modify USM device
1884+ memory on ``peer`` when enabled. Atomics must have
1885+ ``memory_scope::system`` when modifying memory on a peer
1886+ device.
1887+
1888+ If ``False`` is returned, these operations result in
1889+ undefined behavior.
1890+
1891+ Default: ``"access_supported"``
1892+
1893+ Returns:
1894+ bool:
1895+ ``True`` if the kind of peer access specified by ``value`` is
1896+ supported between this device and ``peer``, otherwise ``False``.
1897+
1898+ Raises:
1899+ TypeError:
1900+ If ``peer`` is not :class:`dpctl.SyclDevice`.
1901+ """
1902+ cdef SyclDevice p_dev
1903+
1904+ if not isinstance (value, str ):
1905+ raise TypeError (
1906+ f" Expected `value` to be of type str, got {type(value)}"
1907+ )
1908+ if value == " access_supported" :
1909+ access_type = _peer_access._access_supported
1910+ elif value == " atomics_supported" :
1911+ access_type = _peer_access._atomics_supported
1912+ else :
1913+ raise ValueError (
1914+ " `value` must be 'access_supported' or 'atomics_supported', "
1915+ f" got {value}"
1916+ )
1917+ if not isinstance (peer, SyclDevice):
1918+ raise TypeError (
1919+ " peer device must be a `dpctl.SyclDevice`, got "
1920+ f" {type(peer)}"
1921+ )
1922+ p_dev = < SyclDevice> peer
1923+ if _check_peer_access(self , p_dev):
1924+ return DPCTLDevice_CanAccessPeer(
1925+ self ._device_ref,
1926+ p_dev.get_device_ref(),
1927+ access_type
1928+ )
1929+ return False
1930+
1931+ def enable_peer_access (self , peer ):
1932+ """ Enables this device (``self``) to access USM device allocations
1933+ located on ``peer``.
1934+
1935+ Peer access may be disabled by calling :meth:`.disable_peer_access`.
1936+
1937+ For details, see
1938+ :oneapi_peer_access:`DPC++ peer access SYCL extension <>`.
1939+
1940+ Args:
1941+ peer (:class:`dpctl.SyclDevice`):
1942+ The :class:`dpctl.SyclDevice` instance to enable peer access
1943+ to.
1944+
1945+ Raises:
1946+ TypeError:
1947+ If ``peer`` is not :class:`dpctl.SyclDevice`.
1948+ ValueError:
1949+ If the backend associated with this device or ``peer`` does not
1950+ support peer access.
1951+ """
1952+ cdef SyclDevice p_dev
1953+
1954+ if not isinstance (peer, SyclDevice):
1955+ raise TypeError (
1956+ " peer device must be a `dpctl.SyclDevice`, got "
1957+ f" {type(peer)}"
1958+ )
1959+ p_dev = < SyclDevice> peer
1960+ _raise_invalid_peer_access(self , p_dev)
1961+ DPCTLDevice_EnablePeerAccess(
1962+ self ._device_ref,
1963+ p_dev.get_device_ref()
1964+ )
1965+ return
1966+
1967+ def disable_peer_access (self , peer ):
1968+ """ Disables peer access to ``peer`` from this device (``self``).
1969+
1970+ Peer access may be enabled by calling :meth:`.enable_peer_access`.
1971+
1972+ For details, see
1973+ :oneapi_peer_access:`DPC++ peer access SYCL extension <>`.
1974+
1975+ Args:
1976+ peer (:class:`dpctl.SyclDevice`):
1977+ The :class:`dpctl.SyclDevice` instance to
1978+ disable peer access to.
1979+
1980+ Raises:
1981+ TypeError:
1982+ If ``peer`` is not :class:`dpctl.SyclDevice`.
1983+ ValueError:
1984+ If the backend associated with this device or ``peer`` does not
1985+ support peer access.
1986+ """
1987+ cdef SyclDevice p_dev
1988+
1989+ if not isinstance (peer, SyclDevice):
1990+ raise TypeError (
1991+ " peer device must be a `dpctl.SyclDevice`, got "
1992+ f" {type(peer)}"
1993+ )
1994+ p_dev = < SyclDevice> peer
1995+ _raise_invalid_peer_access(self , p_dev)
1996+ DPCTLDevice_DisablePeerAccess(
1997+ self ._device_ref,
1998+ p_dev.get_device_ref()
1999+ )
2000+ return
2001+
17952002 @property
17962003 def profiling_timer_resolution (self ):
17972004 """ Profiling timer resolution.
@@ -1912,7 +2119,7 @@ cdef class SyclDevice(_SyclDevice):
19122119 same _device_ref as this SyclDevice.
19132120
19142121 Args:
1915- other (dpctl.SyclDevice):
2122+ other (:class:` dpctl.SyclDevice` ):
19162123 A :class:`dpctl.SyclDevice` instance to
19172124 compare against.
19182125
0 commit comments