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

IntelPython / dpctl / 14537256782

18 Apr 2025 03:10PM UTC coverage: 86.41% (+0.001%) from 86.409%
14537256782

Pull #2056

github

web-flow
Merge f63bdbb79 into f57963e87
Pull Request #2056: extend pre-commit hooks with cython-lint

3014 of 3710 branches covered (81.24%)

Branch coverage included in aggregate %.

205 of 263 new or added lines in 18 files covered. (77.95%)

4 existing lines in 3 files now uncovered.

12189 of 13884 relevant lines covered (87.79%)

7003.4 hits per line

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

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

108
from .enum_types import backend_type, device_type, global_mem_cache_type
1✔
109

110
from libc.stdint cimport int64_t, uint32_t, uint64_t
111
from libc.stdlib cimport free, malloc
112

113
from ._sycl_platform cimport SyclPlatform
114

115
import collections
1✔
116
import functools
1✔
117
import warnings
1✔
118

119
__all__ = [
1✔
120
    "SyclDevice", "SyclDeviceCreationError", "SyclSubDeviceCreationError",
121
]
122

123

124
cdef class SyclDeviceCreationError(Exception):
125
    """
126
    A ``SyclDeviceCreationError`` exception is raised when
127
    :class:`.SyclDevice` instance could not created.
128
    """
129
    pass
130

131

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

141

142
cdef class _SyclDevice:
143
    """
144
    A helper data-owner class to abstract ``sycl::device``
145
    instance.
146
    """
147

148
    def __dealloc__(self):
149
        DPCTLDevice_Delete(self._device_ref)
1✔
150
        DPCTLCString_Delete(self._name)
1✔
151
        DPCTLCString_Delete(self._vendor)
1✔
152
        DPCTLCString_Delete(self._driver_version)
1✔
153
        DPCTLSize_t_Array_Delete(self._max_work_item_sizes)
1✔
154

155

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

170
    return devices
1✔
171

172

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

185

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

198

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

215

216
@functools.lru_cache(maxsize=None)
1✔
217
def _cached_filter_string(d : SyclDevice):
218
    """
219
    Internal utility to compute filter_string of input SyclDevice
220
    and cached with `functools.cache`.
221

222
    Args:
223
        d (dpctl.SyclDevice):
224
            A device for which to compute the filter string.
225
    Returns:
226
        out(str):
227
            Filter string that can be used to create input device,
228
            if the device is a root (unpartitioned) device.
229

230
    Raises:
231
        ValueError: if the input device is a sub-device.
232
    """
233
    cdef _backend_type BTy
234
    cdef _device_type DTy
235
    cdef int64_t relId = -1
1✔
236
    cdef SyclDevice cd = <SyclDevice> d
1✔
237
    relId = DPCTLDeviceMgr_GetRelativeId(cd._device_ref)
1✔
238
    if (relId == -1):
1✔
239
        raise ValueError("This SyclDevice is not a root device")
×
240
    BTy = DPCTLDevice_GetBackend(cd._device_ref)
1✔
241
    br_str = _backend_type_to_filter_string_part(BTy)
1✔
242
    DTy = DPCTLDevice_GetDeviceType(cd._device_ref)
1✔
243
    dt_str = _device_type_to_filter_string_part(DTy)
1✔
244
    return ":".join((br_str, dt_str, str(relId)))
1✔
245

246

247
cdef class SyclDevice(_SyclDevice):
248
    """ SyclDevice(arg=None)
249
    A Python wrapper for the ``sycl::device`` C++ class.
250

251
    There are two ways of creating a SyclDevice instance:
252

253
    - by directly passing in a filter string to the class
254
      constructor. The filter string needs to conform to the
255
      :oneapi_filter_selection:`DPC++ filter selector SYCL extension <>`.
256

257
    :Example:
258

259
        .. code-block:: python
260

261
            import dpctl
262

263
            # Create a SyclDevice with an explicit filter string,
264
            # in this case the first level_zero gpu device.
265
            level_zero_gpu = dpctl.SyclDevice("level_zero:gpu:0")
266
            level_zero_gpu.print_device_info()
267

268
    - by calling one of the device selector helper functions:
269
      :py:func:`dpctl.select_accelerator_device()`,
270
      :py:func:`dpctl.select_cpu_device()`,
271
      :py:func:`dpctl.select_default_device()`,
272
      :py:func:`dpctl.select_gpu_device()`
273

274
    :Example:
275

276
        .. code-block:: python
277

278
            import dpctl
279

280
            # Create a SyclDevice of type GPU based on whatever is returned
281
            # by the SYCL `gpu_selector` device selector class.
282
            gpu = dpctl.select_gpu_device()
283
            gpu.print_device_info()
284

285
    Args:
286
        arg (str, optional):
287
            The argument can be a selector string, another
288
            :class:`dpctl.SyclDevice`, or ``None``.
289
            Defaults to ``None``.
290

291
    Raises:
292
        MemoryError:
293
            If the constructor could not allocate necessary
294
            temporary memory.
295
        SyclDeviceCreationError:
296
            If the :class:`dpctl.SyclDevice` object creation failed.
297
        TypeError:
298
            If the argument is not a :class:`dpctl.SyclDevice` or string.
299
    """
300
    @staticmethod
301
    cdef SyclDevice _create(DPCTLSyclDeviceRef dref):
1✔
302
        """
303
        This function calls DPCTLDevice_Delete(dref).
304

305
        The user of this function must pass a copy to keep the
306
        dref argument alive.
307
        """
308
        cdef _SyclDevice ret = _SyclDevice.__new__(_SyclDevice)
1✔
309
        # Initialize the attributes of the SyclDevice object
310
        _init_helper(<_SyclDevice> ret, dref)
1✔
311
        # ret is a temporary, and _SyclDevice.__dealloc__ will delete dref
312
        return SyclDevice(ret)
1✔
313

314
    cdef int _init_from__SyclDevice(self, _SyclDevice other):
1✔
315
        self._device_ref = DPCTLDevice_Copy(other._device_ref)
1✔
316
        if (self._device_ref is NULL):
1✔
317
            return -1
×
318
        self._name = DPCTLDevice_GetName(self._device_ref)
1✔
319
        self._driver_version = DPCTLDevice_GetDriverVersion(self._device_ref)
1✔
320
        self._max_work_item_sizes = (
1✔
321
            DPCTLDevice_GetMaxWorkItemSizes3d(self._device_ref)
322
        )
323
        self._vendor = DPCTLDevice_GetVendor(self._device_ref)
1✔
324
        return 0
1✔
325

326
    cdef int _init_from_selector(self, DPCTLSyclDeviceSelectorRef DSRef):
1✔
327
        # Initialize the attributes of the SyclDevice object
328
        cdef DPCTLSyclDeviceRef DRef = DPCTLDevice_CreateFromSelector(DSRef)
1✔
329
        # Free up the device selector
330
        DPCTLDeviceSelector_Delete(DSRef)
1✔
331
        if DRef is NULL:
1✔
332
            return -1
1✔
333
        else:
334
            _init_helper(self, DRef)
1✔
335
            return 0
1✔
336

337
    def __cinit__(self, arg=None):
338
        cdef DPCTLSyclDeviceSelectorRef DSRef = NULL
1✔
339
        cdef const char *filter_c_str = NULL
1✔
340
        cdef int ret = 0
1✔
341

342
        if type(arg) is str:
1✔
343
            string = bytes(<str>arg, "utf-8")
1✔
344
            filter_c_str = string
1✔
345
            DSRef = DPCTLFilterSelector_Create(filter_c_str)
1✔
346
            ret = self._init_from_selector(DSRef)
1✔
347
            if ret == -1:
1✔
348
                raise SyclDeviceCreationError(
1✔
349
                    "Could not create a SyclDevice with the selector string "
350
                    "'{selector_string}'".format(selector_string=arg)
1✔
351
                )
352
        elif isinstance(arg, _SyclDevice):
1✔
353
            ret = self._init_from__SyclDevice(arg)
1✔
354
            if ret == -1:
1✔
355
                raise SyclDeviceCreationError(
×
356
                    "Could not create a SyclDevice from _SyclDevice instance"
357
                )
358
        elif arg is None:
1✔
359
            DSRef = DPCTLDefaultSelector_Create()
1✔
360
            ret = self._init_from_selector(DSRef)
1✔
361
            if ret == -1:
1✔
362
                raise SyclDeviceCreationError(
×
363
                    "Could not create a SyclDevice from default selector"
364
                )
365
        else:
366
            raise TypeError(
1✔
367
                "Invalid argument. Argument should be a str object specifying "
368
                "a SYCL filter selector string or another SyclDevice."
369
            )
370

371
    def print_device_info(self):
1✔
372
        """
373
        Print information about the SYCL device.
374
        """
375
        cdef const char * info_str = DPCTLDeviceMgr_GetDeviceInfoStr(
1✔
376
            self._device_ref
377
        )
378
        py_info = <bytes> info_str
1✔
379
        DPCTLCString_Delete(info_str)
1✔
380
        print(py_info.decode("utf-8"))
1✔
381

382
    cdef DPCTLSyclDeviceRef get_device_ref(self):
1✔
383
        """
384
        Returns the :c:struct:`DPCTLSyclDeviceRef` pointer for this class.
385
        """
