Skip to content

Commit 67317b0

Browse files
authored
Merge pull request #1993 from IntelPython/support-composite-devices
Support for composite devices
2 parents 579d2f8 + c23cbcb commit 67317b0

22 files changed

+501
-8
lines changed

docs/doc_sources/api_reference/dpctl/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
has_gpu_devices
6262
has_cpu_devices
6363
has_accelerator_devices
64+
get_composite_devices
6465

6566
.. rubric:: Enums
6667

dpctl/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
SyclSubDeviceCreationError,
3636
)
3737
from ._sycl_device_factory import (
38+
get_composite_devices,
3839
get_devices,
3940
get_num_devices,
4041
has_accelerator_devices,
@@ -87,6 +88,7 @@
8788
"has_gpu_devices",
8889
"has_accelerator_devices",
8990
"has_host_device",
91+
"get_composite_devices",
9092
]
9193
__all__ += [
9294
"SyclEvent",

dpctl/_backend.pxd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ cdef extern from "syclinterface/dpctl_sycl_enum_types.h":
9898
_usm_atomic_shared_allocations 'usm_atomic_shared_allocations',
9999
_host_debuggable 'host_debuggable',
100100
_emulated 'emulated',
101+
_is_component 'is_component',
102+
_is_composite 'is_composite',
101103

102104
ctypedef enum _partition_affinity_domain_type 'DPCTLPartitionAffinityDomainType':
103105
_not_applicable 'not_applicable',
@@ -217,6 +219,8 @@ cdef extern from "syclinterface/dpctl_sycl_device_interface.h":
217219
cdef uint32_t DPCTLDevice_GetPartitionMaxSubDevices(const DPCTLSyclDeviceRef DRef)
218220
cdef uint32_t DPCTLDevice_GetMaxClockFrequency(const DPCTLSyclDeviceRef DRef)
219221
cdef uint64_t DPCTLDevice_GetMaxMemAllocSize(const DPCTLSyclDeviceRef DRef)
222+
cdef DPCTLSyclDeviceRef DPCTLDevice_GetCompositeDevice(const DPCTLSyclDeviceRef DRef)
223+
cdef DPCTLDeviceVectorRef DPCTLDevice_GetComponentDevices(const DPCTLSyclDeviceRef DRef)
220224

221225

222226
cdef extern from "syclinterface/dpctl_sycl_device_manager.h":
@@ -238,6 +242,7 @@ cdef extern from "syclinterface/dpctl_sycl_device_manager.h":
238242
cdef DPCTLSyclContextRef DPCTLDeviceMgr_GetCachedContext(
239243
const DPCTLSyclDeviceRef DRef)
240244
cdef int64_t DPCTLDeviceMgr_GetRelativeId(const DPCTLSyclDeviceRef DRef)
245+
cdef DPCTLDeviceVectorRef DPCTLDeviceMgr_GetCompositeDevices()
241246

242247

243248
cdef extern from "syclinterface/dpctl_sycl_device_selector_interface.h":
@@ -316,6 +321,8 @@ cdef extern from "syclinterface/dpctl_sycl_platform_interface.h":
316321
const DPCTLSyclPlatformRef)
317322
cdef DPCTLDeviceVectorRef DPCTLPlatform_GetDevices(
318323
const DPCTLSyclPlatformRef PRef, _device_type DTy)
324+
cdef DPCTLDeviceVectorRef DPCTLPlatform_GetCompositeDevices(
325+
const DPCTLSyclPlatformRef PRef)
319326

320327

321328
cdef extern from "syclinterface/dpctl_sycl_context_interface.h":

