• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IntelPython / dpctl / 16270219306

14 Jul 2025 02:53PM UTC coverage: 85.89%. Remained the same
16270219306

Pull #2123

github

web-flow
Merge 4947f5cfd into e2789db9a
Pull Request #2123: Allow type casting of zero-sized array to any dtype

3227 of 3878 branches covered (83.21%)

Branch coverage included in aggregate %.

3 of 3 new or added lines in 1 file covered. (100.0%)

2 existing lines in 2 files now uncovered.

12235 of 14124 relevant lines covered (86.63%)

6889.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.75
/dpctl/_sycl_device.pyx
1
#                      Data Parallel Control (dpctl)
1✔
2
#
3
# Copyright 2020-2025 Intel Corporation
4
#
5
# Licensed under the Apache License, Version 2.0 (the "License");
6
# you may not use this file except in compliance with the License.
7
# You may obtain a copy of the License at
8
#
9
#    http://www.apache.org/licenses/LICENSE-2.0
10
#
11
# Unless required by applicable law or agreed to in writing, software
12
# distributed under the License is distributed on an "AS IS" BASIS,
13
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
# See the License for the specific language governing permissions and
15
# limitations under the License.
16

17
# distutils: language = c++
18
# cython: language_level=3
19
# cython: linetrace=True
20

21
""" Implements SyclDevice Cython extension type.
22
"""
23

24
from ._backend cimport (  # noqa: E211
25
    DPCTLCString_Delete,
26
    DPCTLDefaultSelector_Create,
27
    DPCTLDevice_AreEq,
28
    DPCTLDevice_CanAccessPeer,
29
    DPCTLDevice_Copy,
30
    DPCTLDevice_CreateFromSelector,
31
    DPCTLDevice_CreateSubDevicesByAffinity,
32
    DPCTLDevice_CreateSubDevicesByCounts,
33
    DPCTLDevice_CreateSubDevicesEqually,
34
    DPCTLDevice_Delete,
35
    DPCTLDevice_DisablePeerAccess,
36
    DPCTLDevice_EnablePeerAccess,
37
    DPCTLDevice_GetBackend,
38
    DPCTLDevice_GetComponentDevices,
39
    DPCTLDevice_GetCompositeDevice,
40
    DPCTLDevice_GetDeviceType,
41
    DPCTLDevice_GetDriverVersion,
42
    DPCTLDevice_GetGlobalMemCacheLineSize,
43
    DPCTLDevice_GetGlobalMemCacheSize,
44
    DPCTLDevice_GetGlobalMemCacheType,
45
    DPCTLDevice_GetGlobalMemSize,
46
    DPCTLDevice_GetImage2dMaxHeight,
47
    DPCTLDevice_GetImage2dMaxWidth,
48
    DPCTLDevice_GetImage3dMaxDepth,
49
    DPCTLDevice_GetImage3dMaxHeight,
50
    DPCTLDevice_GetImage3dMaxWidth,
51
    DPCTLDevice_GetLocalMemSize,
52
    DPCTLDevice_GetMaxClockFrequency,
53
    DPCTLDevice_GetMaxComputeUnits,
54
    DPCTLDevice_GetMaxMemAllocSize,
55
    DPCTLDevice_GetMaxNumSubGroups,
56
    DPCTLDevice_GetMaxReadImageArgs,
57
    DPCTLDevice_GetMaxWorkGroupSize,
58
    DPCTLDevice_GetMaxWorkItemDims,
59
    DPCTLDevice_GetMaxWorkItemSizes1d,
60
    DPCTLDevice_GetMaxWorkItemSizes2d,
61
    DPCTLDevice_GetMaxWorkItemSizes3d,
62
    DPCTLDevice_GetMaxWriteImageArgs,
63
    DPCTLDevice_GetName,
64
    DPCTLDevice_GetNativeVectorWidthChar,
65
    DPCTLDevice_GetNativeVectorWidthDouble,
66
    DPCTLDevice_GetNativeVectorWidthFloat,
67
    DPCTLDevice_GetNativeVectorWidthHalf,
68
    DPCTLDevice_GetNativeVectorWidthInt,
69
    DPCTLDevice_GetNativeVectorWidthLong,
70
    DPCTLDevice_GetNativeVectorWidthShort,
71
    DPCTLDevice_GetParentDevice,
72
    DPCTLDevice_GetPartitionMaxSubDevices,
73
    DPCTLDevice_GetPlatform,
74
    DPCTLDevice_GetPreferredVectorWidthChar,
75
    DPCTLDevice_GetPreferredVectorWidthDouble,
76
    DPCTLDevice_GetPreferredVectorWidthFloat,
77
    DPCTLDevice_GetPreferredVectorWidthHalf,
78
    DPCTLDevice_GetPreferredVectorWidthInt,
79
    DPCTLDevice_GetPreferredVectorWidthLong,
80
    DPCTLDevice_GetPreferredVectorWidthShort,
81
    DPCTLDevice_GetProfilingTimerResolution,
82
    DPCTLDevice_GetSubGroupIndependentForwardProgress,
83
    DPCTLDevice_GetSubGroupSizes,
84
    DPCTLDevice_GetVendor,
85
    DPCTLDevice_HasAspect,
86
    DPCTLDevice_Hash,
87
    DPCTLDevice_IsAccelerator,
88
    DPCTLDevice_IsCPU,
89
    DPCTLDevice_IsGPU,
90
    DPCTLDeviceMgr_GetDeviceInfoStr,
91
    DPCTLDeviceMgr_GetPositionInDevices,
92
    DPCTLDeviceMgr_GetRelativeId,
93
    DPCTLDeviceSelector_Delete,
94
    DPCTLDeviceSelector_Score,
95
    DPCTLDeviceVector_Delete,
96
    DPCTLDeviceVector_GetAt,
97
    DPCTLDeviceVector_Size,
98
    DPCTLDeviceVectorRef,
99
    DPCTLFilterSelector_Create,
100
    DPCTLSize_t_Array_Delete,
101
    DPCTLSyclDeviceRef,
102
    DPCTLSyclDeviceSelectorRef,
103
    DPCTLSyclPlatformRef,
104
    _aspect_type,
105
    _backend_type,
106
    _device_type,
107
    _global_mem_cache_type,
108
    _partition_affinity_domain_type,
109
    _peer_access,
110
)
111

112
from .enum_types import backend_type, device_type, global_mem_cache_type
1✔
113

114
from libc.stdint cimport int64_t, uint32_t, uint64_t
115
from libc.stdlib cimport free, malloc
116

117
from ._sycl_platform cimport SyclPlatform
118

119
import collections
1✔
120
import functools
1✔
121
import warnings
1✔
122

123
__all__ = [
1✔
124
    "SyclDevice", "SyclDeviceCreationError", "SyclSubDeviceCreationError",
125
]
126

127

128
cdef class SyclDeviceCreationError(Exception):
129
    """
130
    A ``SyclDeviceCreationError`` exception is raised when
131
    :class:`.SyclDevice` instance could not created.
132
    """
133
    pass
134

135

136
cdef class SyclSubDeviceCreationError(Exception):
137
    """
138
    A ``SyclSubDeviceCreationError`` exception is raised
139
    by :meth:`.SyclDevice.create_sub_devices` when
140
    :class:`.SyclDevice` instance could not be partitioned
141
    into sub-devices.
142
    """
143
    pass
144

145

146
cdef class _SyclDevice:
147
    """
148
    A helper data-owner class to abstract ``sycl::device``
149
    instance.
150
    """
151

152
    def __dealloc__(self):
153
        DPCTLDevice_Delete(self._device_ref)
1✔
154
        DPCTLCString_Delete(self._name)
1✔
155
        DPCTLCString_Delete(self._vendor)
1✔
156
        DPCTLCString_Delete(self._driver_version)
1✔
157
        DPCTLSize_t_Array_Delete(self._max_work_item_sizes)
1✔
158

159

160
cdef list _get_devices(DPCTLDeviceVectorRef DVRef):
1✔
161
    """
162
    Deletes DVRef. Pass a copy in case an original reference is needed.
163
    """
164
    cdef list devices = []
1✔
165
    cdef size_t nelems = 0
1✔
166
    if DVRef:
1✔
167
        nelems = DPCTLDeviceVector_Size(DVRef)
1✔
168
        for i in range(0, nelems):
1✔
169
            DRef = DPCTLDeviceVector_GetAt(DVRef, i)
1✔
170
            D = SyclDevice._create(DRef)
1✔
171
            devices.append(D)
1✔
172
        DPCTLDeviceVector_Delete(DVRef)
1✔
173

174
    return devices
1✔
175

176

177
cdef str _backend_type_to_filter_string_part(_backend_type BTy):
1✔
178
    if BTy == _backend_type._CUDA:
1✔
179
        return "cuda"
×
180
    elif BTy == _backend_type._HIP:
181
        return "hip"
×
182
    elif BTy == _backend_type._LEVEL_ZERO:
183
        return "level_zero"
×
184
    elif BTy == _backend_type._OPENCL:
185
        return "opencl"
1✔
186
    else:
187
        return "unknown"
×
188

189

190
cdef str _device_type_to_filter_string_part(_device_type DTy):
1✔
191
    if DTy == _device_type._ACCELERATOR:
1✔
192
        return "accelerator"
×
193
    elif DTy == _device_type._AUTOMATIC:
194
        return "automatic"
×
195
    elif DTy == _device_type._CPU:
196
        return "cpu"
1✔
197
    elif DTy == _device_type._GPU:
198
        return "gpu"
×
199
    else:
200
        return "unknown"
×
201

202

203
cdef void _init_helper(_SyclDevice device, DPCTLSyclDeviceRef DRef) except *:
1✔
204
    "Populate attributes of device from opaque device reference DRef"
205
    device._device_ref = DRef
1✔
206
    device._name = DPCTLDevice_GetName(DRef)
1✔
207
    if device._name is NULL:
1✔
208
        raise RuntimeError("Descriptor 'name' not available")
×
209
    device._driver_version = DPCTLDevice_GetDriverVersion(DRef)
1✔
210
    if device._driver_version is NULL:
1✔
211
        raise RuntimeError("Descriptor 'driver_version' not available")
×
212
    device._vendor = DPCTLDevice_GetVendor(DRef)
1✔
213
    if device._vendor is NULL:
1✔
214
        raise RuntimeError("Descriptor 'vendor' not available")
×
215
    device._max_work_item_sizes = DPCTLDevice_GetMaxWorkItemSizes3d(DRef)