386
        return self._device_ref
1✔
387

388
    def addressof_ref(self):
1✔
389
        """
390
        Returns the address of the :c:struct:`DPCTLSyclDeviceRef` pointer as a
391
        ``size_t``.
392

393
        :Example:
394

395
            .. code-block:: python
396

397
                >>> import dpctl
398
                >>> dev = dpctl.select_cpu_device()
399
                >>> hex(dev.addressof_ref())
400
                '0x55b18ec649d0'
401

402
        Returns:
403
            int: The address of the :c:struct:`DPCTLSyclDeviceRef` object used
404
            to create this :class:`dpctl.SyclDevice` cast to a ``size_t``.
405
        """
406
        return <size_t>self._device_ref
1✔
407

408
    @property
409
    def backend(self):
410
        """Returns the ``backend_type`` enum value for this device
411

412
        :Example:
413

414
            .. code-block:: python
415

416
                >>> import dpctl
417
                >>> dev = dpctl.select_cpu_device()
418
                >>> dev.backend
419
                <backend_type.opencl: 4>
420

421
        Returns:
422
            backend_type:
423
                The backend for the device.
424
        """
425
        cdef _backend_type BTy = (
426
            DPCTLDevice_GetBackend(self._device_ref)
1✔
427
        )
428
        if BTy == _backend_type._CUDA:
1✔
429
            return backend_type.cuda
×
430
        elif BTy == _backend_type._HIP:
431
            return backend_type.hip
×
432
        elif BTy == _backend_type._LEVEL_ZERO:
433
            return backend_type.level_zero
×
434
        elif BTy == _backend_type._OPENCL:
435
            return backend_type.opencl
1✔
436
        else:
437
            raise ValueError("Unknown backend type.")
×
438

439
    @property
440
    def device_type(self):
441
        """ Returns the type of the device as a ``device_type`` enum.
442

443
        :Example:
444

445
            .. code-block:: python
446

447
                >>> import dpctl
448
                >>> dev = dpctl.select_cpu_device()
449
                >>> dev.device_type
450
                <device_type.cpu: 4>
451

452
        Returns:
453
            device_type:
454
                The type of device encoded as a ``device_type`` enum.
455

456
        Raises:
457
            ValueError:
458
                If the device type is not recognized.
459
        """
460
        cdef _device_type DTy = (
461
            DPCTLDevice_GetDeviceType(self._device_ref)
1✔
462
        )
463
        if DTy == _device_type._ACCELERATOR:
1✔
464
            return device_type.accelerator
×
465
        elif DTy == _device_type._AUTOMATIC:
466
            return device_type.automatic
×
467
        elif DTy == _device_type._CPU:
468
            return device_type.cpu
1✔
469
        elif DTy == _device_type._GPU:
470
            return device_type.gpu
×
471
        else:
472
            raise ValueError("Unknown device type.")
×
473

474
    @property
475
    def has_aspect_cpu(self):
476
        """ Returns ``True`` if this device is a CPU device,
477
        ``False`` otherwise.
478

479
        :Example:
480

481
            .. code-block:: python
482

483
                >>> import dpctl
484
                >>> dev = dpctl.select_cpu_device()
485
                >>> dev.has_aspect_cpu
486
                True
487

488
        Returns:
489
            bool:
490
                Indicates whether the device is a cpu.
491
        """
492
        cdef _aspect_type AT = _aspect_type._cpu
1✔
493
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
494

495
    @property
496
    def has_aspect_gpu(self):
497
        """ Returns ``True`` if this device is a GPU device,
498
        ``False`` otherwise.
499

500
        :Example:
501

502
            .. code-block:: python
503

504
                >>> import dpctl
505
                >>> dev = dpctl.select_cpu_device()
506
                >>> dev.has_aspect_gpu
507
                False
508

509
        Returns:
510
            bool:
511
                Indicates whether the device is a gpu.
512
        """
513
        cdef _aspect_type AT = _aspect_type._gpu
1✔
514
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
515

516
    @property
517
    def has_aspect_accelerator(self):
518
        """ Returns ``True`` if this device is an accelerator device,
519
        ``False`` otherwise.
520

521
        SYCL considers an accelerator to be a device that usually uses a
522
        peripheral interconnect for communication.
523

524
        :Example:
525

526
            .. code-block:: python
527

528
                >>> import dpctl
529
                >>> dev = dpctl.select_cpu_device()
530
                >>> dev.has_aspect_accelerator
531
                False
532

533
        Returns:
534
            bool:
535
                Indicates whether the device is an accelerator.
536
        """
537
        cdef _aspect_type AT = _aspect_type._accelerator
1✔
538
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
539

540
    @property
541
    def has_aspect_custom(self):
542
        """ Returns ``True`` if this device is a custom device,
543
        ``False`` otherwise.
544

545
        A custom device can be a dedicated accelerator that can use the
546
        SYCL API, but programmable kernels cannot be dispatched to the device,
547
        only fixed functionality is available. Refer SYCL spec for more details.
548

549
        :Example:
550

551
            .. code-block:: python
552

553
                >>> import dpctl
554
                >>> dev = dpctl.select_cpu_device()
555
                >>> dev.has_aspect_custom
556
                False
557

558
        Returns:
559
            bool:
560
                Indicates if the device is a custom SYCL device.
561
        """
562
        cdef _aspect_type AT = _aspect_type._custom
1✔
563
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
564

565
    @property
566
    def has_aspect_fp16(self):
567
        """ Returns ``True`` if the device supports half-precision floating
568
        point operations, ``False`` otherwise.
569

570
        :Example:
571

572
            .. code-block:: python
573

574
                >>> import dpctl
575
                >>> dev = dpctl.select_cpu_device()
576
                >>> dev.has_aspect_fp16
577
                True
578

579
        Returns:
580
            bool:
581
                Indicates that the device supports half precision floating
582
                point operations.
583
        """
584
        cdef _aspect_type AT = _aspect_type._fp16
1✔
585
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
586

587
    @property
588
    def has_aspect_fp64(self):
589
        """ Returns ``True`` if the device supports 64-bit precision floating
590
        point operations, ``False`` otherwise.
591

592
        :Example:
593

594
            .. code-block:: python
595

596
                >>> import dpctl
597
                >>> dev = dpctl.select_cpu_device()
598
                >>> dev.has_aspect_fp64
599
                True
600

601
        Returns:
602
            bool:
603
                Indicates that the device supports 64-bit precision floating
604
                point operations.
605
        """
606
        cdef _aspect_type AT = _aspect_type._fp64
1✔
607
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
608

609
    @property
610
    def has_aspect_atomic64(self):
611
        """ Returns ``True`` if the device supports a basic set of atomic
612
        operations, ``False`` otherwise.
613

614
        Indicates that the device supports the following atomic operations on
615
        64-bit values:
616

617
            - ``sycl::atomic_ref::load``
618
            - ``sycl::atomic_ref::store``
619
            - ``sycl::atomic_ref::fetch_add``
620
            - ``sycl::atomic_ref::fetch_sub``
621
            - ``sycl::atomic_ref::exchange``
622
            - ``sycl::atomic_ref::compare_exchange_strong``
623
            - ``sycl::atomic_ref::compare_exchange_weak``
624

625
        :Example:
626

627
            .. code-block:: python
628

629
                >>> import dpctl
630
                >>> dev = dpctl.select_cpu_device()
631
                >>> dev.has_aspect_atomic64
632
                True
633

634
        Returns:
635
            bool:
636
                Indicates that the device supports a basic set of atomic
637
                operations on 64-bit values.
638
        """
639
        cdef _aspect_type AT = _aspect_type._atomic64
1✔
640
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
641

642
    @property
643
    def has_aspect_image(self):
644
        """ Returns ``True`` if the device supports images, ``False`` otherwise
645
        (refer Sec 4.15.3 of SYCL 2020 spec).
646

647
        Returns:
648
            bool:
649
                Indicates that the device supports images
650
        """
651
        cdef _aspect_type AT = _aspect_type._image
1✔
652
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
653

654
    @property
655
    def has_aspect_online_compiler(self):
656
        """ Returns ``True`` if this device supports online compilation of
657
        device code, ``False`` otherwise.
658

659
        Returns:
660
            bool:
661
                Indicates that the device supports online compilation of
662
                device code.
663
        """
664
        cdef _aspect_type AT = _aspect_type._online_compiler
1✔
665
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
666

667
    @property
668
    def has_aspect_online_linker(self):
669
        """ Returns ``True`` if this device supports online linking of
670
        device code, ``False`` otherwise.
671

672
        Returns:
673
            bool:
674
                Indicates that the device supports online linking of device
675
                code.
676
        """
677
        cdef _aspect_type AT = _aspect_type._online_linker
1✔
678
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
679

680
    @property
681
    def has_aspect_queue_profiling(self):
682
        """ Returns ``True`` if this device supports queue profiling,
683
        ``False`` otherwise.
684

685
        Returns:
686
            bool:
687
                Indicates that the device supports queue profiling.
688
        """
689
        cdef _aspect_type AT = _aspect_type._queue_profiling
1✔
690
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
691

692
    @property
693
    def has_aspect_usm_device_allocations(self):