dpctl/_sycl_device.pyx

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ from ._backend cimport ( # noqa: E211
3232
DPCTLDevice_CreateSubDevicesEqually,
3333
DPCTLDevice_Delete,
3434
DPCTLDevice_GetBackend,
35+
DPCTLDevice_GetComponentDevices,
36+
DPCTLDevice_GetCompositeDevice,
3537
DPCTLDevice_GetDeviceType,
3638
DPCTLDevice_GetDriverVersion,
3739
DPCTLDevice_GetGlobalMemCacheLineSize,
@@ -795,6 +797,32 @@ cdef class SyclDevice(_SyclDevice):
795797
cdef _aspect_type AT = _aspect_type._emulated
796798
return DPCTLDevice_HasAspect(self._device_ref, AT)
797799

800+
@property
801+
def has_aspect_is_component(self):
802+
""" Returns ``True`` if this device is a component device, ``False``
803+
otherwise. A device with this aspect will have a composite device
804+
from which it is descended.
805+
806+
Returns:
807+
bool:
808+
Indicates if device is a component device.
809+
"""
810+
cdef _aspect_type AT = _aspect_type._is_component
811+
return DPCTLDevice_HasAspect(self._device_ref, AT)
812+
813+
814+
@property
815+
def has_aspect_is_composite(self):
816+
""" Returns ``True`` if this device is a composite device, ``False``
817+
otherwise. A device with this aspect contains component devices.
818+
819+
Returns:
820+
bool:
821+
Indicates if device is a composite device.
822+
"""
823+
cdef _aspect_type AT = _aspect_type._is_composite
824+
return DPCTLDevice_HasAspect(self._device_ref, AT)
825+
798826
@property
799827
def image_2d_max_width(self):
800828
""" Returns the maximum width of a 2D image or 1D image in pixels.
@@ -1520,7 +1548,7 @@ cdef class SyclDevice(_SyclDevice):
15201548
Created sub-devices.
15211549
15221550
Raises:
1523-
dpctl.SyclSubdeviceCreationError:
1551+
dpctl.SyclSubDeviceCreationError:
15241552
if sub-devices can not be created.
15251553
"""
15261554
cdef DPCTLDeviceVectorRef DVRef = NULL
@@ -1546,7 +1574,7 @@ cdef class SyclDevice(_SyclDevice):
15461574
Created sub-devices.
15471575
15481576
Raises:
1549-
dpctl.SyclSubdeviceCreationError:
1577+
dpctl.SyclSubDeviceCreationError:
15501578
if sub-devices can not be created.
15511579
"""
15521580
cdef int ncounts = len(counts)
@@ -1592,7 +1620,7 @@ cdef class SyclDevice(_SyclDevice):
15921620
Created sub-devices.
15931621
15941622
Raises:
1595-
dpctl.SyclSubdeviceCreationError:
1623+
dpctl.SyclSubDeviceCreationError:
15961624
if sub-devices can not be created.
15971625
"""
15981626
cdef DPCTLDeviceVectorRef DVRef = NULL
@@ -1662,7 +1690,7 @@ cdef class SyclDevice(_SyclDevice):
16621690
If the ``partition`` keyword argument is not specified or
16631691
the affinity domain string is not legal or is not one of the
16641692
three supported options.
1665-
dpctl.SyclSubdeviceCreationError:
1693+
dpctl.SyclSubDeviceCreationError:
16661694
If sub-devices can not be created.
16671695
"""
16681696
if "partition" not in kwargs:
@@ -1728,6 +1756,43 @@ cdef class SyclDevice(_SyclDevice):
17281756
return None
17291757
return SyclDevice._create(pDRef)
17301758

1759+
@property
1760+
def composite_device(self):
1761+
""" The composite device for a component device, or ``None`` for a
1762+
non-component device.
1763+
1764+
Returns:
1765+
dpctl.SyclDevice:
1766+
The composite :class:`dpctl.SyclDevice` instance for a
1767+
component device, or ``None`` for a non-component device.
1768+
"""
1769+
cdef DPCTLSyclDeviceRef CDRef = NULL
1770+
CDRef = DPCTLDevice_GetCompositeDevice(self._device_ref)
1771+
if (CDRef is NULL):
1772+
return None
1773+
return SyclDevice._create(CDRef)
1774+
1775+
def component_devices(self):
1776+
""" Returns a list of component devices contained in this SYCL device.
1777+
1778+
The returned list will be empty if this SYCL device is not a composite
1779+
device, i.e., if `is_composite` is ``False``.
1780+
1781+
Returns:
1782+
List[:class:`dpctl.SyclDevice`]:
1783+
List of component devices.
1784+
1785+
Raises:
1786+
ValueError:
1787+
If the ``DPCTLDevice_GetComponentDevices`` call returned
1788+
``NULL`` instead of a ``DPCTLDeviceVectorRef`` object.
1789+
"""
1790+
cdef DPCTLDeviceVectorRef cDVRef = NULL
1791+
cDVRef = DPCTLDevice_GetComponentDevices(self._device_ref)
1792+
if cDVRef is NULL:
1793+
raise ValueError("Internal error: NULL device vector encountered")
1794+
return _get_devices(cDVRef)
1795+
17311796
@property
17321797
def profiling_timer_resolution(self):
17331798
""" Profiling timer resolution.

dpctl/_sycl_device_factory.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ cpdef SyclDevice select_cpu_device()
3232
cpdef SyclDevice select_default_device()
3333
cpdef SyclDevice select_gpu_device()
3434
cpdef list get_devices(backend=*, device_type=*)
35+
cpdef list get_composite_devices()
3536
cpdef int get_num_devices(backend=*, device_type=*)
3637
cpdef cpp_bool has_gpu_devices()
3738
cpdef cpp_bool has_cpu_devices()

dpctl/_sycl_device_factory.pyx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ from ._backend cimport ( # noqa: E211
3131
DPCTLCPUSelector_Create,
3232
DPCTLDefaultSelector_Create,
3333
DPCTLDevice_CreateFromSelector,
34+
DPCTLDeviceMgr_GetCompositeDevices,
3435
DPCTLDeviceMgr_GetDevices,
3536
DPCTLDeviceMgr_GetNumDevices,
3637
DPCTLDeviceSelector_Delete,
@@ -62,6 +63,7 @@ __all__ = [
6263
"has_gpu_devices",
6364
"has_accelerator_devices",
6465
"_cached_default_device",
66+
"get_composite_devices",
6567
]
6668

6769

@@ -202,6 +204,32 @@ cpdef list get_devices(backend=backend_type.all, device_type=device_type_t.all):
202204
return devices
203205

204206

207+
cpdef list get_composite_devices():
208+
"""
209+
Returns a list of the available composite :class:`dpctl.SyclDevice`
210+
instances.
211+
212+
Only available when `ZE_FLAT_DEVICE_HIERARCHY=COMBINED` is set in
213+
the environment, and only for specific Level Zero devices
214+
(i.e., those which expose multiple tiles as root devices).
215+
216+
For more information, see:
217+
https://github.com/intel/llvm/blob/sycl/sycl/doc/extensions/experimental/sycl_ext_oneapi_composite_device.asciidoc
218+
219+
Returns:
220+
list:
221+
A list of available composite :class:`dpctl.SyclDevice` instances.
222+
"""
223+
cdef DPCTLDeviceVectorRef DVRef = NULL
224+
cdef list composite_devices
225+
226+
DVRef = DPCTLDeviceMgr_GetCompositeDevices()
227+
composite_devices = _get_devices(DVRef)
228+
DPCTLDeviceVector_Delete(DVRef)
229+
230+
return composite_devices
231+
232+
205233
cpdef int get_num_devices(
206234
backend=backend_type.all, device_type=device_type_t.all
207235
):

dpctl/_sycl_platform.pyx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ from ._backend cimport ( # noqa: E211
3737
DPCTLPlatform_CreateFromSelector,
3838
DPCTLPlatform_Delete,
3939
DPCTLPlatform_GetBackend,
40+
DPCTLPlatform_GetCompositeDevices,
4041
DPCTLPlatform_GetDefaultContext,
4142
DPCTLPlatform_GetDevices,
4243
DPCTLPlatform_GetName,
@@ -448,6 +449,38 @@ cdef class SyclPlatform(_SyclPlatform):
448449

449450
return devices
450451

452+
def get_composite_devices(self):
453+
"""
454+
Returns the list of composite :class:`dpctl.SyclDevice` objects
455+
associated with :class:`dpctl.SyclPlatform` instance.
456+
457+
Returns:
458+
list:
459+
A :obj:`list` of composite :class:`dpctl.SyclDevice` objects
460+
that belong to this platform.
461+
462+
Raises:
463+
ValueError:
464+
If the ``DPCTLPlatform_GetCompositeDevices`` call returned
465+
``NULL`` instead of a ``DPCTLDeviceVectorRef`` object.
466+
"""
467+
cdef DPCTLDeviceVectorRef DVRef = NULL
468+
cdef size_t num_devs
469+
cdef size_t i
470+
cdef DPCTLSyclDeviceRef DRef
471+
472+
DVRef = DPCTLPlatform_GetCompositeDevices(self.get_platform_ref())
473+
if (DVRef is NULL):
474+
raise ValueError("Internal error: NULL device vector encountered")
475+
num_devs = DPCTLDeviceVector_Size(DVRef)
476+
composite_devices = []
477+
for i in range(num_devs):
478+
DRef = DPCTLDeviceVector_GetAt(DVRef, i)
479+
composite_devices.append(SyclDevice._create(DRef))
480+
DPCTLDeviceVector_Delete(DVRef)
481+
482+
return composite_devices
483+
451484

452485
def lsplatform(verbosity=0):
453486
"""

dpctl/tests/test_sycl_device.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ def test_equal():
165165
"usm_atomic_host_allocations",
166166
"usm_atomic_shared_allocations",
167167
"emulated",
168+
"is_component",
169+
"is_composite",
168170
]
169171

170172
# SYCL 2020 spec aspects not presently
@@ -310,3 +312,32 @@ def test_get_unpartitioned_parent_device_from_sub_device():
310312
pytest.skip("Default device can not be partitioned")
311313
assert isinstance(sdevs, list) and len(sdevs) > 0
312314
assert dev == sdevs[0].get_unpartitioned_parent_device()
315+
316+
317+
def test_composite_device_method():
318+
"""
319+
Test that the composite_device method returns a composite
320+
device found in ``dpctl.get_composite_devices()``
321+
"""
322+
devices = dpctl.get_devices()
323+
composite_devices = dpctl.get_composite_devices()
324+
for d in devices:
325+
if d.has_aspect_is_component:
326+
Cd = d.composite_device
327+
assert Cd in composite_devices
328+
329+
330+
def test_get_component_devices_from_composite():
331+
"""
332+
Test that the component_devices method returns component
333+
root devices.
334+
"""
335+
devices = dpctl.get_devices()
336+
composite_devices = dpctl.get_composite_devices()
337+
for Cd in composite_devices:
338+
assert Cd.has_aspect_is_composite
339+
component_devices = Cd.component_devices()
340+
for d in component_devices:
341+
assert d.has_aspect_is_component
342+
# component devices are root devices
343+
assert d in devices

dpctl/tests/test_sycl_device_factory.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,13 @@ def test_get_devices_with_device_type_str(device_type_str):
185185
assert dev == devices[i]
186186
else:
187187
pytest.skip()
188+
189+
190+
def test_get_composite_devices():
191+
devices = dpctl.get_composite_devices()
192+
if devices:
193+
num_devices = len(devices)
194+
for i in range(num_devices):
195+
assert devices[i].has_aspect_is_composite
196+
else:
197+
pytest.skip()

dpctl/tests/test_sycl_platform.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,3 +259,20 @@ def test_platform_get_devices_enum_device_type():
259259
devices = p.get_devices(device_type=dty)
260260
if len(devices):
261261
assert (d.device_type == dty for d in devices)
262+
263+
264+
def test_platform_get_composite_devices():
265+
platforms = dpctl.get_platforms()
266+
if platforms:
267+
for p in platforms:
268+
composite_devices = p.get_composite_devices()
269+
if not composite_devices:
270+
pass
271+
devices = p.get_devices()
272+
for Cd in composite_devices:
273+
assert Cd.has_aspect_is_composite
274+
component_devices = Cd.component_devices()
275+
# all component devices are root devices
276+
assert all(d in devices for d in component_devices)
277+
else:
278+
pytest.skip("No platforms available")

0 commit comments

Comments
 (0)