1✔
216
    if device._max_work_item_sizes is NULL:
1✔
217
        raise RuntimeError("Descriptor 'max_work_item_sizes3d' not available")
×
218

219

220
cdef inline bint _check_peer_access(SyclDevice dev, SyclDevice peer) except *:
1✔
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(
1✔
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

279
@functools.lru_cache(maxsize=None)
1✔
280
def _cached_filter_string(d : SyclDevice):
281
    """
282
    Internal utility to compute filter_string of input SyclDevice
283
    and cached with `functools.cache`.
284

285
    Args:
286
        d (:class:`dpctl.SyclDevice`):
287
            A device for which to compute the filter string.
288
    Returns:
289
        out(str):
290
            Filter string that can be used to create input device,
291
            if the device is a root (unpartitioned) device.
292

293
    Raises:
294
        ValueError: if the input device is a sub-device.
295
    """
296
    cdef _backend_type BTy
297
    cdef _device_type DTy
298
    cdef int64_t relId = -1
1✔
299
    cdef SyclDevice cd = <SyclDevice> d
1✔
300
    relId = DPCTLDeviceMgr_GetRelativeId(cd._device_ref)
1✔
301
    if (relId == -1):
1✔
302
        raise ValueError("This SyclDevice is not a root device")
×
303
    BTy = DPCTLDevice_GetBackend(cd._device_ref)
1✔
304
    br_str = _backend_type_to_filter_string_part(BTy)
1✔
305
    DTy = DPCTLDevice_GetDeviceType(cd._device_ref)
1✔
306
    dt_str = _device_type_to_filter_string_part(DTy)
1✔
307
    return ":".join((br_str, dt_str, str(relId)))
1✔
308

309

310
cdef class SyclDevice(_SyclDevice):
311
    """ SyclDevice(arg=None)
312
    A Python wrapper for the ``sycl::device`` C++ class.
313

314
    There are two ways of creating a SyclDevice instance:
315

316
    - by directly passing in a filter string to the class
317
      constructor. The filter string needs to conform to the
318
      :oneapi_filter_selection:`DPC++ filter selector SYCL extension <>`.
319

320
    :Example:
321

322
        .. code-block:: python
323

324
            import dpctl
325

326
            # Create a SyclDevice with an explicit filter string,
327
            # in this case the first level_zero gpu device.
328
            level_zero_gpu = dpctl.SyclDevice("level_zero:gpu:0")
329
            level_zero_gpu.print_device_info()
330

331
    - by calling one of the device selector helper functions:
332
      :py:func:`dpctl.select_accelerator_device()`,
333
      :py:func:`dpctl.select_cpu_device()`,
334
      :py:func:`dpctl.select_default_device()`,
335
      :py:func:`dpctl.select_gpu_device()`
336

337
    :Example:
338

339
        .. code-block:: python
340

341
            import dpctl
342

343
            # Create a SyclDevice of type GPU based on whatever is returned
344
            # by the SYCL `gpu_selector` device selector class.
345
            gpu = dpctl.select_gpu_device()
346
            gpu.print_device_info()
347

348
    Args:
349
        arg (str, optional):
350
            The argument can be a selector string, another
351
            :class:`dpctl.SyclDevice`, or ``None``.
352
            Defaults to ``None``.
353

354
    Raises:
355
        MemoryError:
356
            If the constructor could not allocate necessary
357
            temporary memory.
358
        SyclDeviceCreationError:
359
            If the :class:`dpctl.SyclDevice` object creation failed.
360
        TypeError:
361
            If the argument is not a :class:`dpctl.SyclDevice` or string.
362
    """
363
    @staticmethod
1✔
364
    cdef SyclDevice _create(DPCTLSyclDeviceRef dref):
365
        """
366
        This function calls DPCTLDevice_Delete(dref).
367

368
        The user of this function must pass a copy to keep the
369
        dref argument alive.
370
        """
371
        cdef _SyclDevice ret = _SyclDevice.__new__(_SyclDevice)
1✔
372
        # Initialize the attributes of the SyclDevice object
373
        _init_helper(<_SyclDevice> ret, dref)
1✔
374
        # ret is a temporary, and _SyclDevice.__dealloc__ will delete dref
375
        return SyclDevice(ret)
1✔
376

377
    cdef int _init_from__SyclDevice(self, _SyclDevice other):
1✔
378
        self._device_ref = DPCTLDevice_Copy(other._device_ref)
1✔
379
        if (self._device_ref is NULL):
1✔
380
            return -1
×
381
        self._name = DPCTLDevice_GetName(self._device_ref)
1✔
382
        self._driver_version = DPCTLDevice_GetDriverVersion(self._device_ref)
1✔
383
        self._max_work_item_sizes = (
1✔
384
            DPCTLDevice_GetMaxWorkItemSizes3d(self._device_ref)
385
        )
386
        self._vendor = DPCTLDevice_GetVendor(self._device_ref)
1✔
387
        return 0
1✔
388

389
    cdef int _init_from_selector(self, DPCTLSyclDeviceSelectorRef DSRef):
1✔
390
        # Initialize the attributes of the SyclDevice object
391
        cdef DPCTLSyclDeviceRef DRef = DPCTLDevice_CreateFromSelector(DSRef)
1✔
392
        # Free up the device selector
393
        DPCTLDeviceSelector_Delete(DSRef)
1✔
394
        if DRef is NULL:
1✔
395
            return -1
1✔
396
        else:
397
            _init_helper(self, DRef)
1✔
398
            return 0
1✔
399

400
    def __cinit__(self, arg=None):
401
        cdef DPCTLSyclDeviceSelectorRef DSRef = NULL
1✔
402
        cdef const char *filter_c_str = NULL
1✔
403
        cdef int ret = 0
1✔
404

405
        if type(arg) is str:
1✔
406
            string = bytes(<str>arg, "utf-8")
1✔
407
            filter_c_str = string
1✔
408
            DSRef = DPCTLFilterSelector_Create(filter_c_str)
1✔
409
            ret = self._init_from_selector(DSRef)
1✔
410
            if ret == -1:
1✔
411
                raise SyclDeviceCreationError(
1✔
412
                    "Could not create a SyclDevice with the selector string "
413
                    "'{selector_string}'".format(selector_string=arg)
1✔
414
                )
415
        elif isinstance(arg, _SyclDevice):
1✔
416
            ret = self._init_from__SyclDevice(arg)
1✔
417
            if ret == -1:
1✔
418
                raise SyclDeviceCreationError(
×
419
                    "Could not create a SyclDevice from _SyclDevice instance"
420
                )
421
        elif arg is None:
1✔
422
            DSRef = DPCTLDefaultSelector_Create()
1✔
423
            ret = self._init_from_selector(DSRef)
1✔
424
            if ret == -1:
1✔
425
                raise SyclDeviceCreationError(
×
426
                    "Could not create a SyclDevice from default selector"
427
                )
428
        else:
429
            raise TypeError(
1✔
430
                "Invalid argument. Argument should be a str object specifying "
431
                "a SYCL filter selector string or another SyclDevice."
432
            )
433

434
    def print_device_info(self):
1✔
435
        """
436
        Print information about the SYCL device.
437
        """
438
        cdef const char * info_str = DPCTLDeviceMgr_GetDeviceInfoStr(
1✔
439
            self._device_ref
440
        )
441
        py_info = <bytes> info_str
1✔
442
        DPCTLCString_Delete(info_str)
1✔
443
        print(py_info.decode("utf-8"))
1✔
444

445
    cdef DPCTLSyclDeviceRef get_device_ref(self):
1✔
446
        """
447
        Returns the :c:struct:`DPCTLSyclDeviceRef` pointer for this class.
448
        """
449
        return self._device_ref
1✔
450

451
    def addressof_ref(self):
1✔
452
        """
453
        Returns the address of the :c:struct:`DPCTLSyclDeviceRef` pointer as a
454
        ``size_t``.
455

456
        :Example:
457

458
            .. code-block:: python
459

460
                >>> import dpctl
461
                >>> dev = dpctl.select_cpu_device()
462
                >>> hex(dev.addressof_ref())
463
                '0x55b18ec649d0'
464

465
        Returns:
466
            int: The address of the :c:struct:`DPCTLSyclDeviceRef` object used
467
            to create this :class:`dpctl.SyclDevice` cast to a ``size_t``.
468
        """
469
        return <size_t>self._device_ref
1✔
470

471
    @property
472
    def backend(self):
473
        """Returns the ``backend_type`` enum value for this device
474

475
        :Example:
476

477
            .. code-block:: python
478

479
                >>> import dpctl
480
                >>> dev = dpctl.select_cpu_device()
481
                >>> dev.backend
482
                <backend_type.opencl: 4>
483

484
        Returns:
485
            backend_type:
486
                The backend for the device.
487
        """
488
        cdef _backend_type BTy = (
489
            DPCTLDevice_GetBackend(self._device_ref)
1✔
490
        )
491
        if BTy == _backend_type._CUDA:
1✔
492
            return backend_type.cuda
×
493
        elif BTy == _backend_type._HIP:
494
            return backend_type.hip
×
495
        elif BTy == _backend_type._LEVEL_ZERO:
496
            return backend_type.level_zero
×
497
        elif BTy == _backend_type._OPENCL:
498
            return backend_type.opencl
1✔
499
        else:
500
            raise ValueError("Unknown backend type.")
×
501

502
    @property
503
    def device_type(self):
504
        """ Returns the type of the device as a ``device_type`` enum.
505

506
        :Example:
507

508
            .. code-block:: python
509

510
                >>> import dpctl
511
                >>> dev = dpctl.select_cpu_device()
512
                >>> dev.device_type
513
                <device_type.cpu: 4>
514

515
        Returns:
516
            device_type:
517
                The type of device encoded as a ``device_type`` enum.
518

519
        Raises:
520
            ValueError:
521
                If the device type is not recognized.
522
        """
523
        cdef _device_type DTy = (
524
            DPCTLDevice_GetDeviceType(self._device_ref)
1✔
525
        )
526
        if DTy == _device_type._ACCELERATOR:
1✔
527
            return device_type.accelerator
×
528
        elif DTy == _device_type._AUTOMATIC:
529
            return device_type.automatic
×
530
        elif DTy == _device_type._CPU:
531
            return device_type.cpu
1✔
532
        elif DTy == _device_type._GPU:
533
            return device_type.gpu
×
534
        else:
535
            raise ValueError("Unknown device type.")
×
536

537
    @property
538
    def has_aspect_cpu(self):
539
        """ Returns ``True`` if this device is a CPU device,
540
        ``False`` otherwise.
541

542
        :Example:
543

544
            .. code-block:: python
545

546
                >>> import dpctl
547
                >>> dev = dpctl.select_cpu_device()
548
                >>> dev.has_aspect_cpu
549
                True
550

551
        Returns:
552
            bool:
553
                Indicates whether the device is a cpu.
554
        """
555
        cdef _aspect_type AT = _aspect_type._cpu
1✔
556
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
557

558
    @property
559
    def has_aspect_gpu(self):
560
        """ Returns ``True`` if this device is a GPU device,
561
        ``False`` otherwise.
562

563
        :Example:
564

565
            .. code-block:: python
566

567
                >>> import dpctl
568
                >>> dev = dpctl.select_cpu_device()
569
                >>> dev.has_aspect_gpu
570
                False
571

572
        Returns:
573
            bool:
574
                Indicates whether the device is a gpu.
575
        """
576
        cdef _aspect_type AT = _aspect_type._gpu
1✔
577
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
578

579
    @property
580
    def has_aspect_accelerator(self):
581
        """ Returns ``True`` if this device is an accelerator device,
582
        ``False`` otherwise.
583

584
        SYCL considers an accelerator to be a device that usually uses a
585
        peripheral interconnect for communication.
586

587
        :Example:
588

589
            .. code-block:: python
590

591
                >>> import dpctl
592
                >>> dev = dpctl.select_cpu_device()
593
                >>> dev.has_aspect_accelerator
594
                False
595

596
        Returns:
597
            bool:
598
                Indicates whether the device is an accelerator.
599
        """
600
        cdef _aspect_type AT = _aspect_type._accelerator
1✔
601
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
602

603
    @property
604
    def has_aspect_custom(self):
605
        """ Returns ``True`` if this device is a custom device,
606
        ``False`` otherwise.
607

608
        A custom device can be a dedicated accelerator that can use the
609
        SYCL API, but programmable kernels cannot be dispatched to the device,
610
        only fixed functionality is available. Refer SYCL spec for more details.
611

612
        :Example:
613

614
            .. code-block:: python
615

616
                >>> import dpctl
617
                >>> dev = dpctl.select_cpu_device()
618
                >>> dev.has_aspect_custom
619
                False
620

621
        Returns:
622
            bool:
623
                Indicates if the device is a custom SYCL device.
624
        """
625
        cdef _aspect_type AT = _aspect_type._custom
1✔
626
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
627

628
    @property
629
    def has_aspect_fp16(self):
630
        """ Returns ``True`` if the device supports half-precision floating
631
        point operations, ``False`` otherwise.
632

633
        :Example:
634

635
            .. code-block:: python
636

637
                >>> import dpctl
638
                >>> dev = dpctl.select_cpu_device()
639
                >>> dev.has_aspect_fp16
640
                True
641

642
        Returns:
643
            bool:
644
                Indicates that the device supports half precision floating
645
                point operations.
646
        """
647
        cdef _aspect_type AT = _aspect_type._fp16
1✔
648
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
649

650
    @property
651
    def has_aspect_fp64(self):
652
        """ Returns ``True`` if the device supports 64-bit precision floating
653
        point operations, ``False`` otherwise.
654

655
        :Example:
656

657
            .. code-block:: python
658

659
                >>> import dpctl
660
                >>> dev = dpctl.select_cpu_device()
661
                >>> dev.has_aspect_fp64
662
                True
663

664
        Returns:
665
            bool:
666
                Indicates that the device supports 64-bit precision floating
667
                point operations.
668
        """
669
        cdef _aspect_type AT = _aspect_type._fp64
1✔
670
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
671

672
    @property
673
    def has_aspect_atomic64(self):
674
        """ Returns ``True`` if the device supports a basic set of atomic
675
        operations, ``False`` otherwise.
676

677
        Indicates that the device supports the following atomic operations on
678
        64-bit values:
679

680
            - ``sycl::atomic_ref::load``
681
            - ``sycl::atomic_ref::store``
682
            - ``sycl::atomic_ref::fetch_add``
683
            - ``sycl::atomic_ref::fetch_sub``
684
            - ``sycl::atomic_ref::exchange``
685
            - ``sycl::atomic_ref::compare_exchange_strong``
686
            - ``sycl::atomic_ref::compare_exchange_weak``
687

688
        :Example:
689

690
            .. code-block:: python
691

692
                >>> import dpctl
693
                >>> dev = dpctl.select_cpu_device()
694
                >>> dev.has_aspect_atomic64
695
                True
696

697
        Returns:
698
            bool:
699
                Indicates that the device supports a basic set of atomic
700
                operations on 64-bit values.
701
        """
702
        cdef _aspect_type AT = _aspect_type._atomic64
1✔
703
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
704

705
    @property
706
    def has_aspect_image(self):
707
        """ Returns ``True`` if the device supports images, ``False`` otherwise
708
        (refer Sec 4.15.3 of SYCL 2020 spec).
709

710
        Returns:
711
            bool:
712
                Indicates that the device supports images
713
        """
714
        cdef _aspect_type AT = _aspect_type._image
1✔
715
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
716

717
    @property
718
    def has_aspect_online_compiler(self):
719
        """ Returns ``True`` if this device supports online compilation of
720
        device code, ``False`` otherwise.
721

722
        Returns:
723
            bool:
724
                Indicates that the device supports online compilation of
725
                device code.
726
        """
727
        cdef _aspect_type AT = _aspect_type._online_compiler
1✔
728
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
729

730
    @property
731
    def has_aspect_online_linker(self):
732
        """ Returns ``True`` if this device supports online linking of
733
        device code, ``False`` otherwise.
734

735
        Returns:
736
            bool:
737
                Indicates that the device supports online linking of device
738
                code.
739
        """
740
        cdef _aspect_type AT = _aspect_type._online_linker
1✔
741
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
742

743
    @property
744
    def has_aspect_queue_profiling(self):
745
        """ Returns ``True`` if this device supports queue profiling,
746
        ``False`` otherwise.
747

748
        Returns:
749
            bool:
750
                Indicates that the device supports queue profiling.
751
        """
752
        cdef _aspect_type AT = _aspect_type._queue_profiling
1✔
753
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
754

755
    @property
756
    def has_aspect_usm_device_allocations(self):
757
        """ Returns ``True`` if this device supports explicit USM allocations,
758
        ``False`` otherwise (refer Section 4.8 of SYCL 2020 specs).
759

760
        Returns:
761
            bool:
762
                Indicates that the device supports explicit USM allocations.
763
        """
764
        cdef _aspect_type AT = _aspect_type._usm_device_allocations
1✔
765
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
766

767
    @property
768
    def has_aspect_usm_host_allocations(self):
769
        """ Returns ``True`` if this device can access USM-host memory,
770
        ``False`` otherwise (refer Section 4.8 of SYCL 2020 specs).
771

772
        Returns:
773
            bool:
774
                Indicates that the device can access USM memory
775
                allocated using ``sycl::malloc_host``.
776
        """
777
        cdef _aspect_type AT = _aspect_type._usm_host_allocations
1✔
778
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
779

780
    @property
781
    def has_aspect_usm_shared_allocations(self):
782
        """ Returns ``True`` if this device supports USM-shared memory
783
        allocated on the same device, ``False`` otherwise.
784

785
        Returns:
786
            bool:
787
                Indicates that the device supports USM memory
788
                allocated using ``sycl::malloc_shared``.
789
        """
790
        cdef _aspect_type AT = _aspect_type._usm_shared_allocations
1✔
791
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
792

793
    @property
794
    def has_aspect_usm_system_allocations(self):
795
        """ Returns ``True`` if system allocator may be used instead of
796
        SYCL USM allocation mechanism for USM-shared allocations on this
797
        device, ``False`` otherwise.
798

799
        Returns:
800
            bool:
801
                Indicates that system allocator may be used instead of
802
                ``sycl::malloc_shared``.
803
        """
804
        cdef _aspect_type AT = _aspect_type._usm_system_allocations
1✔
805
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
806

807
    @property
808
    def has_aspect_usm_atomic_host_allocations(self):
809
        """ Returns ``True`` if this device supports USM-host allocations
810
        and the host and this device may concurrently access and atomically
811
        modify host allocations, ``False`` otherwise.
812

813
        Returns:
814
            bool:
815
                Indicates if the device supports USM atomic host allocations.
816
        """
817
        cdef _aspect_type AT = _aspect_type._usm_atomic_host_allocations
1✔
818
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
819

820
    @property
821
    def has_aspect_usm_atomic_shared_allocations(self):
822
        """ Returns ``True`` if this device supports USM-shared allocations
823
        and the host and other devices in the same context as this device may
824
        concurrently access and atomically modify shared allocations,
825
        ``False`` otherwise.
826

827
        Returns:
828
            bool:
829
                Indicates if this device supports concurrent atomic modification
830
                of USM-shared allocation by host and device.
831
        """
832
        cdef _aspect_type AT = _aspect_type._usm_atomic_shared_allocations
1✔
833
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
834

835
    @property
836
    def has_aspect_host_debuggable(self):
837
        """ Returns ``True`` if kernels running on this device can be debugged
838
        using standard debuggers that are normally available on the host
839
        system, ``False`` otherwise.
840

841
        Returns:
842
            bool:
843
                Indicates if host debugger may be used to debug device code.
844
        """
845
        cdef _aspect_type AT = _aspect_type._host_debuggable
1✔
846
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
847

848
    @property
849
    def has_aspect_emulated(self):
850
        """ Returns ``True`` if this device is somehow emulated, ``False``
851
        otherwise. A device with this aspect is not intended for performance,
852
        and instead will generally have another purpose such as emulation
853
        or profiling.
854

855
        Returns:
856
            bool:
857
                Indicates if device is somehow emulated.
858
        """
859
        cdef _aspect_type AT = _aspect_type._emulated
1✔
860
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
861

862
    @property
863
    def has_aspect_is_component(self):
864
        """ Returns ``True`` if this device is a component device, ``False``
865
        otherwise. A device with this aspect will have a composite device
866
        from which it is descended.
867

868
        Returns:
869
            bool:
870
                Indicates if device is a component device.
871
        """
872
        cdef _aspect_type AT = _aspect_type._is_component
1✔
873
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
874

875
    @property
876
    def has_aspect_is_composite(self):
877
        """ Returns ``True`` if this device is a composite device, ``False``
878
        otherwise. A device with this aspect contains component devices.
879

880
        Returns:
881
            bool:
882
                Indicates if device is a composite device.
883
        """
884
        cdef _aspect_type AT = _aspect_type._is_composite
1✔
885
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
886

887
    @property
888
    def image_2d_max_width(self):
889
        """ Returns the maximum width of a 2D image or 1D image in pixels.
890
            The minimum value is 8192 if the SYCL device has
891
            ``sycl::aspect::image``.
892

893
            Returns:
894
                int:
895
                    Maximum width of a 2D image or 1D image in pixels.
896
        """
897
        return DPCTLDevice_GetImage2dMaxWidth(self._device_ref)
1✔
898

899
    @property
900
    def image_2d_max_height(self):
901
        """ Returns the maximum height of a 2D image or 1D image in pixels.
902
            The minimum value is 8192 if the SYCL device has
903
            ``sycl::aspect::image``.
904

905
            Returns:
906
                int:
907
                    Maximum height of a 2D image or 1D image in pixels.
908
        """
909
        return DPCTLDevice_GetImage2dMaxHeight(self._device_ref)
1✔
910

911
    @property
912
    def image_3d_max_width(self):
913
        """ Returns the maximum width of a 3D image in pixels.
914
            The minimum value is 2048 if the SYCL device has
915
            ``sycl::aspect::image``.
916

917
            Returns:
918
                int:
919
                    Maximum width of a 3D image in pixels.
920
        """
921
        return DPCTLDevice_GetImage3dMaxWidth(self._device_ref)
1✔
922

923
    @property
924
    def image_3d_max_height(self):
925
        """ Returns the maximum height of a 3D image in pixels.
926
            The minimum value is 2048 if the SYCL device has
927
            ``sycl::aspect::image``.
928

929
            Returns:
930
                int:
931
                    Maximum height of a 3D image in pixels.
932
        """
933
        return DPCTLDevice_GetImage3dMaxHeight(self._device_ref)
1✔
934

935
    @property
936
    def image_3d_max_depth(self):
937
        """ Returns the maximum depth of a 3D image in pixels.
938
            The minimum value is 2048 if the SYCL device has
939
            ``sycl::aspect::image``.
940

941
            Returns:
942
                int:
943
                    Maximum depth of a 3D image in pixels.
944
        """
945
        return DPCTLDevice_GetImage3dMaxDepth(self._device_ref)
1✔
946

947
    @property
948
    def default_selector_score(self):
949
        """ Integral score assigned to this device by DPC++ runtime's default
950
        selector's scoring function. Score of -1 denotes that this device
951
        was rejected and may not be properly programmed by the DPC++ runtime.
952

953
        Returns:
954
            int:
955
                Score assign to this device by ``sycl::default_selector_v``
956
                function.
957
        """
958
        cdef DPCTLSyclDeviceSelectorRef DSRef = DPCTLDefaultSelector_Create()
1✔
959
        cdef int score = -1
1✔
960
        if (DSRef):
1✔
961
            score = DPCTLDeviceSelector_Score(DSRef, self._device_ref)
1✔
962
            DPCTLDeviceSelector_Delete(DSRef)
1✔
963
        return score
1✔
964

965
    @property
966
    def max_read_image_args(self):
967
        """ Returns the maximum number of simultaneous image objects that
968
        can be read from by a kernel. The minimum value is 128 if the
969
        SYCL device has ``sycl::aspect::image``.
970

971
        Returns:
972
            int:
973
                Maximum number of image objects that can be read from by
974
                a kernel.
975
        """
976
        return DPCTLDevice_GetMaxReadImageArgs(self._device_ref)
1✔
977

978
    @property
979
    def max_write_image_args(self):
980
        """ Returns the maximum number of simultaneous image objects that
981
        can be written to by a kernel. The minimum value is 8 if the SYCL
982
        device has ``sycl::aspect::image``.
983

984
        Return:
985
            int:
986
                Maximum number of simultaneous image objects that
987
                can be written to by a kernel.
988
        """
989
        return DPCTLDevice_GetMaxWriteImageArgs(self._device_ref)
1✔
990

991
    @property
992
    def is_accelerator(self):
993
        """ Returns ``True`` if this instance is a SYCL
994
        accelerator device.
995

996
        Returns:
997
            bool:
998
                ``True`` if the :class:`.SyclDevice` is a SYCL accelerator
999
                device, else ``False``.
1000
        """
1001
        return DPCTLDevice_IsAccelerator(self._device_ref)
1✔
1002

1003
    @property
1004
    def is_cpu(self):
1005
        """ Returns ``True`` if this instance is a SYCL CPU device.
1006

1007
        Returns:
1008
            bool:
1009
                ``True`` if the :class:`.SyclDevice` is a SYCL CPU device,
1010
                else ``False``.
1011
        """
1012
        return DPCTLDevice_IsCPU(self._device_ref)
1✔
1013

1014
    @property
1015
    def is_gpu(self):
1016
        """ Returns ``True`` if this instance is a SYCL GPU device.
1017

1018
        Returns:
1019
            bool:
1020
                ``True`` if the :class:`.SyclDevice` is a SYCL GPU device,
1021
                else ``False``.
1022
        """
1023
        return DPCTLDevice_IsGPU(self._device_ref)
1✔
1024

1025
    @property
1026
    def max_work_item_dims(self):
1027
        """ Returns the maximum dimensions that specify the global and local
1028
        work-item IDs used by the data parallel execution model.
1029

1030
        Returns:
1031
            int:
1032
                The maximum number of work items supported by the device.
1033
        """
1034
        cdef uint32_t max_work_item_dims = 0
1✔
1035
        max_work_item_dims = DPCTLDevice_GetMaxWorkItemDims(self._device_ref)
1✔
1036
        return max_work_item_dims
1✔
1037

1038
    @property
1039
    def max_work_item_sizes1d(self):
1040
        """ Returns the maximum number of work-items that are permitted in each
1041
        dimension of the work-group of the ``sycl::nd_range<1>``. The minimum
1042
        value is ``(1, )`` for devices that evaluate to ``False`` for
1043
        :py:attr:`~has_aspect_custom`.
1044

1045
        Returns:
1046
            Tuple[int]:
1047
                A one-tuple with the maximum allowed value for a 1D range
1048
                used to enqueue a kernel on the device.
1049
        """
1050
        cdef size_t *max_work_item_sizes1d = NULL
1✔
1051
        cdef size_t s0
1052
        max_work_item_sizes1d = DPCTLDevice_GetMaxWorkItemSizes1d(
1✔
1053
            self._device_ref
1054
        )
1055
        if max_work_item_sizes1d is NULL:
1✔
1056
            raise RuntimeError("error obtaining 'max_work_item_sizes1d'")
×
1057
        s0 = max_work_item_sizes1d[0]
1✔
1058
        DPCTLSize_t_Array_Delete(max_work_item_sizes1d)
1✔
1059
        return (s0, )
1✔
1060

1061
    @property
1062
    def max_work_item_sizes2d(self):
1063
        """ Returns the maximum number of work-items that are permitted in each
1064
        dimension of the work-group of the ``sycl::nd_range<2>``. The minimum
1065
        value is ``(1, 1,)`` for devices that evaluate to ``False`` for
1066
        :py:attr:`~has_aspect_custom`.
1067

1068
        Returns:
1069
            Tuple[int]:
1070
                A two-tuple with the maximum allowed value for each
1071
                dimension of a 2D range used to enqueue a kernel on the device.
1072
        """
1073
        cdef size_t *max_work_item_sizes2d = NULL
1✔
1074
        cdef size_t s0
1075
        cdef size_t s1
1076
        max_work_item_sizes2d = DPCTLDevice_GetMaxWorkItemSizes2d(
1✔
1077
            self._device_ref
1078
        )
1079
        if max_work_item_sizes2d is NULL:
1✔
1080
            raise RuntimeError("error obtaining 'max_work_item_sizes2d'")
×
1081
        s0 = max_work_item_sizes2d[0]
1✔
1082
        s1 = max_work_item_sizes2d[1]
1✔
1083
        DPCTLSize_t_Array_Delete(max_work_item_sizes2d)
1✔
1084
        return (s0, s1,)
1✔
1085

1086
    @property
1087
    def max_work_item_sizes3d(self):
1088
        """ Returns the maximum number of work-items that are permitted in each
1089
        dimension of the work-group of the ``sycl::nd_range<3>``. The minimum
1090
        value is ``(1, 1, 1,)`` for devices that evaluate to ``False`` for
1091
        :py:attr:`~has_aspect_custom`.
1092

1093
        Returns:
1094
            Tuple[int]:
1095
                A three-tuple with the maximum allowed value for
1096
                each dimension of a 3D range used to enqueue a kernel on
1097
                the device.
1098
        """
1099
        return (
1✔
1100
            self._max_work_item_sizes[0],
1✔
1101
            self._max_work_item_sizes[1],
1✔
1102
            self._max_work_item_sizes[2],
1✔
1103
        )
1104

1105
    @property
1106
    def max_work_item_sizes(self):
1107
        """ Returns the maximum number of work-items that are permitted in each
1108
        dimension of the work-group of the nd_range. The minimum value is
1109
        `(1; 1; 1)` for devices that evaluate to ``False`` for
1110
        :py:attr:`~has_aspect_custom`.
1111

1112
        Returns:
1113
            Tuple[int]:
1114
                A three-tuple whose length depends on the number of
1115
                work-group dimensions supported by the device.
1116

1117
        .. deprecated:: 0.14
1118
           The property is deprecated use :py:attr:`~max_work_item_sizes3d`
1119
           instead.
1120
        """
1121
        warnings.warn(
1✔
1122
            "dpctl.SyclDevice.max_work_item_sizes is deprecated, "
1123
            "use dpctl.SyclDevice.max_work_item_sizes3d instead",
1124
            DeprecationWarning,
1✔
1125
        )
1126
        return (
1✔
1127
            self._max_work_item_sizes[0],
1✔
1128
            self._max_work_item_sizes[1],
1✔
1129
            self._max_work_item_sizes[2],
1✔
1130
        )
1131

1132
    @property
1133
    def max_compute_units(self):
1134
        """ Returns the number of parallel compute units available to the
1135
        device. The minimum value is 1.
1136

1137
        Returns:
1138
            int:
1139
                The number of compute units in the device.
1140
        """
1141
        cdef uint32_t max_compute_units = 0
1✔
1142
        max_compute_units = DPCTLDevice_GetMaxComputeUnits(self._device_ref)
1✔
1143
        return max_compute_units
1✔
1144

1145
    @property
1146
    def max_work_group_size(self):
1147
        """ Returns the maximum number of work-items that are permitted in a
1148
        work-group executing a kernel on a single compute unit. The minimum
1149
        value is 1.
1150

1151
        Returns:
1152
            int:
1153
                The maximum supported work-group size.
1154
        """
1155
        cdef uint32_t max_work_group_size = 0
1✔
1156
        max_work_group_size = DPCTLDevice_GetMaxWorkGroupSize(self._device_ref)
1✔
1157
        return max_work_group_size
1✔
1158

1159
    @property
1160
    def max_num_sub_groups(self):
1161
        """ Returns the maximum number of sub-groups
1162
        in a work-group for any kernel executed on the
1163
        device. The minimum value is 1.
1164

1165
        Returns:
1166
            int:
1167
                The maximum number of sub-groups support per work-group by
1168
                the device.
1169
        """
1170
        cdef uint32_t max_num_sub_groups = (
1171
            DPCTLDevice_GetMaxNumSubGroups(self._device_ref)
1✔
1172
        )
1173
        return max_num_sub_groups
1✔
1174

1175
    @property
1176
    def sub_group_independent_forward_progress(self):
1177
        """ Returns ``True`` if the device supports independent forward progress
1178
        of sub-groups with respect to other sub-groups in the same work-group.
1179

1180
        Returns:
1181
            bool:
1182
                Indicates if the device supports independent forward progress
1183
                of sub-groups.
1184
        """
1185
        return DPCTLDevice_GetSubGroupIndependentForwardProgress(
1✔
1186
            self._device_ref
1✔
1187
        )
1188

1189
    @property
1190
    def sub_group_sizes(self):
1191
        """ Returns list of supported sub-group sizes for this device.
1192

1193
        :Example:
1194

1195
            .. code-block:: python
1196

1197
                >>> import dpctl
1198
                >>> dev = dpctl.select_cpu_device()
1199
                >>> dev.sub_group_sizes
1200
                [4, 8, 16, 32, 64]
1201

1202
        Returns:
1203
            List[int]:
1204
                List of supported sub-group sizes.
1205
        """
1206
        cdef size_t *sg_sizes = NULL
1✔
1207
        cdef size_t sg_sizes_len = 0
1✔
1208
        cdef size_t i
1209

1210
        sg_sizes = DPCTLDevice_GetSubGroupSizes(
1✔
1211
            self._device_ref, &sg_sizes_len)
1212
        if (sg_sizes is not NULL and sg_sizes_len > 0):
1✔
1213
            res = list()
1✔
1214
            for i in range(sg_sizes_len):
1✔
1215
                res.append(sg_sizes[i])
1✔
1216
            DPCTLSize_t_Array_Delete(sg_sizes)
1✔
1217
            return res
1✔
1218
        else:
1219
            return []
×
1220

1221
    @property
1222
    def sycl_platform(self):
1223
        """ Returns the platform associated with this device.
1224

1225
        Returns:
1226
            :class:`dpctl.SyclPlatform`:
1227
                The platform associated with this device.
1228
        """
1229
        cdef DPCTLSyclPlatformRef PRef = (
1230
            DPCTLDevice_GetPlatform(self._device_ref)
1✔
1231
        )
1232
        if (PRef == NULL):
1✔
1233
            raise RuntimeError("Could not get platform for device.")
×
1234
        else:
1235
            return SyclPlatform._create(PRef)
1✔
1236

1237
    @property
1238
    def preferred_vector_width_char(self):
1239
        """ Returns the preferred native vector width size for built-in scalar
1240
        types that can be put into vectors.
1241

1242
        Returns:
1243
            int:
1244
                Preferred native vector width size for C type ``char``.
1245

1246
        :Example:
1247

1248
            .. code-block:: python
1249

1250
                import dpctl
1251

1252
                dev = dpctl.select_cpu_device()
1253
                pvw_c = dev.preferred_vector_width_char
1254
        """
1255
        return DPCTLDevice_GetPreferredVectorWidthChar(self._device_ref)
1✔
1256

1257
    @property
1258
    def preferred_vector_width_short(self):
1259
        """ Returns the preferred native vector width size for built-in scalar
1260
        types that can be put into vectors.
1261

1262
        Returns:
1263
            int:
1264
                Preferred native vector width size for C type ``short``.
1265

1266
        :Example:
1267

1268
            .. code-block:: python
1269

1270
                import dpctl
1271

1272
                dev = dpctl.select_cpu_device()
1273
                pvw_s = dev.preferred_vector_width_short
1274
        """
1275
        return DPCTLDevice_GetPreferredVectorWidthShort(self._device_ref)
1✔
1276

1277
    @property
1278
    def preferred_vector_width_int(self):
1279
        """ Returns the preferred native vector width size for built-in scalar
1280
        types that can be put into vectors.
1281

1282
        Returns:
1283
            int:
1284
                Preferred native vector width size for C type ``int``.
1285

1286
        :Example:
1287

1288
            .. code-block:: python
1289

1290
                import dpctl
1291

1292
                dev = dpctl.select_cpu_device()
1293
                pvw_i = dev.preferred_vector_width_int
1294
        """
1295
        return DPCTLDevice_GetPreferredVectorWidthInt(self._device_ref)
1✔
1296

1297
    @property
1298
    def preferred_vector_width_long(self):
1299
        """ Returns the preferred native vector width size for built-in scalar
1300
        types that can be put into vectors.
1301

1302
        Returns:
1303
            int:
1304
                Preferred native vector width size for C type ``long``.
1305

1306
        :Example:
1307

1308
            .. code-block:: python
1309

1310
                import dpctl
1311

1312
                dev = dpctl.select_cpu_device()
1313
                pvw_l = dev.preferred_vector_width_long
1314
        """
1315
        return DPCTLDevice_GetPreferredVectorWidthLong(self._device_ref)
1✔
1316

1317
    @property
1318
    def preferred_vector_width_float(self):
1319
        """ Returns the preferred native vector width size for built-in scalar
1320
        types that can be put into vectors.
1321

1322
        Returns:
1323
            int:
1324
                Preferred native vector width size for C type ``float``.
1325

1326
        :Example:
1327

1328
            .. code-block:: python
1329

1330
                import dpctl
1331

1332
                dev = dpctl.select_cpu_device()
1333
                pvw_f = dev.preferred_vector_width_float
1334
        """
1335
        return DPCTLDevice_GetPreferredVectorWidthFloat(self._device_ref)
1✔
1336

1337
    @property
1338
    def preferred_vector_width_double(self):
1339
        """ Returns the preferred native vector width size for built-in scalar
1340
        types that can be put into vectors.
1341

1342
        Returns:
1343
            int:
1344
                Preferred native vector width size for C type ``double``.
1345

1346
        If device does not support double-precision floating point operations,
1347
        the native width is zero.
1348

1349
        :Example:
1350

1351
            .. code-block:: python
1352

1353
                import dpctl
1354

1355
                dev = dpctl.select_cpu_device()
1356
                pvw_d = dev.preferred_vector_width_double
1357
        """
1358
        return DPCTLDevice_GetPreferredVectorWidthDouble(self._device_ref)
1✔
1359

1360
    @property
1361
    def preferred_vector_width_half(self):
1362
        """ Returns the preferred native vector width size for built-in scalar
1363
        types that can be put into vectors.
1364

1365
        Returns:
1366
            int:
1367
                Preferred native vector width size for C type ``sycl::half``.
1368

1369
        If device does not support half-precision floating point operations,
1370
        the native width is zero.
1371
        """
1372
        return DPCTLDevice_GetPreferredVectorWidthHalf(self._device_ref)
1✔
1373

1374
    @property
1375
    def native_vector_width_char(self):
1376
        """ Returns the native ISA vector width size for built-in scalar
1377
        types that can be put into vectors.
1378

1379
        Returns:
1380
            int:
1381
                Native ISA vector width size for C type ``char``.
1382

1383
        :Example:
1384

1385
            .. code-block:: python
1386

1387
                import dpctl
1388

1389
                dev = dpctl.select_cpu_device()
1390
                nvw_c = dev.native_vector_width_char
1391
        """
1392
        return DPCTLDevice_GetNativeVectorWidthChar(self._device_ref)
1✔
1393

1394
    @property
1395
    def native_vector_width_short(self):
1396
        """ Returns the native ISA vector width size for built-in scalar
1397
        types that can be put into vectors.
1398

1399
        Returns:
1400
            int:
1401
                Native ISA vector width size for C type ``short``.
1402

1403
        :Example:
1404

1405
            .. code-block:: python
1406

1407
                import dpctl
1408

1409
                dev = dpctl.select_cpu_device()
1410
                nvw_s = dev.native_vector_width_short
1411
        """
1412
        return DPCTLDevice_GetNativeVectorWidthShort(self._device_ref)
1✔
1413

1414
    @property
1415
    def native_vector_width_int(self):
1416
        """ Returns the native ISA vector width size for built-in scalar
1417
        types that can be put into vectors.
1418

1419
        Returns:
1420
            int:
1421
                Native ISA vector width size for C type ``int``.
1422

1423
        :Example:
1424

1425
            .. code-block:: python
1426

1427
                import dpctl
1428

1429
                dev = dpctl.select_cpu_device()
1430
                nvw_i = dev.native_vector_width_int
1431
        """
1432
        return DPCTLDevice_GetNativeVectorWidthInt(self._device_ref)
1✔
1433

1434
    @property
1435
    def native_vector_width_long(self):
1436
        """ Returns the native ISA vector width size for built-in scalar
1437
        types that can be put into vectors.
1438

1439
        Returns:
1440
            int:
1441
                Native ISA vector width size for C type ``long``.
1442

1443
        :Example:
1444

1445
            .. code-block:: python
1446

1447
                import dpctl
1448

1449
                dev = dpctl.select_cpu_device()
1450
                nvw_l = dev.native_vector_width_long
1451
        """
1452
        return DPCTLDevice_GetNativeVectorWidthLong(self._device_ref)
1✔
1453

1454
    @property
1455
    def native_vector_width_float(self):
1456
        """ Returns the native ISA vector width size for built-in scalar
1457
        types that can be put into vectors.
1458

1459
        Returns:
1460
            int:
1461
                Native ISA vector width size for C type ``float``.
1462

1463
        :Example:
1464

1465
            .. code-block:: python
1466

1467
                import dpctl
1468

1469
                dev = dpctl.select_cpu_device()
1470
                nvw_f = dev.native_vector_width_float
1471
        """
1472
        return DPCTLDevice_GetNativeVectorWidthFloat(self._device_ref)
1✔
1473

1474
    @property
1475
    def native_vector_width_double(self):
1476
        """ Returns the native ISA vector width size for built-in scalar
1477
        types that can be put into vectors.
1478

1479
        Returns:
1480
            int:
1481
                Native ISA vector width size for C type ``double``.
1482

1483
        :Example:
1484

1485
            .. code-block:: python
1486

1487
                import dpctl
1488

1489
                dev = dpctl.select_cpu_device()
1490
                nvw_d = dev.native_vector_width_double
1491
        """
1492
        return DPCTLDevice_GetNativeVectorWidthDouble(self._device_ref)
1✔
1493

1494
    @property
1495
    def native_vector_width_half(self):
1496
        """ Returns the native ISA vector width size for built-in scalar
1497
        types that can be put into vectors.
1498

1499
        Returns:
1500
            int:
1501
                Native ISA vector width size for C type ``sycl::half``.
1502
        """
1503
        return DPCTLDevice_GetNativeVectorWidthHalf(self._device_ref)
1✔
1504

1505
    @property
1506
    def global_mem_size(self):
1507
        """ Returns the size of global memory on this device in bytes.
1508

1509
        Returns:
1510
            int:
1511
                Size of global memory in bytes.
1512
        """
1513
        cdef size_t global_mem_size = 0
1✔
1514
        global_mem_size = DPCTLDevice_GetGlobalMemSize(self._device_ref)
1✔
1515
        return global_mem_size
1✔
1516

1517
    @property
1518
    def local_mem_size(self):
1519
        """ Returns the size of local memory on this device in bytes.
1520

1521
        Returns:
1522
            int:
1523
                Size of global memory in bytes.
1524
        """
1525
        cdef size_t local_mem_size = 0
1✔
1526
        local_mem_size = DPCTLDevice_GetLocalMemSize(self._device_ref)
1✔
1527
        return local_mem_size
1✔
1528

1529
    @property
1530
    def vendor(self):
1531
        """ Returns the device vendor name as a string.
1532

1533
        Returns:
1534
            str:
1535
                The vendor name for the device as a string.
1536
        """
1537
        return self._vendor.decode()
1✔
1538

1539
    @property
1540
    def driver_version(self):
1541
        """ Returns a backend-defined driver version as a string.
1542

1543
        Returns:
1544
            str:
1545
                The driver version of the device as a string.
1546
        """
1547
        return self._driver_version.decode()
1✔
1548

1549
    @property
1550
    def name(self):
1551
        """ Returns the name of the device as a string
1552

1553
        Returns:
1554
            str:
1555
                The name of the device as a string.
1556
        """
1557
        return self._name.decode()
1✔
1558

1559
    @property
1560
    def __name__(self):
1561
        """ Returns the name of the class  :class:`dpctl.SyclDevice`
1562

1563
        Returns:
1564
            str:
1565
                Name of the class as a string.
1566
        """
1567
        return "SyclDevice"
1✔
1568

1569
    def __repr__(self):
1570
        return (
1✔
1571
            "<dpctl."
1572
            + self.__name__
1✔
1573
            + " ["
1✔
1574
            + str(self.backend)
1✔
1575
            + ", "
1✔
1576
            + str(self.device_type)
1✔
1577
            + ", "
1✔
1578
            + " "
1✔
1579
            + self.name
1✔
1580
            + "] at {}>".format(hex(id(self)))
1✔
1581
        )
1582

1583
    def __hash__(self):
1584
        """Returns a hash value by hashing the underlying ``sycl::device``
1585
        object.
1586

1587
        Returns:
1588
            int:
1589
                Hash value.
1590
        """
1591
        return DPCTLDevice_Hash(self._device_ref)
1✔
1592

1593
    cdef list create_sub_devices_equally(self, size_t count):
1✔
1594
        """ Returns a list of sub-devices partitioned from this SYCL device
1595
        based on the ``count`` parameter.
1596

1597
        The returned list contains as many sub-devices as can be created
1598
        such that each sub-device contains count compute units. If the
1599
        device’s total number of compute units is not evenly divided by
1600
        count, then the remaining compute units are not included in any of
1601
        the sub-devices.
1602

1603
        Args:
1604
            count (int):
1605
                Number of sub-devices to partition into.
1606

1607
        Returns:
1608
            List[:class:`dpctl.SyclDevice`]:
1609
                Created sub-devices.
1610

1611
        Raises:
1612
            dpctl.SyclSubDeviceCreationError:
1613
                if sub-devices can not be created.
1614
        """
1615
        cdef DPCTLDeviceVectorRef DVRef = NULL
1✔
1616
        if count > 0:
1✔
1617
            DVRef = DPCTLDevice_CreateSubDevicesEqually(self._device_ref, count)
1✔
1618
        if DVRef is NULL:
1✔
1619
            raise SyclSubDeviceCreationError(
×
1620
                "Sub-devices were not created." if (count > 0) else
×
1621
                "Sub-devices were not created, "
1622
                "requested compute units count was zero."
1623
            )
1624
        return _get_devices(DVRef)
1✔
1625

1626
    cdef list create_sub_devices_by_counts(self, object counts):
1✔
1627
        """ Returns a list of sub-devices partitioned from this SYCL device
1628
        based on the ``counts`` parameter.
1629

1630
        For each non-zero value ``M`` in the counts vector, a sub-device
1631
        with ``M`` compute units is created.
1632

1633
        Returns:
1634
            List[:class:`dpctl.SyclDevice`]:
1635
                Created sub-devices.
1636

1637
        Raises:
1638
            dpctl.SyclSubDeviceCreationError:
1639
                if sub-devices can not be created.
1640
        """
1641
        cdef int ncounts = len(counts)
1✔
1642
        cdef size_t *counts_buff = NULL
1✔
1643
        cdef size_t min_count = 1
1✔
1644
        cdef DPCTLDeviceVectorRef DVRef = NULL
1✔
1645
        cdef int i
1646

1647
        if ncounts == 0:
1✔
1648
            raise ValueError(
×
1649
                "Non-empty object representing list of counts is expected."
1650
            )
1651
        counts_buff = <size_t *> malloc((<size_t> ncounts) * sizeof(size_t))
1✔
1652
        if counts_buff is NULL:
1✔
1653
            raise MemoryError(
×
1654
                "Allocation of counts array of size {} failed.".format(ncounts)
×
1655
            )
1656
        for i in range(ncounts):
1✔
1657
            counts_buff[i] = counts[i]
1✔
1658
            if counts_buff[i] == 0:
1✔
1659
                min_count = 0
×
1660
        if min_count:
1✔
1661
            DVRef = DPCTLDevice_CreateSubDevicesByCounts(
1✔
1662
                self._device_ref, counts_buff, ncounts
1663
            )
1664
        free(counts_buff)
1✔
1665
        if DVRef is NULL:
1✔
1666
            raise SyclSubDeviceCreationError(
×
1667
                "Sub-devices were not created." if (min_count > 0) else
×
1668
                "Sub-devices were not created, "
1669
                "sub-device execution units counts must be positive."
1670
            )
1671
        return _get_devices(DVRef)
1✔
1672

1673
    cdef list create_sub_devices_by_affinity(
1✔
1674
        self, _partition_affinity_domain_type domain
1675
    ):
1676
        """ Returns a list of sub-devices partitioned from this SYCL device by
1677
        affinity domain based on the ``domain`` parameter.
1678

1679
        Returns:
1680
            List[:class:`dpctl.SyclDevice`]:
1681
                Created sub-devices.
1682

1683
        Raises:
1684
            dpctl.SyclSubDeviceCreationError:
1685
                if sub-devices can not be created.
1686
        """
1687
        cdef DPCTLDeviceVectorRef DVRef = NULL
1✔
1688
        DVRef = DPCTLDevice_CreateSubDevicesByAffinity(self._device_ref, domain)
1✔
1689
        if DVRef is NULL:
1✔
1690
            raise SyclSubDeviceCreationError("Sub-devices were not created.")
1✔
1691
        return _get_devices(DVRef)
×
1692

1693
    def create_sub_devices(self, **kwargs):
1✔
1694
        """create_sub_devices(partition=parition_spec)
1695
        Creates a list of sub-devices by partitioning a root device based on the
1696
        provided partition specifier.
1697

1698
        A partition specifier must be provided using a ``partition``
1699
        keyword argument. Possible values for the specifier are: an integer, a
1700
        string specifying the affinity domain, or a collection of integers.
1701

1702
        :Example:
1703
            .. code-block:: python
1704

1705
                import dpctl
1706

1707
                cpu_d = dpctl.SyclDevice("cpu")
1708
                cpu_count = cpu_d.max_compute_units
1709
                sub_devs = cpu_d.create_sub_devices(partition=cpu_count // 2)
1710
                for d in sub_devs:
1711
                    d.print_device_info()
1712

1713
                # Create sub-devices partitioning by affinity.
1714
                try:
1715
                    sd = cpu_d.create_sub_devices(partition="numa")
1716
                    print(
1717
                        "{0} sub-devices were created with respective "
1718
                        "#EUs being {1}".format(
1719
                            len(sd), [d.max_compute_units for d in sd]
1720
                        )
1721
                    )
1722
                except Exception:
1723
                    print("Device partitioning by affinity was not successful.")
1724

1725
        Args:
1726
            partition (Union[int, str, List[int]]):
1727
                Specification to partition the device as follows:
1728

1729
                - Specifying an int (``count``)
1730
                    The returned list contains as
1731
                    many sub-devices as can be created such that each
1732
                    sub-device contains ``count`` compute units. If the
1733
                    device’s total number of compute units is not evenly
1734
                    divided by ``count``, then the remaining compute units
1735
                    are not included in any of the sub-devices.
1736

1737
                - Specifying an affinity domain as a string
1738
                    The supported values are: ``"numa"``, ``"L4_cache"``,
1739
                    ``"L3_cache"``, ``"L2_cache"``, ``"L1_cache"``,
1740
                    ``"next_partitionable"``.
1741

1742
                - Specifying a collection of integral values
1743
                    For each non-zero value ``M`` in the collection, a
1744
                    sub-device with ``M`` compute units is created.
1745

1746
        Returns:
1747
            List[:class:`dpctl.SyclDevice`]:
1748
                Created sub-devices.
1749

1750
        Raises:
1751
            ValueError:
1752
                If the ``partition`` keyword argument is not specified or
1753
                the affinity domain string is not legal or is not one of the
1754
                three supported options.
1755
            dpctl.SyclSubDeviceCreationError:
1756
                If sub-devices can not be created.
1757
        """
1758
        if "partition" not in kwargs:
1✔
1759
            raise TypeError(
×
1760
                "create_sub_devices(partition=parition_spec) is expected."
1761
            )
1762
        partition = kwargs.pop("partition")
1✔
1763
        if kwargs:
1✔
1764
            raise TypeError(
×
1765
                "create_sub_devices(partition=parition_spec) is expected."
1766
            )
1767
        if isinstance(partition, int) and partition >= 0:
1✔
1768
            return self.create_sub_devices_equally(partition)
1✔
1769
        elif isinstance(partition, str):
1✔
1770
            if partition == "not_applicable":
1✔
1771
                domain_type = _partition_affinity_domain_type._not_applicable
1✔
1772
            elif partition == "numa":
1✔
1773
                domain_type = _partition_affinity_domain_type._numa
1✔
1774
            elif partition == "L4_cache":
1✔
1775
                domain_type = _partition_affinity_domain_type._L4_cache
1✔
1776
            elif partition == "L3_cache":
1✔
1777
                domain_type = _partition_affinity_domain_type._L3_cache
1✔
1778
            elif partition == "L2_cache":
1✔
1779
                domain_type = _partition_affinity_domain_type._L2_cache
1✔
1780
            elif partition == "L1_cache":
1✔
1781
                domain_type = _partition_affinity_domain_type._L1_cache
1✔
1782
            elif partition == "next_partitionable":
1✔
1783
                domain_type = (
1784
                    _partition_affinity_domain_type._next_partitionable
1✔
1785
                )
1786
            else:
1787
                raise ValueError(
×
1788
                    "Partition affinity domain {} is not understood.".format(
×
1789
                        partition
×
1790
                    )
1791
                )
1792
            return self.create_sub_devices_by_affinity(domain_type)
1✔
1793
        elif isinstance(partition, collections.abc.Sized) and isinstance(
1✔
1794
            partition, collections.abc.Iterable
1✔
1795
        ):
1796
            return self.create_sub_devices_by_counts(partition)
1✔
1797
        else:
1798
            try:
×
1799
                partition = int(partition)
×
1800
            except Exception as e:
×
1801
                raise TypeError(
×
1802
                    "Unsupported type of sub-device argument"
1803
                ) from e
×
1804
            return self.create_sub_devices_equally(partition)
×
1805

1806
    @property
1807
    def parent_device(self):
1808
        """ Parent device for a sub-device, or None for a root device.
1809

1810
        Returns:
1811
            dpctl.SyclDevice:
1812
                A parent :class:`dpctl.SyclDevice` instance if the
1813
                device is a sub-device, ``None`` otherwise.
1814
        """
1815
        cdef DPCTLSyclDeviceRef pDRef = NULL
1✔
1816
        pDRef = DPCTLDevice_GetParentDevice(self._device_ref)
1✔
1817
        if (pDRef is NULL):
1✔
1818
            return None
1✔
1819
        return SyclDevice._create(pDRef)
×
1820

1821
    @property
1822
    def composite_device(self):
1823
        """ The composite device for a component device, or ``None`` for a
1824
        non-component device.
1825

1826
        Returns:
1827
            dpctl.SyclDevice:
1828
                The composite :class:`dpctl.SyclDevice` instance for a
1829
                component device, or ``None`` for a non-component device.
1830
        """
1831
        cdef DPCTLSyclDeviceRef CDRef = NULL
×
1832
        CDRef = DPCTLDevice_GetCompositeDevice(self._device_ref)
×
1833
        if (CDRef is NULL):
×
1834
            return None
×
1835
        return SyclDevice._create(CDRef)
×
1836

1837
    def component_devices(self):
1✔
1838
        """ Returns a list of component devices contained in this SYCL device.
1839

1840
        The returned list will be empty if this SYCL device is not a composite
1841
        device, i.e., if `is_composite` is ``False``.
1842

1843
        Returns:
1844
            List[:class:`dpctl.SyclDevice`]:
1845
                List of component devices.
1846

1847
        Raises:
1848
            ValueError:
1849
                If the ``DPCTLDevice_GetComponentDevices`` call returned
1850
                ``NULL`` instead of a ``DPCTLDeviceVectorRef`` object.
1851
        """
1852
        cdef DPCTLDeviceVectorRef cDVRef = NULL
×
1853
        cDVRef = DPCTLDevice_GetComponentDevices(self._device_ref)
×
1854
        if cDVRef is NULL:
×
1855
            raise ValueError("Internal error: NULL device vector encountered")
×
1856
        return _get_devices(cDVRef)
×
1857

1858
    def can_access_peer(self, peer, value="access_supported"):
1✔
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):
1✔
1905
            raise TypeError(
×
1906
                f"Expected `value` to be of type str, got {type(value)}"
×
1907
            )