694
        """ Returns ``True`` if this device supports explicit USM allocations,
695
        ``False`` otherwise (refer Section 4.8 of SYCL 2020 specs).
696

697
        Returns:
698
            bool:
699
                Indicates that the device supports explicit USM allocations.
700
        """
701
        cdef _aspect_type AT = _aspect_type._usm_device_allocations
1✔
702
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
703

704
    @property
705
    def has_aspect_usm_host_allocations(self):
706
        """ Returns ``True`` if this device can access USM-host memory,
707
        ``False`` otherwise (refer Section 4.8 of SYCL 2020 specs).
708

709
        Returns:
710
            bool:
711
                Indicates that the device can access USM memory
712
                allocated using ``sycl::malloc_host``.
713
        """
714
        cdef _aspect_type AT = _aspect_type._usm_host_allocations
1✔
715
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
716

717
    @property
718
    def has_aspect_usm_shared_allocations(self):
719
        """ Returns ``True`` if this device supports USM-shared memory
720
        allocated on the same device, ``False`` otherwise.
721

722
        Returns:
723
            bool:
724
                Indicates that the device supports USM memory
725
                allocated using ``sycl::malloc_shared``.
726
        """
727
        cdef _aspect_type AT = _aspect_type._usm_shared_allocations
1✔
728
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
729

730
    @property
731
    def has_aspect_usm_system_allocations(self):
732
        """ Returns ``True`` if system allocator may be used instead of
733
        SYCL USM allocation mechanism for USM-shared allocations on this
734
        device, ``False`` otherwise.
735

736
        Returns:
737
            bool:
738
                Indicates that system allocator may be used instead of
739
                ``sycl::malloc_shared``.
740
        """
741
        cdef _aspect_type AT = _aspect_type._usm_system_allocations
1✔
742
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
743

744
    @property
745
    def has_aspect_usm_atomic_host_allocations(self):
746
        """ Returns ``True`` if this device supports USM-host allocations
747
        and the host and this device may concurrently access and atomically
748
        modify host allocations, ``False`` otherwise.
749

750
        Returns:
751
            bool:
752
                Indicates if the device supports USM atomic host allocations.
753
        """
754
        cdef _aspect_type AT = _aspect_type._usm_atomic_host_allocations
1✔
755
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
756

757
    @property
758
    def has_aspect_usm_atomic_shared_allocations(self):
759
        """ Returns ``True`` if this device supports USM-shared allocations
760
        and the host and other devices in the same context as this device may
761
        concurrently access and atomically modify shared allocations,
762
        ``False`` otherwise.
763

764
        Returns:
765
            bool:
766
                Indicates if this device supports concurrent atomic modification
767
                of USM-shared allocation by host and device.
768
        """
769
        cdef _aspect_type AT = _aspect_type._usm_atomic_shared_allocations
1✔
770
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
771

772
    @property
773
    def has_aspect_host_debuggable(self):
774
        """ Returns ``True`` if kernels running on this device can be debugged
775
        using standard debuggers that are normally available on the host
776
        system, ``False`` otherwise.
777

778
        Returns:
779
            bool:
780
                Indicates if host debugger may be used to debug device code.
781
        """
782
        cdef _aspect_type AT = _aspect_type._host_debuggable
1✔
783
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
784

785
    @property
786
    def has_aspect_emulated(self):
787
        """ Returns ``True`` if this device is somehow emulated, ``False``
788
        otherwise. A device with this aspect is not intended for performance,
789
        and instead will generally have another purpose such as emulation
790
        or profiling.
791

792
        Returns:
793
            bool:
794
                Indicates if device is somehow emulated.
795
        """
796
        cdef _aspect_type AT = _aspect_type._emulated
1✔
797
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
798

799
    @property
800
    def has_aspect_is_component(self):
801
        """ Returns ``True`` if this device is a component device, ``False``
802
        otherwise. A device with this aspect will have a composite device
803
        from which it is descended.
804

805
        Returns:
806
            bool:
807
                Indicates if device is a component device.
808
        """
809
        cdef _aspect_type AT = _aspect_type._is_component
1✔
810
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
811

812
    @property
813
    def has_aspect_is_composite(self):
814
        """ Returns ``True`` if this device is a composite device, ``False``
815
        otherwise. A device with this aspect contains component devices.
816

817
        Returns:
818
            bool:
819
                Indicates if device is a composite device.
820
        """
821
        cdef _aspect_type AT = _aspect_type._is_composite
1✔
822
        return DPCTLDevice_HasAspect(self._device_ref, AT)
1✔
823

824
    @property
825
    def image_2d_max_width(self):
826
        """ Returns the maximum width of a 2D image or 1D image in pixels.
827
            The minimum value is 8192 if the SYCL device has
828
            ``sycl::aspect::image``.
829

830
            Returns:
831
                int:
832
                    Maximum width of a 2D image or 1D image in pixels.
833
        """
834
        return DPCTLDevice_GetImage2dMaxWidth(self._device_ref)
1✔
835

836
    @property
837
    def image_2d_max_height(self):
838
        """ Returns the maximum height of a 2D image or 1D image in pixels.
839
            The minimum value is 8192 if the SYCL device has
840
            ``sycl::aspect::image``.
841

842
            Returns:
843
                int:
844
                    Maximum height of a 2D image or 1D image in pixels.
845
        """
846
        return DPCTLDevice_GetImage2dMaxHeight(self._device_ref)
1✔
847

848
    @property
849
    def image_3d_max_width(self):
850
        """ Returns the maximum width of a 3D image in pixels.
851
            The minimum value is 2048 if the SYCL device has
852
            ``sycl::aspect::image``.
853

854
            Returns:
855
                int:
856
                    Maximum width of a 3D image in pixels.
857
        """
858
        return DPCTLDevice_GetImage3dMaxWidth(self._device_ref)
1✔
859

860
    @property
861
    def image_3d_max_height(self):
862
        """ Returns the maximum height of a 3D image in pixels.
863
            The minimum value is 2048 if the SYCL device has
864
            ``sycl::aspect::image``.
865

866
            Returns:
867
                int:
868
                    Maximum height of a 3D image in pixels.
869
        """
870
        return DPCTLDevice_GetImage3dMaxHeight(self._device_ref)
1✔
871

872
    @property
873
    def image_3d_max_depth(self):
874
        """ Returns the maximum depth of a 3D image in pixels.
875
            The minimum value is 2048 if the SYCL device has
876
            ``sycl::aspect::image``.
877

878
            Returns:
879
                int:
880
                    Maximum depth of a 3D image in pixels.
881
        """
882
        return DPCTLDevice_GetImage3dMaxDepth(self._device_ref)
1✔
883

884
    @property
885
    def default_selector_score(self):
886
        """ Integral score assigned to this device by DPC++ runtime's default
887
        selector's scoring function. Score of -1 denotes that this device
888
        was rejected and may not be properly programmed by the DPC++ runtime.
889

890
        Returns:
891
            int:
892
                Score assign to this device by ``sycl::default_selector_v``
893
                function.
894
        """
895
        cdef DPCTLSyclDeviceSelectorRef DSRef = DPCTLDefaultSelector_Create()
1✔
896
        cdef int score = -1
1✔
897
        if (DSRef):
1✔
898
            score = DPCTLDeviceSelector_Score(DSRef, self._device_ref)
1✔
899
            DPCTLDeviceSelector_Delete(DSRef)
1✔
900
        return score
1✔
901

902
    @property
903
    def max_read_image_args(self):
904
        """ Returns the maximum number of simultaneous image objects that
905
        can be read from by a kernel. The minimum value is 128 if the
906
        SYCL device has ``sycl::aspect::image``.
907

908
        Returns:
909
            int:
910
                Maximum number of image objects that can be read from by
911
                a kernel.
912
        """
913
        return DPCTLDevice_GetMaxReadImageArgs(self._device_ref)
1✔
914

915
    @property
916
    def max_write_image_args(self):
917
        """ Returns the maximum number of simultaneous image objects that
918
        can be written to by a kernel. The minimum value is 8 if the SYCL
919
        device has ``sycl::aspect::image``.
920

921
        Return:
922
            int:
923
                Maximum number of simultaneous image objects that
924
                can be written to by a kernel.
925
        """
926
        return DPCTLDevice_GetMaxWriteImageArgs(self._device_ref)
1✔
927

928
    @property
929
    def is_accelerator(self):
930
        """ Returns ``True`` if this instance is a SYCL
931
        accelerator device.
932

933
        Returns:
934
            bool:
935
                ``True`` if the :class:`.SyclDevice` is a SYCL accelerator
936
                device, else ``False``.
937
        """
938
        return DPCTLDevice_IsAccelerator(self._device_ref)
1✔
939

940
    @property
941
    def is_cpu(self):
942
        """ Returns ``True`` if this instance is a SYCL CPU device.
943

944
        Returns:
945
            bool:
946
                ``True`` if the :class:`.SyclDevice` is a SYCL CPU device,
947
                else ``False``.
948
        """
949
        return DPCTLDevice_IsCPU(self._device_ref)
1✔
950

951
    @property
952
    def is_gpu(self):
953
        """ Returns ``True`` if this instance is a SYCL GPU device.
954

955
        Returns:
956
            bool:
957
                ``True`` if the :class:`.SyclDevice` is a SYCL GPU device,
958
                else ``False``.
959
        """
960
        return DPCTLDevice_IsGPU(self._device_ref)
1✔
961

962
    @property
963
    def max_work_item_dims(self):
964
        """ Returns the maximum dimensions that specify the global and local
965
        work-item IDs used by the data parallel execution model.
966

967
        Returns:
968
            int:
969
                The maximum number of work items supported by the device.
970
        """
971
        cdef uint32_t max_work_item_dims = 0
1✔
972
        max_work_item_dims = DPCTLDevice_GetMaxWorkItemDims(self._device_ref)
1✔
973
        return max_work_item_dims
1✔
974

975
    @property
976
    def max_work_item_sizes1d(self):
977
        """ Returns the maximum number of work-items that are permitted in each
978
        dimension of the work-group of the ``sycl::nd_range<1>``. The minimum
979
        value is ``(1, )`` for devices that evaluate to ``False`` for
980
        :py:attr:`~has_aspect_custom`.
981

982
        Returns:
983
            Tuple[int]:
984
                A one-tuple with the maximum allowed value for a 1D range
985
                used to enqueue a kernel on the device.
986
        """
987
        cdef size_t *max_work_item_sizes1d = NULL
1✔
988
        cdef size_t s0
989
        max_work_item_sizes1d = DPCTLDevice_GetMaxWorkItemSizes1d(
1✔
990
            self._device_ref
991
        )
992
        if max_work_item_sizes1d is NULL:
1✔
993
            raise RuntimeError("error obtaining 'max_work_item_sizes1d'")
×
994
        s0 = max_work_item_sizes1d[0]
1✔
995
        DPCTLSize_t_Array_Delete(max_work_item_sizes1d)
1✔
996
        return (s0, )
1✔
997

998
    @property
999
    def max_work_item_sizes2d(self):
1000
        """ Returns the maximum number of work-items that are permitted in each
1001
        dimension of the work-group of the ``sycl::nd_range<2>``. The minimum
1002
        value is ``(1, 1,)`` for devices that evaluate to ``False`` for
1003
        :py:attr:`~has_aspect_custom`.
1004

1005
        Returns:
1006
            Tuple[int]:
1007
                A two-tuple with the maximum allowed value for each
1008
                dimension of a 2D range used to enqueue a kernel on the device.
1009
        """
1010
        cdef size_t *max_work_item_sizes2d = NULL
1✔
1011
        cdef size_t s0
1012
        cdef size_t s1
1013
        max_work_item_sizes2d = DPCTLDevice_GetMaxWorkItemSizes2d(
1✔
1014
            self._device_ref
1015
        )
1016
        if max_work_item_sizes2d is NULL:
1✔
1017
            raise RuntimeError("error obtaining 'max_work_item_sizes2d'")
×
1018
        s0 = max_work_item_sizes2d[0]
1✔
1019
        s1 = max_work_item_sizes2d[1]
1✔
1020
        DPCTLSize_t_Array_Delete(max_work_item_sizes2d)
1✔
1021
        return (s0, s1,)
1✔
1022

1023
    @property
1024
    def max_work_item_sizes3d(self):
1025
        """ Returns the maximum number of work-items that are permitted in each
1026
        dimension of the work-group of the ``sycl::nd_range<3>``. The minimum
1027
        value is ``(1, 1, 1,)`` for devices that evaluate to ``False`` for
1028
        :py:attr:`~has_aspect_custom`.
1029

1030
        Returns:
1031
            Tuple[int]:
1032
                A three-tuple with the maximum allowed value for
1033
                each dimension of a 3D range used to enqueue a kernel on
1034
                the device.
1035
        """
1036
        return (
1✔
1037
            self._max_work_item_sizes[0],
1✔
1038
            self._max_work_item_sizes[1],
1✔
1039
            self._max_work_item_sizes[2],
1✔
1040
        )
1041

1042
    @property
1043
    def max_work_item_sizes(self):
1044
        """ Returns the maximum number of work-items that are permitted in each
1045
        dimension of the work-group of the nd_range. The minimum value is
1046
        `(1; 1; 1)` for devices that evaluate to ``False`` for
1047
        :py:attr:`~has_aspect_custom`.
1048

1049
        Returns:
1050
            Tuple[int]:
1051
                A three-tuple whose length depends on the number of
1052
                work-group dimensions supported by the device.
1053

1054
        .. deprecated:: 0.14
1055
           The property is deprecated use :py:attr:`~max_work_item_sizes3d`
1056
           instead.
1057
        """
1058
        warnings.warn(
1✔
1059
            "dpctl.SyclDevice.max_work_item_sizes is deprecated, "
1060
            "use dpctl.SyclDevice.max_work_item_sizes3d instead",
1061
            DeprecationWarning,
1✔
1062
        )
1063
        return (
1✔
1064
            self._max_work_item_sizes[0],
1✔
1065
            self._max_work_item_sizes[1],
1✔
1066
            self._max_work_item_sizes[2],
1✔
1067
        )
1068

1069
    @property
1070
    def max_compute_units(self):
1071
        """ Returns the number of parallel compute units available to the
1072
        device. The minimum value is 1.
1073

1074
        Returns:
1075
            int:
1076
                The number of compute units in the device.
1077
        """
1078
        cdef uint32_t max_compute_units = 0
1✔
1079
        max_compute_units = DPCTLDevice_GetMaxComputeUnits(self._device_ref)
1✔
1080
        return max_compute_units
1✔
1081

1082
    @property
1083
    def max_work_group_size(self):
1084
        """ Returns the maximum number of work-items that are permitted in a
1085
        work-group executing a kernel on a single compute unit. The minimum
1086
        value is 1.
1087

1088
        Returns:
1089
            int:
1090
                The maximum supported work-group size.
1091
        """
1092
        cdef uint32_t max_work_group_size = 0
1✔
1093
        max_work_group_size = DPCTLDevice_GetMaxWorkGroupSize(self._device_ref)
1✔
1094
        return max_work_group_size
1✔
1095

1096
    @property
1097
    def max_num_sub_groups(self):
1098
        """ Returns the maximum number of sub-groups
1099
        in a work-group for any kernel executed on the
1100
        device. The minimum value is 1.
1101

1102
        Returns:
1103
            int:
1104
                The maximum number of sub-groups support per work-group by
1105
                the device.
1106
        """
1107
        cdef uint32_t max_num_sub_groups = (
1108
            DPCTLDevice_GetMaxNumSubGroups(self._device_ref)
1✔
1109
        )
1110
        return max_num_sub_groups
1✔
1111

1112
    @property
1113
    def sub_group_independent_forward_progress(self):
1114
        """ Returns ``True`` if the device supports independent forward progress
1115
        of sub-groups with respect to other sub-groups in the same work-group.
1116

1117
        Returns:
1118
            bool:
1119
                Indicates if the device supports independent forward progress
1120
                of sub-groups.
1121
        """
1122
        return DPCTLDevice_GetSubGroupIndependentForwardProgress(
1✔
1123
            self._device_ref
1✔
1124
        )
1125

1126
    @property
1127
    def sub_group_sizes(self):
1128
        """ Returns list of supported sub-group sizes for this device.
1129

1130
        :Example:
1131

1132
            .. code-block:: python
1133

1134
                >>> import dpctl
1135
                >>> dev = dpctl.select_cpu_device()
1136
                >>> dev.sub_group_sizes
1137
                [4, 8, 16, 32, 64]
1138

1139
        Returns:
1140
            List[int]:
1141
                List of supported sub-group sizes.
1142
        """
1143
        cdef size_t *sg_sizes = NULL
1✔
1144
        cdef size_t sg_sizes_len = 0
1✔
1145
        cdef size_t i
1146

1147
        sg_sizes = DPCTLDevice_GetSubGroupSizes(
1✔
1148
            self._device_ref, &sg_sizes_len)
1149
        if (sg_sizes is not NULL and sg_sizes_len > 0):
1✔
1150
            res = list()
1✔
1151
            for i in range(sg_sizes_len):
1✔
1152
                res.append(sg_sizes[i])
1✔
1153
            DPCTLSize_t_Array_Delete(sg_sizes)
1✔
1154
            return res
1✔
1155
        else:
NEW
1156
            return []
×
1157

1158
    @property
1159
    def sycl_platform(self):
1160
        """ Returns the platform associated with this device.
1161

1162
        Returns:
1163
            :class:`dpctl.SyclPlatform`:
1164
                The platform associated with this device.
1165
        """
1166
        cdef DPCTLSyclPlatformRef PRef = (
1167
            DPCTLDevice_GetPlatform(self._device_ref)
1✔
1168
        )
1169
        if (PRef == NULL):
1✔
1170
            raise RuntimeError("Could not get platform for device.")
×
1171
        else:
1172
            return SyclPlatform._create(PRef)
1✔
1173

1174
    @property
1175
    def preferred_vector_width_char(self):
1176
        """ Returns the preferred native vector width size for built-in scalar
1177
        types that can be put into vectors.
1178

1179
        Returns:
1180
            int:
1181
                Preferred native vector width size for C type ``char``.
1182

1183
        :Example:
1184

1185
            .. code-block:: python
1186

1187
                import dpctl
1188

1189
                dev = dpctl.select_cpu_device()
1190
                pvw_c = dev.preferred_vector_width_char
1191
        """
1192
        return DPCTLDevice_GetPreferredVectorWidthChar(self._device_ref)
1✔
1193

1194
    @property
1195
    def preferred_vector_width_short(self):
1196
        """ Returns the preferred native vector width size for built-in scalar
1197
        types that can be put into vectors.
1198

1199
        Returns:
1200
            int:
1201
                Preferred native vector width size for C type ``short``.
1202

1203
        :Example:
1204

1205
            .. code-block:: python
1206

1207
                import dpctl
1208

1209
                dev = dpctl.select_cpu_device()
1210
                pvw_s = dev.preferred_vector_width_short
1211
        """
1212
        return DPCTLDevice_GetPreferredVectorWidthShort(self._device_ref)
1✔
1213

1214
    @property
1215
    def preferred_vector_width_int(self):
1216
        """ Returns the preferred native vector width size for built-in scalar
1217
        types that can be put into vectors.
1218

1219
        Returns:
1220
            int:
1221
                Preferred native vector width size for C type ``int``.
1222

1223
        :Example:
1224

1225
            .. code-block:: python
1226

1227
                import dpctl
1228

1229
                dev = dpctl.select_cpu_device()
1230
                pvw_i = dev.preferred_vector_width_int
1231
        """
1232
        return DPCTLDevice_GetPreferredVectorWidthInt(self._device_ref)
1✔
1233

1234
    @property
1235
    def preferred_vector_width_long(self):
1236
        """ Returns the preferred native vector width size for built-in scalar
1237
        types that can be put into vectors.
1238

1239
        Returns:
1240
            int:
1241
                Preferred native vector width size for C type ``long``.
1242

1243
        :Example:
1244

1245
            .. code-block:: python
1246

1247
                import dpctl
1248

1249
                dev = dpctl.select_cpu_device()
1250
                pvw_l = dev.preferred_vector_width_long
1251
        """
1252
        return DPCTLDevice_GetPreferredVectorWidthLong(self._device_ref)
1✔
1253

1254
    @property
1255
    def preferred_vector_width_float(self):
1256
        """ Returns the preferred native vector width size for built-in scalar
1257
        types that can be put into vectors.
1258

1259
        Returns:
1260
            int:
1261
                Preferred native vector width size for C type ``float``.
1262

1263
        :Example:
1264

1265
            .. code-block:: python
1266

1267
                import dpctl
1268

1269
                dev = dpctl.select_cpu_device()
1270
                pvw_f = dev.preferred_vector_width_float
1271
        """
1272
        return DPCTLDevice_GetPreferredVectorWidthFloat(self._device_ref)
1✔
1273

1274
    @property
1275
    def preferred_vector_width_double(self):
1276
        """ Returns the preferred native vector width size for built-in scalar
1277
        types that can be put into vectors.
1278

1279
        Returns:
1280
            int:
1281
                Preferred native vector width size for C type ``double``.
1282

1283
        If device does not support double-precision floating point operations,
1284
        the native width is zero.
1285

1286
        :Example:
1287

1288
            .. code-block:: python
1289

1290
                import dpctl
1291

1292
                dev = dpctl.select_cpu_device()
1293
                pvw_d = dev.preferred_vector_width_double
1294
        """
1295
        return DPCTLDevice_GetPreferredVectorWidthDouble(self._device_ref)
1✔
1296

1297
    @property
1298
    def preferred_vector_width_half(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 ``sycl::half``.
1305

1306
        If device does not support half-precision floating point operations,
1307
        the native width is zero.
1308
        """
1309
        return DPCTLDevice_GetPreferredVectorWidthHalf(self._device_ref)
1✔
1310

1311
    @property
1312
    def native_vector_width_char(self):
1313
        """ Returns the native ISA vector width size for built-in scalar
1314
        types that can be put into vectors.
1315

1316
        Returns:
1317
            int:
1318
                Native ISA vector width size for C type ``char``.
1319

1320
        :Example:
1321

1322
            .. code-block:: python
1323

1324
                import dpctl
1325

1326
                dev = dpctl.select_cpu_device()
1327
                nvw_c = dev.native_vector_width_char
1328
        """
1329
        return DPCTLDevice_GetNativeVectorWidthChar(self._device_ref)
1✔
1330

1331
    @property
1332
    def native_vector_width_short(self):
1333
        """ Returns the native ISA vector width size for built-in scalar
1334
        types that can be put into vectors.
1335

1336
        Returns:
1337
            int:
1338
                Native ISA vector width size for C type ``short``.
1339

1340
        :Example:
1341

1342
            .. code-block:: python
1343

1344
                import dpctl
1345

1346
                dev = dpctl.select_cpu_device()
1347
                nvw_s = dev.native_vector_width_short
1348
        """
1349
        return DPCTLDevice_GetNativeVectorWidthShort(self._device_ref)
1✔
1350

1351
    @property
1352
    def native_vector_width_int(self):
1353
        """ Returns the native ISA vector width size for built-in scalar
1354
        types that can be put into vectors.
1355

1356
        Returns:
1357
            int:
1358
                Native ISA vector width size for C type ``int``.
1359

1360
        :Example:
1361

1362
            .. code-block:: python
1363

1364
                import dpctl
1365

1366
                dev = dpctl.select_cpu_device()
1367
                nvw_i = dev.native_vector_width_int
1368
        """
1369
        return DPCTLDevice_GetNativeVectorWidthInt(self._device_ref)
1✔
1370

1371
    @property
1372
    def native_vector_width_long(self):
1373
        """ Returns the native ISA vector width size for built-in scalar
1374
        types that can be put into vectors.
1375

1376
        Returns:
1377
            int:
1378
                Native ISA vector width size for C type ``long``.
1379

1380
        :Example:
1381

1382
            .. code-block:: python
1383

1384
                import dpctl
1385

1386
                dev = dpctl.select_cpu_device()
1387
                nvw_l = dev.native_vector_width_long
1388
        """
1389
        return DPCTLDevice_GetNativeVectorWidthLong(self._device_ref)
1✔
1390

1391
    @property
1392
    def native_vector_width_float(self):
1393
        """ Returns the native ISA vector width size for built-in scalar
1394
        types that can be put into vectors.
1395

1396
        Returns:
1397
            int:
1398
                Native ISA vector width size for C type ``float``.
1399

1400
        :Example:
1401

1402
            .. code-block:: python
1403

1404
                import dpctl
1405

1406
                dev = dpctl.select_cpu_device()
1407
                nvw_f = dev.native_vector_width_float
1408
        """
1409
        return DPCTLDevice_GetNativeVectorWidthFloat(self._device_ref)
1✔
1410

1411
    @property
1412
    def native_vector_width_double(self):
1413
        """ Returns the native ISA vector width size for built-in scalar
1414
        types that can be put into vectors.
1415

1416
        Returns:
1417
            int:
1418
                Native ISA vector width size for C type ``double``.
1419

1420
        :Example:
1421

1422
            .. code-block:: python
1423

1424
                import dpctl
1425

1426
                dev = dpctl.select_cpu_device()
1427
                nvw_d = dev.native_vector_width_double
1428
        """
1429
        return DPCTLDevice_GetNativeVectorWidthDouble(self._device_ref)
1✔
1430

1431
    @property
1432
    def native_vector_width_half(self):
1433
        """ Returns the native ISA vector width size for built-in scalar
1434
        types that can be put into vectors.
1435

1436
        Returns:
1437
            int:
1438
                Native ISA vector width size for C type ``sycl::half``.
1439
        """
1440
        return DPCTLDevice_GetNativeVectorWidthHalf(self._device_ref)
1✔
1441

1442
    @property
1443
    def global_mem_size(self):
1444
        """ Returns the size of global memory on this device in bytes.
1445

1446
        Returns:
1447
            int:
1448
                Size of global memory in bytes.
1449
        """
1450
        cdef size_t global_mem_size = 0
1✔
1451
        global_mem_size = DPCTLDevice_GetGlobalMemSize(self._device_ref)
1✔
1452
        return global_mem_size
1✔
1453

1454
    @property
1455
    def local_mem_size(self):
1456
        """ Returns the size of local memory on this device in bytes.
1457

1458
        Returns:
1459
            int:
1460
                Size of global memory in bytes.
1461
        """
1462
        cdef size_t local_mem_size = 0
1✔
1463
        local_mem_size = DPCTLDevice_GetLocalMemSize(self._device_ref)
1✔
1464
        return local_mem_size
1✔
1465

1466
    @property
1467
    def vendor(self):
1468
        """ Returns the device vendor name as a string.
1469

1470
        Returns:
1471
            str:
1472
                The vendor name for the device as a string.
1473
        """
1474
        return self._vendor.decode()
1✔
1475

1476
    @property
1477
    def driver_version(self):
1478
        """ Returns a backend-defined driver version as a string.
1479

1480
        Returns:
1481
            str:
1482
                The driver version of the device as a string.
1483
        """
1484
        return self._driver_version.decode()
1✔
1485

1486
    @property
1487
    def name(self):
1488
        """ Returns the name of the device as a string
1489

1490
        Returns:
1491
            str:
1492
                The name of the device as a string.
1493
        """
1494
        return self._name.decode()
1✔
1495

1496
    @property
1497
    def __name__(self):
1498
        """ Returns the name of the class  :class:`dpctl.SyclDevice`
1499

1500
        Returns:
1501
            str:
1502
                Name of the class as a string.
1503
        """
1504
        return "SyclDevice"
1✔
1505

1506
    def __repr__(self):
1507
        return (
1✔
1508
            "<dpctl."
1509
            + self.__name__
1✔
1510
            + " ["
1✔
1511
            + str(self.backend)
1✔
1512
            + ", "
1✔
1513
            + str(self.device_type)
1✔
1514
            + ", "
1✔
1515
            + " "
1✔
1516
            + self.name
1✔
1517
            + "] at {}>".format(hex(id(self)))
1✔
1518
        )
1519

1520
    def __hash__(self):
1521
        """Returns a hash value by hashing the underlying ``sycl::device``
1522
        object.
1523

1524
        Returns:
1525
            int:
1526
                Hash value.
1527
        """
1528
        return DPCTLDevice_Hash(self._device_ref)
1✔
1529

1530
    cdef list create_sub_devices_equally(self, size_t count):
1✔
1531
        """ Returns a list of sub-devices partitioned from this SYCL device
1532
        based on the ``count`` parameter.
1533

1534
        The returned list contains as many sub-devices as can be created
1535
        such that each sub-device contains count compute units. If the
1536
        device’s total number of compute units is not evenly divided by
1537
        count, then the remaining compute units are not included in any of
1538
        the sub-devices.
1539

1540
        Args:
1541
            count (int):
1542
                Number of sub-devices to partition into.
1543

1544
        Returns:
1545
            List[:class:`dpctl.SyclDevice`]:
1546
                Created sub-devices.
1547

1548
        Raises:
1549
            dpctl.SyclSubDeviceCreationError:
1550
                if sub-devices can not be created.
1551
        """
1552
        cdef DPCTLDeviceVectorRef DVRef = NULL
1✔
1553
        if count > 0:
1✔
1554
            DVRef = DPCTLDevice_CreateSubDevicesEqually(self._device_ref, count)
1✔
1555
        if DVRef is NULL:
1✔
1556
            raise SyclSubDeviceCreationError(
×
1557
                "Sub-devices were not created." if (count > 0) else
×
1558
                "Sub-devices were not created, "
1559
                "requested compute units count was zero."
1560
            )
1561
        return _get_devices(DVRef)
1✔
1562

1563
    cdef list create_sub_devices_by_counts(self, object counts):
1✔
1564
        """ Returns a list of sub-devices partitioned from this SYCL device
1565
        based on the ``counts`` parameter.
1566

1567
        For each non-zero value ``M`` in the counts vector, a sub-device
1568
        with ``M`` compute units is created.
1569

1570
        Returns:
1571
            List[:class:`dpctl.SyclDevice`]:
1572
                Created sub-devices.
1573

1574
        Raises:
1575
            dpctl.SyclSubDeviceCreationError:
1576
                if sub-devices can not be created.
1577
        """
1578
        cdef int ncounts = len(counts)
1✔
1579
        cdef size_t *counts_buff = NULL
1✔
1580
        cdef size_t min_count = 1
1✔
1581
        cdef DPCTLDeviceVectorRef DVRef = NULL
1✔
1582
        cdef int i
1583

1584
        if ncounts == 0:
1✔
1585
            raise ValueError(
×
1586
                "Non-empty object representing list of counts is expected."
1587
            )
1588
        counts_buff = <size_t *> malloc((<size_t> ncounts) * sizeof(size_t))
1✔
1589
        if counts_buff is NULL:
1✔
1590
            raise MemoryError(
×
1591
                "Allocation of counts array of size {} failed.".format(ncounts)
×
1592
            )
1593
        for i in range(ncounts):
1✔
1594
            counts_buff[i] = counts[i]
1✔
1595
            if counts_buff[i] == 0:
1✔
1596
                min_count = 0
×
1597
        if min_count:
1✔
1598
            DVRef = DPCTLDevice_CreateSubDevicesByCounts(
1✔
1599
                self._device_ref, counts_buff, ncounts
1600
            )
1601
        free(counts_buff)
1✔
1602
        if DVRef is NULL:
1✔
1603
            raise SyclSubDeviceCreationError(
×
1604
                "Sub-devices were not created." if (min_count > 0) else
×
1605
                "Sub-devices were not created, "
1606
                "sub-device execution units counts must be positive."
1607
            )
1608
        return _get_devices(DVRef)
1✔
1609

1610
    cdef list create_sub_devices_by_affinity(
1✔
1611
        self, _partition_affinity_domain_type domain
1612
    ):
1613
        """ Returns a list of sub-devices partitioned from this SYCL device by
1614
        affinity domain based on the ``domain`` parameter.
1615

1616
        Returns:
1617
            List[:class:`dpctl.SyclDevice`]:
1618
                Created sub-devices.
1619

1620
        Raises:
1621
            dpctl.SyclSubDeviceCreationError:
1622
                if sub-devices can not be created.
1623
        """
1624
        cdef DPCTLDeviceVectorRef DVRef = NULL
1✔
1625
        DVRef = DPCTLDevice_CreateSubDevicesByAffinity(self._device_ref, domain)
1✔
1626
        if DVRef is NULL:
1✔
1627
            raise SyclSubDeviceCreationError("Sub-devices were not created.")
1✔
1628
        return _get_devices(DVRef)
×
1629

1630
    def create_sub_devices(self, **kwargs):
1✔
1631
        """create_sub_devices(partition=parition_spec)
1632
        Creates a list of sub-devices by partitioning a root device based on the
1633
        provided partition specifier.
1634

1635
        A partition specifier must be provided using a ``partition``
1636
        keyword argument. Possible values for the specifier are: an integer, a
1637
        string specifying the affinity domain, or a collection of integers.
1638

1639
        :Example:
1640
            .. code-block:: python
1641

1642
                import dpctl
1643

1644
                cpu_d = dpctl.SyclDevice("cpu")
1645
                cpu_count = cpu_d.max_compute_units
1646
                sub_devs = cpu_d.create_sub_devices(partition=cpu_count // 2)
1647
                for d in sub_devs:
1648
                    d.print_device_info()
1649

1650
                # Create sub-devices partitioning by affinity.
1651
                try:
1652
                    sd = cpu_d.create_sub_devices(partition="numa")
1653
                    print(
1654
                        "{0} sub-devices were created with respective "
1655
                        "#EUs being {1}".format(
1656
                            len(sd), [d.max_compute_units for d in sd]
1657
                        )
1658
                    )
1659
                except Exception:
1660
                    print("Device partitioning by affinity was not successful.")
1661

1662
        Args:
1663
            partition (Union[int, str, List[int]]):
1664
                Specification to partition the device as follows:
1665

1666
                - Specifying an int (``count``)
1667
                    The returned list contains as
1668
                    many sub-devices as can be created such that each
1669
                    sub-device contains ``count`` compute units. If the
1670
                    device’s total number of compute units is not evenly
1671
                    divided by ``count``, then the remaining compute units
1672
                    are not included in any of the sub-devices.
1673

1674
                - Specifying an affinity domain as a string
1675
                    The supported values are: ``"numa"``, ``"L4_cache"``,
1676
                    ``"L3_cache"``, ``"L2_cache"``, ``"L1_cache"``,
1677
                    ``"next_partitionable"``.
1678

1679
                - Specifying a collection of integral values
1680
                    For each non-zero value ``M`` in the collection, a
1681
                    sub-device with ``M`` compute units is created.
1682

1683
        Returns:
1684
            List[:class:`dpctl.SyclDevice`]:
1685
                Created sub-devices.
1686

1687
        Raises:
1688
            ValueError:
1689
                If the ``partition`` keyword argument is not specified or
1690
                the affinity domain string is not legal or is not one of the
1691
                three supported options.
1692
            dpctl.SyclSubDeviceCreationError:
1693
                If sub-devices can not be created.
1694
        """
1695
        if "partition" not in kwargs:
1✔
1696
            raise TypeError(
×
1697
                "create_sub_devices(partition=parition_spec) is expected."
1698
            )
1699
        partition = kwargs.pop("partition")
1✔
1700
        if kwargs:
1✔
1701
            raise TypeError(
×
1702
                "create_sub_devices(partition=parition_spec) is expected."
1703
            )
1704
        if isinstance(partition, int) and partition >= 0:
1✔
1705
            return self.create_sub_devices_equally(partition)
1✔
1706
        elif isinstance(partition, str):
1✔
1707
            if partition == "not_applicable":
1✔
1708
                domain_type = _partition_affinity_domain_type._not_applicable
1✔
1709
            elif partition == "numa":
1✔
1710
                domain_type = _partition_affinity_domain_type._numa
1✔
1711
            elif partition == "L4_cache":
1✔
1712
                domain_type = _partition_affinity_domain_type._L4_cache
1✔
1713
            elif partition == "L3_cache":
1✔
1714
                domain_type = _partition_affinity_domain_type._L3_cache
1✔
1715
            elif partition == "L2_cache":
1✔
1716
                domain_type = _partition_affinity_domain_type._L2_cache
1✔
1717
            elif partition == "L1_cache":
1✔
1718
                domain_type = _partition_affinity_domain_type._L1_cache
1✔
1719
            elif partition == "next_partitionable":
1✔
1720
                domain_type = (
1721
                    _partition_affinity_domain_type._next_partitionable
1✔
1722
                )
1723
            else:
1724
                raise ValueError(
×
1725
                    "Partition affinity domain {} is not understood.".format(
×
1726
                        partition
×
1727
                    )
1728
                )
1729
            return self.create_sub_devices_by_affinity(domain_type)
1✔
1730
        elif isinstance(partition, collections.abc.Sized) and isinstance(
1✔
1731
            partition, collections.abc.Iterable
1✔
1732
        ):
1733
            return self.create_sub_devices_by_counts(partition)
1✔
1734
        else:
1735
            try:
×
1736
                partition = int(partition)
×
1737
            except Exception as e:
×
1738
                raise TypeError(
×
1739
                    "Unsupported type of sub-device argument"
1740
                ) from e
×
1741
            return self.create_sub_devices_equally(partition)
×
1742

1743
    @property
1744
    def parent_device(self):
1745
        """ Parent device for a sub-device, or None for a root device.
1746

1747
        Returns:
1748
            dpctl.SyclDevice:
1749
                A parent :class:`dpctl.SyclDevice` instance if the
1750
                device is a sub-device, ``None`` otherwise.
1751
        """
1752
        cdef DPCTLSyclDeviceRef pDRef = NULL
1✔
1753
        pDRef = DPCTLDevice_GetParentDevice(self._device_ref)
1✔
1754
        if (pDRef is NULL):
1✔
1755
            return None
1✔
1756
        return SyclDevice._create(pDRef)
×
1757

1758
    @property
1759
    def composite_device(self):
1760
        """ The composite device for a component device, or ``None`` for a
1761
        non-component device.
1762

1763
        Returns:
1764
            dpctl.SyclDevice:
1765
                The composite :class:`dpctl.SyclDevice` instance for a
1766
                component device, or ``None`` for a non-component device.
1767
        """
1768
        cdef DPCTLSyclDeviceRef CDRef = NULL
×
1769
        CDRef = DPCTLDevice_GetCompositeDevice(self._device_ref)
×
1770
        if (CDRef is NULL):
×
1771
            return None
×
1772
        return SyclDevice._create(CDRef)
×
1773

1774
    def component_devices(self):
1✔
1775
        """ Returns a list of component devices contained in this SYCL device.
1776

1777
        The returned list will be empty if this SYCL device is not a composite
1778
        device, i.e., if `is_composite` is ``False``.
1779

1780
        Returns:
1781
            List[:class:`dpctl.SyclDevice`]:
1782
                List of component devices.
1783

1784
        Raises:
1785
            ValueError:
1786
                If the ``DPCTLDevice_GetComponentDevices`` call returned
1787
                ``NULL`` instead of a ``DPCTLDeviceVectorRef`` object.
1788
        """
1789
        cdef DPCTLDeviceVectorRef cDVRef = NULL
×
1790
        cDVRef = DPCTLDevice_GetComponentDevices(self._device_ref)
×
1791
        if cDVRef is NULL:
×
1792
            raise ValueError("Internal error: NULL device vector encountered")
×
1793
        return _get_devices(cDVRef)
×
1794

1795
    @property
1796
    def profiling_timer_resolution(self):
1797
        """ Profiling timer resolution.
1798

1799
        Returns:
1800
            int:
1801
                The resolution of device timer in nanoseconds.
1802
        """
1803
        cdef size_t timer_res = 0
1✔
1804
        timer_res = DPCTLDevice_GetProfilingTimerResolution(self._device_ref)
1✔
1805
        if (timer_res == 0):
1✔
1806
            raise RuntimeError("Failed to get device timer resolution.")
×
1807
        return timer_res
1✔
1808

1809
    @property
1810
    def max_clock_frequency(self):
1811
        """ Maximal clock frequency in MHz.
1812

1813
        Returns:
1814
            int: Frequency in MHz
1815
        """
1816
        cdef uint32_t clock_fr = DPCTLDevice_GetMaxClockFrequency(
1✔
1817
            self._device_ref
1818
        )
1819
        return clock_fr
1✔
1820

1821
    @property
1822
    def max_mem_alloc_size(self):
1823
        """ Maximum size of memory object than can be allocated.
1824

1825
        Returns:
1826
            int:
1827
                Maximum size of memory object in bytes
1828
        """
1829
        cdef uint64_t max_alloc_sz = DPCTLDevice_GetMaxMemAllocSize(
1✔
1830
            self._device_ref
1831
        )
1832
        return max_alloc_sz
1✔
1833

1834
    @property
1835
    def global_mem_cache_type(self):
1836
        """ Global device cache memory type.
1837

1838
        :Example:
1839

1840
            .. code-block:: python
1841

1842
                >>> import dpctl
1843
                >>> dev = dpctl.select_cpu_device()
1844
                >>> dev.global_mem_cache_type
1845
                <global_mem_cache_type.read_write: 4>
1846

1847
        Returns:
1848
            global_mem_cache_type:
1849
                type of cache memory
1850

1851
        Raises:
1852
            RuntimeError:
1853
                If an unrecognized memory type is reported by runtime.
1854
        """
1855
        cdef _global_mem_cache_type gmcTy = (
1856
           DPCTLDevice_GetGlobalMemCacheType(self._device_ref)
1✔
1857
        )
1858
        if gmcTy == _global_mem_cache_type._MEM_CACHE_TYPE_READ_WRITE:
1✔
1859
            return global_mem_cache_type.read_write
1✔
1860
        elif gmcTy == _global_mem_cache_type._MEM_CACHE_TYPE_READ_ONLY:
1861
            return global_mem_cache_type.read_only
×
1862
        elif gmcTy == _global_mem_cache_type._MEM_CACHE_TYPE_NONE:
1863
            return global_mem_cache_type.none
×
1864
        elif gmcTy == _global_mem_cache_type._MEM_CACHE_TYPE_INDETERMINATE:
1865
            raise RuntimeError("Unrecognized global memory cache type reported")
×
1866

1867
    @property
1868
    def global_mem_cache_size(self):
1869
        """ Global device memory cache size.
1870

1871
        Returns:
1872
            int:
1873
                Cache size in bytes
1874
        """
1875
        cdef uint64_t cache_sz = DPCTLDevice_GetGlobalMemCacheSize(
1✔
1876
            self._device_ref
1877
        )
1878
        return cache_sz
1✔
1879

1880
    @property
1881
    def global_mem_cache_line_size(self):
1882
        """ Global device memory cache line size.
1883

1884
        Returns:
1885
            int:
1886
                Cache size in bytes
1887
        """
1888
        cdef uint64_t cache_line_sz = DPCTLDevice_GetGlobalMemCacheLineSize(
1✔
1889
            self._device_ref
1890
        )
1891
        return cache_line_sz
1✔
1892

1893
    @property
1894
    def partition_max_sub_devices(self):
1895
        """ The maximum number of sub-devices this :class:`dpctl.SyclDevice`
1896
        instance can be partitioned into. The value returned cannot exceed the
1897
        value returned by :attr:`dpctl.SyclDevice.max_compute_units`.
1898

1899
        Returns:
1900
            int:
1901
                The maximum number of sub-devices that can be created when this
1902
                device is partitioned. Zero value indicates that device can not
1903
                be partitioned.
1904
        """
1905
        cdef uint32_t max_part = DPCTLDevice_GetPartitionMaxSubDevices(
1✔
1906
            self._device_ref
1907
        )
1908
        return max_part
1✔
1909

1910
    cdef cpp_bool equals(self, SyclDevice other):
1✔
1911
        """ Returns ``True`` if the :class:`dpctl.SyclDevice` argument has the
1912
        same _device_ref as this SyclDevice.
1913

1914
        Args:
1915
            other (dpctl.SyclDevice):
1916
                A :class:`dpctl.SyclDevice` instance to
1917
                compare against.
1918

1919
        Returns:
1920
            bool:
1921
                ``True`` if the devices point to the same underlying
1922
                ``sycl::device``, otherwise ``False``.
1923
        """
1924
        return DPCTLDevice_AreEq(self._device_ref, other.get_device_ref())
1✔
1925

1926
    def __eq__(self, other):
1927
        "Returns ``True`` if two devices are the same"
1928
        if isinstance(other, SyclDevice):
1✔
1929
            return self.equals(<SyclDevice> other)
1✔
1930
        else:
1931
            return False
1✔
1932

1933
    @property
1934
    def filter_string(self):
1935
        """ For a root device, returns a fully specified filter selector
1936
        string ``"backend:device_type:relative_id"`` selecting the device.
1937

1938
        Returns:
1939
            str:
1940
                A Python string representing a filter selector string.
1941

1942
        Raises:
1943
            ValueError:
1944
                If the device is a sub-device.
1945

1946
        :Example:
1947
            .. code-block:: python
1948

1949
                import dpctl
1950

1951
                # Create a SyclDevice with an explicit filter string,
1952
                # in this case the first level_zero gpu device.
1953
                level_zero_gpu = dpctl.SyclDevice("level_zero:gpu:0")
1954
                # filter_string property should be "level_zero:gpu:0"
1955
                dev = dpctl.SyclDevice(level_zero_gpu.filter_string)
1956
                assert level_zero_gpu == dev
1957
        """
1958
        cdef DPCTLSyclDeviceRef pDRef = NULL
1✔
1959
        pDRef = DPCTLDevice_GetParentDevice(self._device_ref)
1✔
1960
        if (pDRef is NULL):
1✔
1961
            return _cached_filter_string(self)
1✔
1962
        else:
1963
            # this a sub-device, free it, and raise an exception
1964
            DPCTLDevice_Delete(pDRef)
×
1965
            raise ValueError("This SyclDevice is not a root device")
×
1966

1967
    cdef int get_backend_and_device_type_ordinal(self):
1✔
1968
        """ If this device is a root ``sycl::device``, returns the ordinal
1969
        position of this device in the vector
1970
        ``sycl::device::get_devices(device_type_of_this_device)``
1971
        filtered to contain only devices with the same backend as this
1972
        device.
1973

1974
        Returns -1 if the device is a sub-device, or the device could not
1975
        be found in the vector.
1976
        """
1977
        cdef int64_t relId = DPCTLDeviceMgr_GetRelativeId(self._device_ref)
1✔
1978
        return relId
1✔
1979

1980
    cdef int get_device_type_ordinal(self):
1✔
1981
        """ If this device is a root ``sycl::device``, returns the ordinal
1982
        position of this device in the vector
1983
        ``sycl::device::get_devices(device_type_of_this_device)``
1984

1985
        Returns -1 if the device is a sub-device, or the device could not
1986
        be found in the vector.
1987
        """
1988
        cdef _device_type DTy
1989
        cdef int64_t relId = -1
1✔
1990

1991
        DTy = DPCTLDevice_GetDeviceType(self._device_ref)
1✔
1992
        relId = DPCTLDeviceMgr_GetPositionInDevices(self._device_ref, DTy)
1✔
1993
        return relId
1✔
1994

1995
    cdef int get_backend_ordinal(self):
1✔
1996
        """ If this device is a root ``sycl::device``, returns the ordinal
1997
        position of this device in the vector ``sycl::device::get_devices()``
1998
        filtered to contain only devices with the same backend as this
1999
        device.
2000

2001
        Returns -1 if the device is a sub-device, or the device could not
2002
        be found in the vector.
2003
        """
2004
        cdef _backend_type BTy
2005
        cdef int64_t relId = -1
1✔
2006

2007
        BTy = DPCTLDevice_GetBackend(self._device_ref)
1✔
2008
        relId = DPCTLDeviceMgr_GetPositionInDevices(self._device_ref, BTy)
1✔
2009
        return relId
1✔
2010

2011
    cdef int get_overall_ordinal(self):
1✔
2012
        """ If this device is a root ``sycl::device``, returns the ordinal
2013
        position of this device in the vector ``sycl::device::get_devices()``.
2014

2015
        Returns -1 if the device is a sub-device, or the device could not
2016
        be found in the vector.
2017
        """
2018
        cdef int64_t relId = -1
1✔
2019

2020
        relId = DPCTLDeviceMgr_GetPositionInDevices(
1✔
2021
            self._device_ref,
2022
            (_backend_type._ALL_BACKENDS | _device_type._ALL_DEVICES)
2023
        )
2024
        return relId
1✔
2025

2026
    def get_filter_string(self, include_backend=True, include_device_type=True):
1✔
2027
        """ get_filter_string(include_backend=True, include_device_type=True)
2028

2029
        For a parent device, returns a filter selector string
2030
        that includes backend or device type based on the value
2031
        of the given keyword arguments.
2032

2033
        Args:
2034
            include_backend (bool, optional):
2035
                A flag indicating if the backend should be included in
2036
                the filter string. Default: ``True``.
2037
            include_device_type (bool, optional):
2038
                A flag indicating if the device type should be included
2039
                in the filter string. Default: ``True``.
2040

2041
        Returns:
2042
            str:
2043
                A Python string representing a filter selector string.
2044

2045
        Raises:
2046
            ValueError:
2047
                If the device is a sub-device.
2048

2049
                If no match for the device was found in the vector
2050
                returned by ``sycl::device::get_devices()``
2051

2052
        :Example:
2053
            .. code-block:: python
2054

2055
                import dpctl
2056

2057
                # Create a GPU SyclDevice
2058
                gpu_dev = dpctl.SyclDevice("gpu:0")
2059
                # filter string should be "gpu:0"
2060
                fs = gpu_dev.get_filter_string(use_backend=False)
2061
                dev = dpctl.SyclDevice(fs)
2062
                assert gpu _dev == dev
2063
        """
2064
        cdef int relId = -1
1✔
2065
        cdef DPCTLSyclDeviceRef pDRef = NULL
1✔
2066
        cdef _device_type DTy
2067
        cdef _backend_type BTy
2068

2069
        if include_backend:
1✔
2070
            if include_device_type:
1✔
2071
                relId = self.get_backend_and_device_type_ordinal()
1✔
2072
            else:
2073
                relId = self.get_backend_ordinal()
1✔
2074
        else:
2075
            if include_device_type:
1✔
2076
                relId = self.get_device_type_ordinal()
1✔
2077
            else:
2078
                relId = self.get_overall_ordinal()
1✔
2079

2080
        if relId < 0:
1✔
2081
            pDRef = DPCTLDevice_GetParentDevice(self._device_ref)
×
2082
            if (pDRef is NULL):
×
2083
                raise ValueError
×
2084
            else:
2085
                # this a sub-device, free it, and raise an exception
2086
                DPCTLDevice_Delete(pDRef)
×
2087
                raise ValueError("This SyclDevice is not a root device")
×
2088
        else:
2089
            if include_backend:
1✔
2090
                BTy = DPCTLDevice_GetBackend(self._device_ref)
1✔
2091
                be_str = _backend_type_to_filter_string_part(BTy)
1✔
2092
                if include_device_type:
1✔
2093
                    DTy = DPCTLDevice_GetDeviceType(self._device_ref)
1✔
2094
                    dt_str = _device_type_to_filter_string_part(DTy)
1✔
2095
                    return ":".join((be_str, dt_str, str(relId)))
1✔
2096
                else:
2097
                    return ":".join((be_str, str(relId)))
1✔
2098
            else:
2099
                if include_device_type:
1✔
2100
                    DTy = DPCTLDevice_GetDeviceType(self._device_ref)
1✔
2101
                    dt_str = _device_type_to_filter_string_part(DTy)
1✔
2102
                    return ":".join((dt_str, str(relId)))
1✔
2103
                else:
2104
                    return str(relId)
1✔
2105

2106
    def get_unpartitioned_parent_device(self):
1✔
2107
        """ get_unpartitioned_parent_device()
2108

2109
        Returns the unpartitioned parent device of this device.
2110

2111
        If this device is already an unpartitioned, root device,
2112
        the same device is returned.
2113

2114
        Returns:
2115
            dpctl.SyclDevice:
2116
                A parent, unpartitioned :class:`dpctl.SyclDevice` instance, or
2117
                ``self`` if already a root device.
2118
        """
2119
        cdef DPCTLSyclDeviceRef pDRef = NULL
1✔
2120
        cdef DPCTLSyclDeviceRef tDRef = NULL
1✔
2121
        pDRef = DPCTLDevice_GetParentDevice(self._device_ref)
1✔
2122
        if pDRef is NULL:
1✔
2123
            return self
1✔
2124
        else:
2125
            tDRef = DPCTLDevice_GetParentDevice(pDRef)
1✔
2126
            while tDRef is not NULL:
1✔
2127
                DPCTLDevice_Delete(pDRef)
×
2128
                pDRef = tDRef
×
2129
                tDRef = DPCTLDevice_GetParentDevice(pDRef)
×
2130
            return SyclDevice._create(pDRef)
1✔
2131

2132
    def get_device_id(self):
1✔
2133
        """ get_device_id()
2134
        For an unpartitioned device, returns the canonical index of this device
2135
        in the list of devices visible to dpctl.
2136

2137
        Returns:
2138
            int:
2139
                The index of the device.
2140

2141
        Raises:
2142
            ValueError:
2143
                If the device could not be found.
2144

2145
        :Example:
2146
            .. code-block:: python
2147

2148
                import dpctl
2149
                gpu_dev = dpctl.SyclDevice("gpu")
2150
                i = gpu_dev.get_device_id
2151
                devs = dpctl.get_devices()
2152
                assert devs[i] == gpu_dev
2153
        """
2154
        cdef int dev_id = -1
1✔
2155
        cdef SyclDevice dev
2156

2157
        dev = self.get_unpartitioned_parent_device()
1✔
2158
        dev_id = dev.get_overall_ordinal()
1✔
2159
        if dev_id < 0:
1✔
2160
            raise ValueError("device could not be found")
×
2161
        return dev_id
1✔
2162

2163

2164
cdef api DPCTLSyclDeviceRef SyclDevice_GetDeviceRef(SyclDevice dev):
1✔
2165
    """
2166
    C-API function to get opaque device reference from
2167
    :class:`dpctl.SyclDevice` instance.
2168
    """
2169
    return dev.get_device_ref()
1✔
2170

2171

2172
cdef api SyclDevice SyclDevice_Make(DPCTLSyclDeviceRef DRef):
1✔
2173
    """
2174
    C-API function to create :class:`dpctl.SyclDevice` instance
2175
    from the given opaque device reference.
2176
    """
2177
    cdef DPCTLSyclDeviceRef copied_DRef = DPCTLDevice_Copy(DRef)
1✔
2178
    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