1908
        if value == "access_supported":
1✔
1909
            access_type = _peer_access._access_supported
1✔
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):
1✔
1918
            raise TypeError(
1✔
1919
                "peer device must be a `dpctl.SyclDevice`, got "
1✔
1920
                f"{type(peer)}"
1✔
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):
1✔
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):
1✔
1955
            raise TypeError(
1✔
1956
                "peer device must be a `dpctl.SyclDevice`, got "
1✔
1957
                f"{type(peer)}"
1✔
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):
1✔
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):
1✔
1990
            raise TypeError(
1✔
1991
                "peer device must be a `dpctl.SyclDevice`, got "
1✔
1992
                f"{type(peer)}"
1✔
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

2002
    @property
2003
    def profiling_timer_resolution(self):
2004
        """ Profiling timer resolution.
2005

2006
        Returns:
2007
            int:
2008
                The resolution of device timer in nanoseconds.
2009
        """
2010
        cdef size_t timer_res = 0
1✔
2011
        timer_res = DPCTLDevice_GetProfilingTimerResolution(self._device_ref)
1✔
2012
        if (timer_res == 0):
1✔
2013
            raise RuntimeError("Failed to get device timer resolution.")
×
2014
        return timer_res
1✔
2015

2016
    @property
2017
    def max_clock_frequency(self):
2018
        """ Maximal clock frequency in MHz.
2019

2020
        Returns:
2021
            int: Frequency in MHz
2022
        """
2023
        cdef uint32_t clock_fr = DPCTLDevice_GetMaxClockFrequency(
1✔
2024
            self._device_ref
2025
        )
2026
        return clock_fr
1✔
2027

2028
    @property
2029
    def max_mem_alloc_size(self):
2030
        """ Maximum size of memory object than can be allocated.
2031

2032
        Returns:
2033
            int:
2034
                Maximum size of memory object in bytes
2035
        """
2036
        cdef uint64_t max_alloc_sz = DPCTLDevice_GetMaxMemAllocSize(
1✔
2037
            self._device_ref
2038
        )
2039
        return max_alloc_sz
1✔
2040

2041
    @property
2042
    def global_mem_cache_type(self):
2043
        """ Global device cache memory type.
2044

2045
        :Example:
2046

2047
            .. code-block:: python
2048

2049
                >>> import dpctl
2050
                >>> dev = dpctl.select_cpu_device()
2051
                >>> dev.global_mem_cache_type
2052
                <global_mem_cache_type.read_write: 4>
2053

2054
        Returns:
2055
            global_mem_cache_type:
2056
                type of cache memory
2057

2058
        Raises:
2059
            RuntimeError:
2060
                If an unrecognized memory type is reported by runtime.
2061
        """
2062
        cdef _global_mem_cache_type gmcTy = (
2063
           DPCTLDevice_GetGlobalMemCacheType(self._device_ref)
1✔
2064
        )
2065
        if gmcTy == _global_mem_cache_type._MEM_CACHE_TYPE_READ_WRITE:
1✔
2066
            return global_mem_cache_type.read_write
1✔
2067
        elif gmcTy == _global_mem_cache_type._MEM_CACHE_TYPE_READ_ONLY:
2068
            return global_mem_cache_type.read_only
×
2069
        elif gmcTy == _global_mem_cache_type._MEM_CACHE_TYPE_NONE:
2070
            return global_mem_cache_type.none
×
2071
        elif gmcTy == _global_mem_cache_type._MEM_CACHE_TYPE_INDETERMINATE:
2072
            raise RuntimeError("Unrecognized global memory cache type reported")
×
2073

2074
    @property
2075
    def global_mem_cache_size(self):
2076
        """ Global device memory cache size.
2077

2078
        Returns:
2079
            int:
2080
                Cache size in bytes
2081
        """
2082
        cdef uint64_t cache_sz = DPCTLDevice_GetGlobalMemCacheSize(
1✔
2083
            self._device_ref
2084
        )
2085
        return cache_sz
1✔
2086

2087
    @property
2088
    def global_mem_cache_line_size(self):
2089
        """ Global device memory cache line size.
2090

2091
        Returns:
2092
            int:
2093
                Cache size in bytes
2094
        """
2095
        cdef uint64_t cache_line_sz = DPCTLDevice_GetGlobalMemCacheLineSize(
1✔
2096
            self._device_ref
2097
        )
2098
        return cache_line_sz
1✔
2099

2100
    @property
2101
    def partition_max_sub_devices(self):
2102
        """ The maximum number of sub-devices this :class:`dpctl.SyclDevice`
2103
        instance can be partitioned into. The value returned cannot exceed the
2104
        value returned by :attr:`dpctl.SyclDevice.max_compute_units`.
2105

2106
        Returns:
2107
            int:
2108
                The maximum number of sub-devices that can be created when this
2109
                device is partitioned. Zero value indicates that device can not
2110
                be partitioned.
2111
        """
2112
        cdef uint32_t max_part = DPCTLDevice_GetPartitionMaxSubDevices(
1✔
2113
            self._device_ref
2114
        )
2115
        return max_part
1✔
2116

2117
    cdef cpp_bool equals(self, SyclDevice other):
1✔
2118
        """ Returns ``True`` if the :class:`dpctl.SyclDevice` argument has the
2119
        same _device_ref as this SyclDevice.
2120

2121
        Args:
2122
            other (:class:`dpctl.SyclDevice`):
2123
                A :class:`dpctl.SyclDevice` instance to
2124
                compare against.
2125

2126
        Returns:
2127
            bool:
2128
                ``True`` if the devices point to the same underlying
2129
                ``sycl::device``, otherwise ``False``.
2130
        """
2131
        return DPCTLDevice_AreEq(self._device_ref, other.get_device_ref())
1✔
2132

2133
    def __eq__(self, other):
2134
        "Returns ``True`` if two devices are the same"
2135
        if isinstance(other, SyclDevice):
1✔
2136
            return self.equals(<SyclDevice> other)
1✔
2137
        else:
2138
            return False
1✔
2139

2140
    @property
2141
    def filter_string(self):
2142
        """ For a root device, returns a fully specified filter selector
2143
        string ``"backend:device_type:relative_id"`` selecting the device.
2144

2145
        Returns:
2146
            str:
2147
                A Python string representing a filter selector string.
2148

2149
        Raises:
2150
            ValueError:
2151
                If the device is a sub-device.
2152

2153
        :Example:
2154
            .. code-block:: python
2155

2156
                import dpctl
2157

2158
                # Create a SyclDevice with an explicit filter string,
2159
                # in this case the first level_zero gpu device.
2160
                level_zero_gpu = dpctl.SyclDevice("level_zero:gpu:0")
2161
                # filter_string property should be "level_zero:gpu:0"
2162
                dev = dpctl.SyclDevice(level_zero_gpu.filter_string)
2163
                assert level_zero_gpu == dev
2164
        """
2165
        cdef DPCTLSyclDeviceRef pDRef = NULL
1✔
2166
        pDRef = DPCTLDevice_GetParentDevice(self._device_ref)
1✔
2167
        if (pDRef is NULL):
1✔
2168
            return _cached_filter_string(self)
1✔
2169
        else:
2170
            # this a sub-device, free it, and raise an exception
2171
            DPCTLDevice_Delete(pDRef)
×
2172
            raise ValueError("This SyclDevice is not a root device")
×
2173

2174
    cdef int get_backend_and_device_type_ordinal(self):
1✔
2175
        """ If this device is a root ``sycl::device``, returns the ordinal
2176
        position of this device in the vector
2177
        ``sycl::device::get_devices(device_type_of_this_device)``
2178
        filtered to contain only devices with the same backend as this
2179
        device.
2180

2181
        Returns -1 if the device is a sub-device, or the device could not
2182
        be found in the vector.
2183
        """
2184
        cdef int64_t relId = DPCTLDeviceMgr_GetRelativeId(self._device_ref)
1✔
2185
        return relId
1✔
2186

2187
    cdef int get_device_type_ordinal(self):
1✔
2188
        """ If this device is a root ``sycl::device``, returns the ordinal
2189
        position of this device in the vector
2190
        ``sycl::device::get_devices(device_type_of_this_device)``
2191

2192
        Returns -1 if the device is a sub-device, or the device could not
2193
        be found in the vector.
2194
        """
2195
        cdef _device_type DTy
2196
        cdef int64_t relId = -1
1✔
2197

2198
        DTy = DPCTLDevice_GetDeviceType(self._device_ref)
1✔
2199
        relId = DPCTLDeviceMgr_GetPositionInDevices(self._device_ref, DTy)
1✔
2200
        return relId
1✔
2201

2202
    cdef int get_backend_ordinal(self):
1✔
2203
        """ If this device is a root ``sycl::device``, returns the ordinal
2204
        position of this device in the vector ``sycl::device::get_devices()``
2205
        filtered to contain only devices with the same backend as this
2206
        device.
2207

2208
        Returns -1 if the device is a sub-device, or the device could not
2209
        be found in the vector.
2210
        """
2211
        cdef _backend_type BTy
2212
        cdef int64_t relId = -1
1✔
2213

2214
        BTy = DPCTLDevice_GetBackend(self._device_ref)
1✔
2215
        relId = DPCTLDeviceMgr_GetPositionInDevices(self._device_ref, BTy)
1✔
2216
        return relId
1✔
2217

2218
    cdef int get_overall_ordinal(self):
1✔
2219
        """ If this device is a root ``sycl::device``, returns the ordinal
2220
        position of this device in the vector ``sycl::device::get_devices()``.
2221

2222
        Returns -1 if the device is a sub-device, or the device could not
2223
        be found in the vector.
2224
        """
2225
        cdef int64_t relId = -1
1✔
2226

2227
        relId = DPCTLDeviceMgr_GetPositionInDevices(
1✔
2228
            self._device_ref,
2229
            (_backend_type._ALL_BACKENDS | _device_type._ALL_DEVICES)
2230
        )
2231
        return relId
1✔
2232

2233
    def get_filter_string(self, include_backend=True, include_device_type=True):
1✔
2234
        """ get_filter_string(include_backend=True, include_device_type=True)
2235

2236
        For a parent device, returns a filter selector string
2237
        that includes backend or device type based on the value
2238
        of the given keyword arguments.
2239

2240
        Args:
2241
            include_backend (bool, optional):
2242
                A flag indicating if the backend should be included in
2243
                the filter string. Default: ``True``.
2244
            include_device_type (bool, optional):
2245
                A flag indicating if the device type should be included
2246
                in the filter string. Default: ``True``.
2247

2248
        Returns:
2249
            str:
2250
                A Python string representing a filter selector string.
2251

2252
        Raises:
2253
            ValueError:
2254
                If the device is a sub-device.
2255

2256
                If no match for the device was found in the vector
2257
                returned by ``sycl::device::get_devices()``
2258

2259
        :Example:
2260
            .. code-block:: python
2261

2262
                import dpctl
2263

2264
                # Create a GPU SyclDevice
2265
                gpu_dev = dpctl.SyclDevice("gpu:0")
2266
                # filter string should be "gpu:0"
2267
                fs = gpu_dev.get_filter_string(use_backend=False)
2268
                dev = dpctl.SyclDevice(fs)
2269
                assert gpu _dev == dev
2270
        """
2271
        cdef int relId = -1
1✔
2272
        cdef DPCTLSyclDeviceRef pDRef = NULL
1✔
2273
        cdef _device_type DTy
2274
        cdef _backend_type BTy
2275

2276
        if include_backend:
1✔
2277
            if include_device_type:
1✔
2278
                relId = self.get_backend_and_device_type_ordinal()
1✔
2279
            else:
2280
                relId = self.get_backend_ordinal()
1✔
2281
        else:
2282
            if include_device_type:
1✔
2283
                relId = self.get_device_type_ordinal()
1✔
2284
            else:
2285
                relId = self.get_overall_ordinal()
1✔
2286

2287
        if relId < 0:
1✔
2288
            pDRef = DPCTLDevice_GetParentDevice(self._device_ref)
×
2289
            if (pDRef is NULL):
×
2290
                raise ValueError
×
2291
            else:
2292
                # this a sub-device, free it, and raise an exception
2293
                DPCTLDevice_Delete(pDRef)
×
2294
                raise ValueError("This SyclDevice is not a root device")
×
2295
        else:
2296
            if include_backend:
1✔
2297
                BTy = DPCTLDevice_GetBackend(self._device_ref)
1✔
2298
                be_str = _backend_type_to_filter_string_part(BTy)
1✔
2299
                if include_device_type:
1✔
2300
                    DTy = DPCTLDevice_GetDeviceType(self._device_ref)
1✔
2301
                    dt_str = _device_type_to_filter_string_part(DTy)
1✔
2302
                    return ":".join((be_str, dt_str, str(relId)))
1✔
2303
                else:
2304
                    return ":".join((be_str, str(relId)))
1✔
2305
            else:
2306
                if include_device_type:
1✔
2307
                    DTy = DPCTLDevice_GetDeviceType(self._device_ref)
1✔
2308
                    dt_str = _device_type_to_filter_string_part(DTy)
1✔
2309
                    return ":".join((dt_str, str(relId)))
1✔
2310
                else:
2311
                    return str(relId)
1✔
2312

2313
    def get_unpartitioned_parent_device(self):
1✔
2314
        """ get_unpartitioned_parent_device()
2315

2316
        Returns the unpartitioned parent device of this device.
2317

2318
        If this device is already an unpartitioned, root device,
2319
        the same device is returned.
2320

2321
        Returns:
2322
            dpctl.SyclDevice:
2323
                A parent, unpartitioned :class:`dpctl.SyclDevice` instance, or
2324
                ``self`` if already a root device.
2325
        """
2326
        cdef DPCTLSyclDeviceRef pDRef = NULL
1✔
2327
        cdef DPCTLSyclDeviceRef tDRef = NULL
1✔
2328
        pDRef = DPCTLDevice_GetParentDevice(self._device_ref)
1✔
2329
        if pDRef is NULL:
1✔
2330
            return self
1✔
2331
        else:
2332
            tDRef = DPCTLDevice_GetParentDevice(pDRef)
1✔
2333
            while tDRef is not NULL:
1✔
2334
                DPCTLDevice_Delete(pDRef)
×
2335
                pDRef = tDRef
×
2336
                tDRef = DPCTLDevice_GetParentDevice(pDRef)
×
2337
            return SyclDevice._create(pDRef)
1✔
2338

2339
    def get_device_id(self):
1✔
2340
        """ get_device_id()
2341
        For an unpartitioned device, returns the canonical index of this device
2342
        in the list of devices visible to dpctl.
2343

2344
        Returns:
2345
            int:
2346
                The index of the device.
2347

2348
        Raises:
2349
            ValueError:
2350
                If the device could not be found.
2351

2352
        :Example:
2353
            .. code-block:: python
2354

2355
                import dpctl
2356
                gpu_dev = dpctl.SyclDevice("gpu")
2357
                i = gpu_dev.get_device_id
2358
                devs = dpctl.get_devices()
2359
                assert devs[i] == gpu_dev
2360
        """
2361
        cdef int dev_id = -1
1✔
2362
        cdef SyclDevice dev
2363

2364
        dev = self.get_unpartitioned_parent_device()
1✔
2365
        dev_id = dev.get_overall_ordinal()
1✔
2366
        if dev_id < 0:
1✔
2367
            raise ValueError("device could not be found")
×
2368
        return dev_id
1✔
2369

2370

2371
cdef api DPCTLSyclDeviceRef SyclDevice_GetDeviceRef(SyclDevice dev):
1✔
2372
    """
2373
    C-API function to get opaque device reference from
2374
    :class:`dpctl.SyclDevice` instance.
2375
    """
2376
    return dev.get_device_ref()
1✔
2377

2378

2379
cdef api SyclDevice SyclDevice_Make(DPCTLSyclDeviceRef DRef):
1✔
2380
    """
2381
    C-API function to create :class:`dpctl.SyclDevice` instance
2382
    from the given opaque device reference.
2383
    """
2384
    cdef DPCTLSyclDeviceRef copied_DRef = DPCTLDevice_Copy(DRef)
1✔
2385
    return SyclDevice._create(copied_DRef)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc