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

IntelPython / dpctl / 15911866840

26 Jun 2025 08:31PM UTC coverage: 85.892% (+0.005%) from 85.887%
15911866840

Pull #2116

github

web-flow
Merge 5df73ee62 into e11dea300
Pull Request #2116: Backport gh-2115 to master

3225 of 3876 branches covered (83.2%)

Branch coverage included in aggregate %.

12233 of 14121 relevant lines covered (86.63%)

6886.67 hits per line

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

75.74
/dpctl/_sycl_queue.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 SyclQueue Cython extension type.
22
"""
23

24
from ._backend cimport (  # noqa: E211
25
    DPCTLContext_Create,
26
    DPCTLContext_Delete,
27
    DPCTLDefaultSelector_Create,
28
    DPCTLDevice_Copy,
29
    DPCTLDevice_CreateFromSelector,
30
    DPCTLDevice_Delete,
31
    DPCTLDeviceMgr_GetCachedContext,
32
    DPCTLDeviceSelector_Delete,
33
    DPCTLEvent_Delete,
34
    DPCTLEvent_Wait,
35
    DPCTLFilterSelector_Create,
36
    DPCTLQueue_AreEq,
37
    DPCTLQueue_Copy,
38
    DPCTLQueue_Create,
39
    DPCTLQueue_Delete,
40
    DPCTLQueue_GetBackend,
41
    DPCTLQueue_GetContext,
42
    DPCTLQueue_GetDevice,
43
    DPCTLQueue_HasEnableProfiling,
44
    DPCTLQueue_Hash,
45
    DPCTLQueue_IsInOrder,
46
    DPCTLQueue_MemAdvise,
47
    DPCTLQueue_Memcpy,
48
    DPCTLQueue_MemcpyWithEvents,
49
    DPCTLQueue_Prefetch,
50
    DPCTLQueue_SubmitBarrierForEvents,
51
    DPCTLQueue_SubmitNDRange,
52
    DPCTLQueue_SubmitRange,
53
    DPCTLQueue_Wait,
54
    DPCTLRawKernelArg_Available,
55
    DPCTLRawKernelArg_Create,
56
    DPCTLRawKernelArg_Delete,
57
    DPCTLSyclContextRef,
58
    DPCTLSyclDeviceSelectorRef,
59
    DPCTLSyclEventRef,
60
    DPCTLWorkGroupMemory_Available,
61
    DPCTLWorkGroupMemory_Create,
62
    DPCTLWorkGroupMemory_Delete,
63
    _arg_data_type,
64
    _backend_type,
65
    _md_local_accessor,
66
    _queue_property_type,
67
)
68
from .memory._memory cimport _Memory
69

70
import ctypes
1✔
71
import numbers
1✔
72

73
from .enum_types import backend_type
1✔
74

75
from cpython cimport pycapsule
76
from cpython.buffer cimport (
77
    Py_buffer,
78
    PyBUF_ANY_CONTIGUOUS,
79
    PyBUF_SIMPLE,
80
    PyBUF_WRITABLE,
81
    PyBuffer_Release,
82
    PyObject_CheckBuffer,
83
    PyObject_GetBuffer,
84
)
85
from cpython.ref cimport Py_INCREF, PyObject
86
from libc.stdlib cimport free, malloc
87

88
import collections.abc
1✔
89
import logging
1✔
90

91

92
cdef extern from "_host_task_util.hpp":
93
    DPCTLSyclEventRef async_dec_ref(
94
        DPCTLSyclQueueRef, PyObject **,
95
        size_t, DPCTLSyclEventRef *, size_t, int *
96
    ) nogil
97

98

99
__all__ = [
1✔
100
    "SyclQueue",
101
    "SyclKernelInvalidRangeError",
102
    "SyclKernelSubmitError",
103
    "SyclQueueCreationError",
104
]
105

106

107
_logger = logging.getLogger(__name__)
1✔
108

109

110
cdef class kernel_arg_type_attribute:
111
    cdef str parent_name
112
    cdef str attr_name
113
    cdef int attr_value
114

115
    def __cinit__(self, str parent, str name, int value):
116
        self.parent_name = parent
1✔
117
        self.attr_name = name
1✔
118
        self.attr_value = value
1✔
119

120
    def __repr__(self):
121
        return f"<{self.parent_name}.{self.attr_name}: {self.attr_value}>"
1✔
122

123
    def __str__(self):
124
        return f"<{self.parent_name}.{self.attr_name}: {self.attr_value}>"
1✔
125

126
    @property
127
    def name(self):
128
        return self.attr_name
1✔
129

130
    @property
131
    def value(self):
132
        return self.attr_value
1✔
133

134

135
cdef class LocalAccessor:
136
    """
137
    LocalAccessor(dtype, shape)
138

139
    Python class for specifying the dimensionality and type of a
140
    ``sycl::local_accessor``, to be used as a kernel argument type.
141

142
    Args:
143
        dtype (str):
144
            the data type of the local memory.
145
            The permitted values are
146

147
                `'i1'`, `'i2'`, `'i4'`, `'i8'`:
148
                    signed integral types int8_t, int16_t, int32_t, int64_t
149
                `'u1'`, `'u2'`, `'u4'`, `'u8'`
150
                    unsigned integral types uint8_t, uint16_t, uint32_t,
151
                    uint64_t
152
                `'f4'`, `'f8'`,
153
                    single- and double-precision floating-point types float and
154
                    double
155
        shape (tuple, list):
156
            Size of LocalAccessor dimensions. Dimension of the LocalAccessor is
157
            determined by the length of the tuple. Must be of length 1, 2, or 3,
158
            and contain only non-negative integers.
159

160
    Raises:
161
        TypeError:
162
            If the given shape is not a tuple or list.
163
        ValueError:
164
            If the given shape sequence is not between one and
165
            three elements long.
166
        TypeError:
167
            If the shape is not a sequence of integers.
168
        ValueError:
169
            If the shape contains a negative integer.
170
        ValueError:
171
            If the dtype string is unrecognized.
172
    """
173
    cdef _md_local_accessor lacc
174

175
    def __cinit__(self, str dtype, shape):
176
        if not isinstance(shape, (list, tuple)):
×
177
            raise TypeError(
×
178
                f"`shape` must be a list or tuple, got {type(shape)}"
×
179
            )
180
        ndim = len(shape)
×
181
        if ndim < 1 or ndim > 3:
×
182
            raise ValueError(
×
183
                "LocalAccessor must have dimension between one and three"
184
            )
185
        for s in shape:
×
186
            if not isinstance(s, numbers.Integral):
×
187
                raise TypeError(
×
188
                    "LocalAccessor shape must be a sequence of integers"
189
                )
190
            if s < 0:
×
191
                raise ValueError(
×
192
                    "LocalAccessor dimensions must be non-negative"
193
                )
194
        self.lacc.ndim = ndim
×
195
        self.lacc.dim0 = <size_t> shape[0]
×
196
        self.lacc.dim1 = <size_t> shape[1] if ndim > 1 else 1
×
197
        self.lacc.dim2 = <size_t> shape[2] if ndim > 2 else 1
×
198

199
        if dtype == "i1":
×
200
            self.lacc.dpctl_type_id = _arg_data_type._INT8_T
×
201
        elif dtype == "u1":
×
202
            self.lacc.dpctl_type_id = _arg_data_type._UINT8_T
×
203
        elif dtype == "i2":
×
204
            self.lacc.dpctl_type_id = _arg_data_type._INT16_T
×
205
        elif dtype == "u2":
×
206
            self.lacc.dpctl_type_id = _arg_data_type._UINT16_T
×
207
        elif dtype == "i4":
×
208
            self.lacc.dpctl_type_id = _arg_data_type._INT32_T
×
209
        elif dtype == "u4":
×
210
            self.lacc.dpctl_type_id = _arg_data_type._UINT32_T
×
211
        elif dtype == "i8":
×
212
            self.lacc.dpctl_type_id = _arg_data_type._INT64_T
×
213
        elif dtype == "u8":
×
214
            self.lacc.dpctl_type_id = _arg_data_type._UINT64_T
×
215
        elif dtype == "f4":
×
216
            self.lacc.dpctl_type_id = _arg_data_type._FLOAT
×
217
        elif dtype == "f8":
×
218
            self.lacc.dpctl_type_id = _arg_data_type._DOUBLE
×
219
        else:
220
            raise ValueError(f"Unrecognized type value: '{dtype}'")
×
221

222
    def __repr__(self):
223
        return f"LocalAccessor({self.lacc.ndim})"
×
224

225
    cdef size_t addressof(self):
1✔
226
        """
227
        Returns the address of the _md_local_accessor for this LocalAccessor
228
        cast to ``size_t``.
229
        """
230
        return <size_t>&self.lacc
×
231

232

233
cdef class _kernel_arg_type:
234
    """
235
    An enumeration of supported kernel argument types in
236
    :func:`dpctl.SyclQueue.submit`
237
    """
238
    cdef str _name
239

240
    def __cinit__(self):
241
        self._name = "kernel_arg_type"
1✔
242

243
    @property
244
    def __name__(self):
245
        return self._name
1✔
246

247
    def __repr__(self):
248
        return "<enum 'kernel_arg_type'>"
1✔
249

250
    def __str__(self):
251
        return "<enum 'kernel_arg_type'>"
1✔
252

253
    @property
254
    def dpctl_int8(self):
255
        cdef str p_name = "dpctl_int8"
1✔
256
        return kernel_arg_type_attribute(
1✔
257
            self._name,
258
            p_name,
259
            _arg_data_type._INT8_T
1✔
260
        )
261

262
    @property
263
    def dpctl_uint8(self):
264
        cdef str p_name = "dpctl_uint8"
1✔
265
        return kernel_arg_type_attribute(
1✔
266
            self._name,
267
            p_name,
268
            _arg_data_type._UINT8_T
1✔
269
        )
270

271
    @property
272
    def dpctl_int16(self):
273
        cdef str p_name = "dpctl_int16"
1✔
274
        return kernel_arg_type_attribute(
1✔
275
            self._name,
276
            p_name,
277
            _arg_data_type._INT16_T
1✔
278
        )
279

280
    @property
281
    def dpctl_uint16(self):
282
        cdef str p_name = "dpctl_uint16"
1✔
283
        return kernel_arg_type_attribute(
1✔
284
            self._name,
285
            p_name,
286
            _arg_data_type._UINT16_T
1✔
287
        )
288

289
    @property
290
    def dpctl_int32(self):
291
        cdef str p_name = "dpctl_int32"
1✔
292
        return kernel_arg_type_attribute(
1✔
293
            self._name,
294
            p_name,
295
            _arg_data_type._INT32_T
1✔
296
        )
297

298
    @property
299
    def dpctl_uint32(self):
300
        cdef str p_name = "dpctl_uint32"
1✔
301
        return kernel_arg_type_attribute(
1✔
302
            self._name,
303
            p_name,
304
            _arg_data_type._UINT32_T
1✔
305
        )
306

307
    @property
308
    def dpctl_int64(self):
309
        cdef str p_name = "dpctl_int64"
1✔
310
        return kernel_arg_type_attribute(
1✔
311
            self._name,
312
            p_name,
313
            _arg_data_type._INT64_T
1✔
314
        )
315

316
    @property
317
    def dpctl_uint64(self):
318
        cdef str p_name = "dpctl_uint64"
1✔
319
        return kernel_arg_type_attribute(
1✔
320
            self._name,
321
            p_name,
322
            _arg_data_type._UINT64_T
1✔
323
        )
324

325
    @property
326
    def dpctl_float32(self):
327
        cdef str p_name = "dpctl_float32"
1✔
328
        return kernel_arg_type_attribute(
1✔
329
            self._name,
330
            p_name,
331
            _arg_data_type._FLOAT
1✔
332
        )
333

334
    @property
335
    def dpctl_float64(self):
336
        cdef str p_name = "dpctl_float64"
1✔
337
        return kernel_arg_type_attribute(
1✔
338
            self._name,
339
            p_name,
340
            _arg_data_type._DOUBLE
1✔
341
        )
342

343
    @property
344
    def dpctl_void_ptr(self):
345
        cdef str p_name = "dpctl_void_ptr"
1✔
346
        return kernel_arg_type_attribute(
1✔
347
            self._name,
348
            p_name,
349
            _arg_data_type._VOID_PTR
1✔
350
        )
351

352
    @property
353
    def dpctl_local_accessor(self):
354
        cdef str p_name = "dpctl_local_accessor"
1✔
355
        return kernel_arg_type_attribute(
1✔
356
            self._name,
357
            p_name,
358
            _arg_data_type._LOCAL_ACCESSOR
1✔
359
        )
360

361
    @property
362
    def dpctl_work_group_memory(self):
363
        cdef str p_name = "dpctl_work_group_memory"
1✔
364
        return kernel_arg_type_attribute(
1✔
365
            self._name,
366
            p_name,
367
            _arg_data_type._WORK_GROUP_MEMORY
1✔
368
        )
369

370
    @property
371
    def dpctl_raw_kernel_arg(self):
372
        cdef str p_name = "dpctl_raw_kernel_arg"
1✔
373
        return kernel_arg_type_attribute(
1✔
374
            self._name,
375
            p_name,
376
            _arg_data_type._RAW_KERNEL_ARG
1✔
377
        )
378

379

380
kernel_arg_type = _kernel_arg_type()
1✔
381

382

383
cdef class SyclKernelSubmitError(Exception):
384
    """
385
    A ``SyclKernelSubmitError`` exception is raised when
386
    the provided :class:`.program.SyclKernel` could not be
387
    submitted to the :class:`.SyclQueue`.
388

389
    """
390
    pass
391

392

393
cdef class SyclKernelInvalidRangeError(Exception):
394
    """
395
    A ``SyclKernelInvalidRangeError`` is raised when the provided
396
    range has less than one or more than three dimensions.
397
    """
398
    pass
399

400

401
cdef class SyclQueueCreationError(Exception):
402
    """
403
    A ``SyclQueueCreationError`` exception is raised when a
404
    :class:`.SyclQueue` could not be created.
405

406
    :class:`.SyclQueue` creation can fail if the filter
407
    string is invalid, or the backend or device type values are not supported.
408

409
    """
410
    pass
411

412

413
cdef int _parse_queue_properties(object prop) except *:
1✔
414
    cdef int res = 0
1✔
415
    cdef object props
416
    if isinstance(prop, int):
1✔
417
        return <int>prop
1✔
418
    if not isinstance(prop, (tuple, list)):
1✔
419
        props = (prop, )
1✔
420
    else:
421
        props = prop
1✔
422
    for p in props:
1✔
423
        if isinstance(p, int):
1✔
424
            res = res | <int> p
1✔
425
        elif isinstance(p, str):
1✔
426
            if (p == "in_order"):
1✔
427
                res = res | _queue_property_type._IN_ORDER
1✔
428
            elif (p == "enable_profiling"):
1✔
429
                res = res | _queue_property_type._ENABLE_PROFILING
1✔
430
            elif (p == "default"):
1✔
431
                res = res | _queue_property_type._DEFAULT_PROPERTY
1✔
432
            else:
433
                raise ValueError(
1✔
434
                    (
435
                        "queue property '{}' is not understood, "
436
                        "expecting 'in_order', 'enable_profiling', or 'default'"
437
                    ).format(prop)
1✔
438
                )
439
        else:
440
            raise ValueError(
1✔
441
                "queue property '{}' is not understood.".format(prop)
1✔
442
            )
443
    return res
1✔
444

445

446
cdef void _queue_capsule_deleter(object o) noexcept:
1✔
447
    cdef DPCTLSyclQueueRef QRef = NULL
1✔
448
    if pycapsule.PyCapsule_IsValid(o, "SyclQueueRef"):
1✔
449
        QRef = <DPCTLSyclQueueRef> pycapsule.PyCapsule_GetPointer(
1✔
450
            o, "SyclQueueRef"
451
        )
452
        DPCTLQueue_Delete(QRef)
1✔
453
    elif pycapsule.PyCapsule_IsValid(o, "used_SyclQueueRef"):
1✔
454
        QRef = <DPCTLSyclQueueRef> pycapsule.PyCapsule_GetPointer(
1✔
455
            o, "used_SyclQueueRef"
456
        )
457
        DPCTLQueue_Delete(QRef)
1✔
458

459

460
cdef bint _is_buffer(object o):
1✔
461
    return PyObject_CheckBuffer(o)
1✔
462

463

464
cdef DPCTLSyclEventRef _memcpy_impl(
1✔
465
     SyclQueue q,
466
     object dst,
467
     object src,
468
     size_t byte_count,
469
     DPCTLSyclEventRef *dep_events,
470
     size_t dep_events_count
471
) except *:
472
    cdef void *c_dst_ptr = NULL
1✔
473
    cdef void *c_src_ptr = NULL
1✔
474
    cdef DPCTLSyclEventRef ERef = NULL
1✔
475
    cdef Py_buffer src_buf_view
476
    cdef Py_buffer dst_buf_view
477
    cdef bint src_is_buf = False
1✔
478
    cdef bint dst_is_buf = False
1✔
479
    cdef int ret_code = 0
1✔
480

481
    if isinstance(src, _Memory):
1✔
482
        c_src_ptr = <void*>(<_Memory>src).get_data_ptr()
1✔
483
    elif _is_buffer(src):
1✔
484
        ret_code = PyObject_GetBuffer(
1✔
485
            src, &src_buf_view, PyBUF_SIMPLE | PyBUF_ANY_CONTIGUOUS
486
        )
487
        if ret_code != 0:  # pragma: no cover
488
            raise RuntimeError("Could not access buffer")
×
489
        c_src_ptr = src_buf_view.buf
1✔
490
        src_is_buf = True
1✔
491
    else:
492
        raise TypeError(
1✔
493
             "Parameter `src` should have either type "
494
             "`dpctl.memory._Memory` or a type that "
495
             "supports Python buffer protocol"
496
        )
497

498
    if isinstance(dst, _Memory):
1✔
499
        c_dst_ptr = <void*>(<_Memory>dst).get_data_ptr()
1✔
500
    elif _is_buffer(dst):
1✔
501
        ret_code = PyObject_GetBuffer(
1✔
502
            dst, &dst_buf_view,
503
            PyBUF_SIMPLE | PyBUF_ANY_CONTIGUOUS | PyBUF_WRITABLE
504
        )
505
        if ret_code != 0:  # pragma: no cover
506
            if src_is_buf:
×
507
                PyBuffer_Release(&src_buf_view)
×
508
            raise RuntimeError("Could not access buffer")
×
509
        c_dst_ptr = dst_buf_view.buf
1✔
510
        dst_is_buf = True
1✔
511
    else:
512
        raise TypeError(
1✔
513
             "Parameter `dst` should have either type "
514
             "`dpctl.memory._Memory` or a type that "
515
             "supports Python buffer protocol"
516
        )
517

518
    if dep_events_count == 0 or dep_events is NULL:
1✔
519
        ERef = DPCTLQueue_Memcpy(q._queue_ref, c_dst_ptr, c_src_ptr, byte_count)
1✔
520
    else:
521
        ERef = DPCTLQueue_MemcpyWithEvents(
1✔
522
            q._queue_ref,
523
            c_dst_ptr,
524
            c_src_ptr,
525
            byte_count,
526
            dep_events,
527
            dep_events_count
1✔
528
        )
529

530
    if src_is_buf:
1✔
531
        PyBuffer_Release(&src_buf_view)
1✔
532
    if dst_is_buf:
1✔
533
        PyBuffer_Release(&dst_buf_view)
1✔
534

535
    return ERef
1✔
536

537

538
cdef class _SyclQueue:
539
    """ Barebone data owner class used by SyclQueue.
540
    """
541
    def __dealloc__(self):
542
        if (self._queue_ref):
1✔
543
            DPCTLQueue_Delete(self._queue_ref)
1✔
544
        # self._context is a Python object and will be GC-ed
545
        # self._device is a Python object
546

547

548
cdef class SyclQueue(_SyclQueue):
549
    """
550
    SyclQueue(*args, **kwargs)
551
    Python class representing ``sycl::queue``.
552

553
    There are multiple ways to create a :class:`dpctl.SyclQueue` object:
554

555
    - Invoking the constructor with no arguments creates a context using
556
      the default selector.
557

558
    :Example:
559
        .. code-block:: python
560

561
            import dpctl
562

563
            # Create a default SyclQueue
564
            q = dpctl.SyclQueue()
565
            print(q.sycl_device)
566

567
    - Invoking the constructor with specific filter selector string that
568
      creates a queue for the device corresponding to the filter string.
569

570
    :Example:
571
        .. code-block:: python
572

573
            import dpctl
574

575
            # Create in-order SyclQueue for either gpu, or cpu device
576
            q = dpctl.SyclQueue("gpu,cpu", property="in_order")
577
            print([q.sycl_device.is_gpu, q.sycl_device.is_cpu])
578

579
    - Invoking the constructor with a :class:`dpctl.SyclDevice` object
580
      creates a queue for that device, automatically finding/creating
581
      a :class:`dpctl.SyclContext` for the given device.
582

583
    :Example:
584
        .. code-block:: python
585

586
            import dpctl
587

588
            d = dpctl.SyclDevice("gpu")
589
            q = dpctl.SyclQueue(d)
590
            ctx = q.sycl_context
591
            print(q.sycl_device == d)
592
            print(any([ d == ctx_d for ctx_d in ctx.get_devices()]))
593

594
    - Invoking the constructor with a :class:`dpctl.SyclContext` and a
595
      :class:`dpctl.SyclDevice` creates a queue for given context and
596
      device.
597

598
    :Example:
599
        .. code-block:: python
600

601
            import dpctl
602

603
            # Create a CPU device using the opencl driver
604
            cpu_d = dpctl.SyclDevice("opencl:cpu")
605
            # Partition the CPU device into sub-devices with two cores each.
606
            sub_devices = cpu_d.create_sub_devices(partition=2)
607
            # Create a context common to all the sub-devices.
608
            ctx = dpctl.SyclContext(sub_devices)
609
            # create a queue for each sub-device using the common context
610
            queues = [dpctl.SyclQueue(ctx, sub_d) for sub_d in sub_devices]
611

612
    - Invoking the constructor with a named ``PyCapsule`` with the name
613
      **"SyclQueueRef"** that carries a pointer to a ``sycl::queue``
614
      object. The capsule will be renamed upon successful consumption
615
      to ensure one-time use. A new named capsule can be constructed by
616
      using :func:`dpctl.SyclQueue._get_capsule` method.
617

618
    Args:
619
        ctx (:class:`dpctl.SyclContext`, optional): Sycl context to create
620
            :class:`dpctl.SyclQueue` from. If not specified, a single-device
621
            context will be created from the specified device.
622
        dev (str, :class:`dpctl.SyclDevice`, capsule, optional): Sycl device
623
             to create :class:`dpctl.SyclQueue` from. If not specified, sycl
624
             device selected by ``sycl::default_selector`` is used.
625
             The argument must be explicitly specified if `ctxt` argument is
626
             provided.
627

628
             If `dev` is a named ``PyCapsule`` called **"SyclQueueRef"** and
629
             `ctxt` is not specified, :class:`dpctl.SyclQueue` instance is
630
             created from foreign `sycl::queue` object referenced by the
631
             capsule.
632
        property (str, tuple(str), list(str), optional): Defaults to None.
633
                The argument can be either "default", "in_order",
634
                "enable_profiling", or a tuple containing these.
635

636
    Raises:
637
        SyclQueueCreationError: If the :class:`dpctl.SyclQueue` object
638
                                creation failed.
639
        TypeError: In case of incorrect arguments given to constructors,
640
                   unexpected types of input arguments, or in the case the input
641
                   capsule contained a null pointer or could not be renamed.
642

643
    """
644
    def __cinit__(self, *args, **kwargs):
645
        cdef int len_args
646
        cdef int status = 0
1✔
647
        cdef const char *filter_c_str = NULL
1✔
648
        if len(args) > 2:
1✔
649
            raise TypeError(
1✔
650
                "SyclQueue constructor takes 0, 1, or 2 positinal arguments, "
651
                "but {} were given.".format(len(args))
1✔
652
            )
653
        props = _parse_queue_properties(
1✔
654
            kwargs.pop("property", _queue_property_type._DEFAULT_PROPERTY)
1✔
655
        )
656
        if (kwargs):
1✔
657
            raise TypeError(
1✔
658
                f"Unsupported keyword arguments {kwargs} to "
1✔
659
                "SyclQueue constructor encountered."
660
            )
661
        len_args = len(args)
1✔
662
        if len_args == 0:
1✔
663
            status = self._init_queue_default(props)
1✔
664
        elif len_args == 1:
665
            arg = args[0]
1✔
666
            if type(arg) is str:
1✔
667
                string = bytes(<str>arg, "utf-8")
1✔
668
                filter_c_str = string
1✔
669
                status = self._init_queue_from_filter_string(
1✔
670
                    filter_c_str, props)
671
            elif type(arg) is _SyclQueue:
1✔
672
                status = self._init_queue_from__SyclQueue(<_SyclQueue>arg)
1✔
673
            elif isinstance(arg, SyclDevice):
1✔
674
                status = self._init_queue_from_device(<SyclDevice>arg, props)
1✔
675
            elif pycapsule.PyCapsule_IsValid(arg, "SyclQueueRef"):
1✔
676
                status = self._init_queue_from_capsule(arg)
1✔
677
            else:
678
                raise TypeError(
1✔
679
                    "Positional argument {} is not a filter string or a "
680
                    "SyclDevice".format(arg)
1✔
681
                )
682
        else:
683
            ctx, dev = args
1✔
684
            if not isinstance(ctx, SyclContext):
1✔
685
                raise TypeError(
1✔
686
                    "SyclQueue constructor with two positional arguments "
687
                    "expected SyclContext as its first argument, but got {}."
688
                    .format(type(ctx))
1✔
689
                )
690
            if not isinstance(dev, SyclDevice):
1✔
691
                raise TypeError(
1✔
692
                    "SyclQueue constructor with two positional arguments "
693
                    "expected SyclDevice as its second argument, but got {}."
694
                    .format(type(dev))
1✔
695
                )
696
            status = self._init_queue_from_context_and_device(
1✔
697
                <SyclContext>ctx, <SyclDevice>dev, props
698
            )
699
        if status < 0:
1✔
700
            if status == -1:
1✔
701
                raise SyclQueueCreationError(
1✔
702
                    "Device filter selector string '{}' is not understood."
703
                    .format(arg)
1✔
704
                )
705
            elif status == -2 or status == -8:
1✔
706
                default_dev_error = (
707
                    "Default SYCL Device could not be created."
1✔
708
                )
709
                raise SyclQueueCreationError(
1✔
710
                    default_dev_error if (len_args == 0) else
1✔
711
                    "SYCL Device '{}' could not be created.".format(arg)
1✔
712
                )
713
            elif status == -3 or status == -7:
×
714
                raise SyclQueueCreationError(
×
715
                    "SYCL Context could not be created " +
716
                    "by default constructor" if len_args == 0 else
×
717
                    "from '{}'.".format(arg)
×
718
                )
719
            elif status == -4 or status == -6:
1✔
720
                if len_args == 2:
1✔
721
                    arg = args
1✔
722
                raise SyclQueueCreationError(
1✔
723
                    "SYCL Queue failed to be created from '{}'.".format(arg)
1✔
724
                )
725
            elif status == -5:
726
                raise TypeError(
×
727
                    "Input capsule {} contains a null pointer or could not "
728
                    "be renamed".format(arg)
×
729
                )
730

731
    cdef int _init_queue_from__SyclQueue(self, _SyclQueue other):
1✔
732
        """ Copy data container _SyclQueue fields over.
733
        """
734
        cdef DPCTLSyclQueueRef QRef = DPCTLQueue_Copy(other._queue_ref)
1✔
735
        if (QRef is NULL):
1✔
736
            return -4
×
737
        self._queue_ref = QRef
1✔
738
        self._context = other._context
1✔
739
        self._device = other._device
1✔
740

741
    cdef int _init_queue_from_DPCTLSyclDeviceRef(
1✔
742
        self, DPCTLSyclDeviceRef DRef, int props
743
    ):
744
        """
745
        Initializes self by creating SyclQueue with specified error handler and
746
        specified properties from the given device instance. SyclContext is
747
        looked-up by DPCTL from a cache to avoid repeated construction of new
748
        context for performance reasons.
749

750
        Returns: 0 : normal execution
751
                -3 : Context creation/look-up failed
752
                -4 : queue could not be created from context,device, error
753
                     handler and properties
754
        """
755
        cdef DPCTLSyclContextRef CRef
756
        cdef DPCTLSyclQueueRef QRef
757

758
        CRef = DPCTLDeviceMgr_GetCachedContext(DRef)
1✔
759
        if (CRef is NULL):
1✔
760
            # look-up failed (was not a root device?)
761
            # create a new context
762
            CRef = DPCTLContext_Create(DRef, NULL, 0)
1✔
763
            if (CRef is NULL):
1✔
764
                DPCTLDevice_Delete(DRef)
×
765
                return -3
×
766
        QRef = DPCTLQueue_Create(
1✔
767
            CRef,
768
            DRef,
769
            NULL,
770
            props
771
        )
772
        if QRef is NULL:
1✔
773
            DPCTLContext_Delete(CRef)
×
774
            DPCTLDevice_Delete(DRef)
×
775
            return -4
×
776
        _dev = SyclDevice._create(DRef)
1✔
777
        _ctxt = SyclContext._create(CRef)
1✔
778
        self._device = _dev
1✔
779
        self._context = _ctxt
1✔
780
        self._queue_ref = QRef
1✔
781
        return 0  # normal return
1✔
782

783
    cdef int _init_queue_from_filter_string(self, const char *c_str, int props):
1✔
784
        """
785
        Initializes self from filter string, error handler and properties.
786
        Creates device from device selector, then calls helper function above.
787

788
        Returns:
789
             0 : normal execution
790
            -1 : filter selector could not be created (malformed?)
791
            -2 : Device could not be created from filter selector
792
            -3 : Context creation/look-up failed
793
            -4 : queue could not be created from context,device, error handler
794
                 and properties
795
        """
796
        cdef DPCTLSyclDeviceSelectorRef DSRef = NULL
1✔
797
        cdef DPCTLSyclDeviceRef DRef = NULL
1✔
798
        cdef int ret = 0
1✔
799

800
        DSRef = DPCTLFilterSelector_Create(c_str)
1✔
801
        if DSRef is NULL:
1✔
802
            ret = -1  # Filter selector failed to be created
1✔
803
        else:
804
            DRef = DPCTLDevice_CreateFromSelector(DSRef)
1✔
805
            DPCTLDeviceSelector_Delete(DSRef)
1✔
806
            if (DRef is NULL):
1✔
807
                ret = -2  # Device could not be created
1✔
808
            else:
809
                ret = self._init_queue_from_DPCTLSyclDeviceRef(DRef, props)
1✔
810
        return ret
1✔
811

812
    cdef int _init_queue_from_device(self, SyclDevice dev, int props):
1✔
813
        cdef DPCTLSyclDeviceRef DRef = NULL
1✔
814
        # The DRef will be stored in self._device and freed when self._device
815
        # is garbage collected.
816
        DRef = DPCTLDevice_Copy(dev.get_device_ref())
1✔
817
        if (DRef is NULL):
1✔
818
            return -2  # Device could not be created
×
819
        else:
820
            return self._init_queue_from_DPCTLSyclDeviceRef(DRef, props)
1✔
821

822
    cdef int _init_queue_default(self, int props):
1✔
823
        cdef DPCTLSyclDeviceSelectorRef DSRef = DPCTLDefaultSelector_Create()
1✔
824
        cdef int ret = 0
1✔
825
        # The DRef will be stored in self._device and freed when self._device
826
        # is garbage collected.
827
        DRef = DPCTLDevice_CreateFromSelector(DSRef)
1✔
828
        DPCTLDeviceSelector_Delete(DSRef)
1✔
829
        if (DRef is NULL):
1✔
830
            ret = -2  # Device could not be created
×
831
        else:
832
            ret = self._init_queue_from_DPCTLSyclDeviceRef(DRef, props)
1✔
833
        return ret
1✔
834

835
    cdef int _init_queue_from_context_and_device(
1✔
836
        self, SyclContext ctxt, SyclDevice dev, int props
837
    ):
838
        cdef DPCTLSyclContextRef CRef = NULL
1✔
839
        cdef DPCTLSyclDeviceRef DRef = NULL
1✔
840
        cdef DPCTLSyclQueueRef QRef = NULL
1✔
841
        CRef = ctxt.get_context_ref()
1✔
842
        DRef = dev.get_device_ref()
1✔
843
        QRef = DPCTLQueue_Create(
1✔
844
            CRef,
845
            DRef,
846
            NULL,
847
            props
848
        )
849
        if (QRef is NULL):
1✔
850
            return -4
1✔
851
        self._device = dev
1✔
852
        self._context = ctxt
1✔
853
        self._queue_ref = QRef
1✔
854
        return 0  # normal return
1✔
855

856
    cdef int _init_queue_from_capsule(self, object cap):
1✔
857
        """
858
        For named PyCapsule with name "SyclQueueRef", which carries pointer to
859
        ``sycl::queue`` object, interpreted as ``DPCTLSyclQueueRef``, creates
860
        corresponding :class:`.SyclQueue`.
861
        """
862
        cdef DPCTLSyclContextRef CRef = NULL
1✔
863
        cdef DPCTLSyclDeviceRef DRef = NULL
1✔
864
        cdef DPCTLSyclQueueRef QRef = NULL
1✔
865
        cdef DPCTLSyclQueueRef QRef_copy = NULL
1✔
866
        cdef int ret = 0
1✔
867
        if pycapsule.PyCapsule_IsValid(cap, "SyclQueueRef"):
1✔
868
            QRef = <DPCTLSyclQueueRef> pycapsule.PyCapsule_GetPointer(
1✔
869
                cap, "SyclQueueRef"
870
            )
871
            if (QRef is NULL):
1✔
872
                return -5
×
873
            ret = pycapsule.PyCapsule_SetName(cap, "used_SyclQueueRef")
1✔
874
            if (ret):
1✔
875
                return -5
×
876
            QRef_copy = DPCTLQueue_Copy(QRef)
1✔
877
            if (QRef_copy is NULL):
1✔
878
                return -6
×
879
            CRef = DPCTLQueue_GetContext(QRef_copy)
1✔
880
            if (CRef is NULL):
1✔
881
                DPCTLQueue_Delete(QRef_copy)
×
882
                return -7
×
883
            DRef = DPCTLQueue_GetDevice(QRef_copy)
1✔
884
            if (DRef is NULL):
1✔
885
                DPCTLContext_Delete(CRef)
×
886
                DPCTLQueue_Delete(QRef_copy)
×
887
                return -8
×
888
            self._context = SyclContext._create(CRef)
1✔
889
            self._device = SyclDevice._create(DRef)
1✔
890
            self._queue_ref = QRef_copy
1✔
891
            return 0
1✔
892
        else:
893
            # __cinit__ checks that capsule is valid, so one can be here only
894
            # if call to `_init_queue_from_capsule` was made outside of
895
            # __cinit__ and the capsule was not checked to be valid.
896
            return -128
×
897

898
    @staticmethod
1✔
899
    cdef SyclQueue _create(DPCTLSyclQueueRef qref):
900
        """
901
        This function calls ``DPCTLQueue_Delete(qref)``.
902
        The user of this function must pass a copy to keep the
903
        qref argument alive.
904
        """
905
        if qref is NULL:
1✔
906
            raise SyclQueueCreationError("Queue creation failed.")
×
907
        cdef _SyclQueue ret = _SyclQueue.__new__(_SyclQueue)
1✔
908
        ret._context = SyclContext._create(DPCTLQueue_GetContext(qref))
1✔
909
        ret._device = SyclDevice._create(DPCTLQueue_GetDevice(qref))
1✔
910
        ret._queue_ref = qref
1✔
911
        # ret is a temporary, and will call DPCTLQueue_Delete(qref)
912
        return SyclQueue(ret)
1✔
913

914
    @staticmethod
1✔
915
    cdef SyclQueue _create_from_context_and_device(
916
        SyclContext ctx, SyclDevice dev, int props=0
917
    ):
918
        """
919
        Static factory method to create :class:`dpctl.SyclQueue` instance
920
        from given :class:`dpctl.SyclContext`, :class:`dpctl.SyclDevice`
921
        and optional integer ``props`` encoding the queue properties.
922
        """
923
        cdef _SyclQueue ret = _SyclQueue.__new__(_SyclQueue)
1✔
924
        cdef DPCTLSyclContextRef cref = ctx.get_context_ref()
1✔
925
        cdef DPCTLSyclDeviceRef dref = dev.get_device_ref()
1✔
926
        cdef DPCTLSyclQueueRef qref = NULL
1✔
927

928
        qref = DPCTLQueue_Create(
1✔
929
            cref,
930
            dref,
931
            NULL,
932
            props
933
        )
934
        if qref is NULL:
1✔
935
            raise SyclQueueCreationError("Queue creation failed.")
×
936
        ret._queue_ref = qref
1✔
937
        ret._context = ctx
1✔
938
        ret._device = dev
1✔
939
        return SyclQueue(ret)
1✔
940

941
    cdef int _populate_args(
1✔
942
        self,
943
        list args,
944
        void **kargs,
945
        _arg_data_type *kargty
946
    ):
947
        cdef int ret = 0
1✔
948
        for idx, arg in enumerate(args):
1✔
949
            if isinstance(arg, ctypes.c_char):
1✔
950
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
×
951
                kargty[idx] = _arg_data_type._INT8_T
×
952
            elif isinstance(arg, ctypes.c_uint8):
1✔
953
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
×
954
                kargty[idx] = _arg_data_type._UINT8_T
×
955
            elif isinstance(arg, ctypes.c_short):
1✔
956
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
957
                kargty[idx] = _arg_data_type._INT16_T
1✔
958
            elif isinstance(arg, ctypes.c_ushort):
1✔
959
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
×
960
                kargty[idx] = _arg_data_type._UINT16_T
×
961
            elif isinstance(arg, ctypes.c_int):
1✔
962
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
963
                kargty[idx] = _arg_data_type._INT32_T
1✔
964
            elif isinstance(arg, ctypes.c_uint):
1✔
965
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
966
                kargty[idx] = _arg_data_type._UINT32_T
1✔
967
            elif isinstance(arg, ctypes.c_longlong):
1✔
968
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
969
                kargty[idx] = _arg_data_type._INT64_T
1✔
970
            elif isinstance(arg, ctypes.c_ulonglong):
1✔
971
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
972
                kargty[idx] = _arg_data_type._UINT64_T
1✔
973
            elif isinstance(arg, ctypes.c_float):
1✔
974
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
975
                kargty[idx] = _arg_data_type._FLOAT
1✔
976
            elif isinstance(arg, ctypes.c_double):
1✔
977
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
978
                kargty[idx] = _arg_data_type._DOUBLE
1✔
979
            elif isinstance(arg, _Memory):
1✔
980
                kargs[idx]= <void*>(<size_t>arg._pointer)
1✔
981
                kargty[idx] = _arg_data_type._VOID_PTR
1✔
982
            elif isinstance(arg, WorkGroupMemory):
1✔
983
                kargs[idx] = <void*>(<size_t>arg._ref)
1✔
984
                kargty[idx] = _arg_data_type._WORK_GROUP_MEMORY
1✔
985
            elif isinstance(arg, LocalAccessor):
×
986
                kargs[idx] = <void*>((<LocalAccessor>arg).addressof())
×
987
                kargty[idx] = _arg_data_type._LOCAL_ACCESSOR
×
988
            elif isinstance(arg, RawKernelArg):
×
989
                kargs[idx] = <void*>(<size_t>arg._ref)
×
990
                kargty[idx] = _arg_data_type._RAW_KERNEL_ARG
×
991
            else:
992
                ret = -1
×
993
        return ret
1✔
994

995
    cdef int _populate_range(self, size_t Range[3], list S, size_t nS):
1✔
996

997
        cdef int ret = 0
1✔
998

999
        if nS == 1:
1✔
1000
            Range[0] = <size_t>S[0]
1✔
1001
            Range[1] = 1
1✔
1002
            Range[2] = 1
1✔
1003
        elif nS == 2:
1004
            Range[0] = <size_t>S[0]
1✔
1005
            Range[1] = <size_t>S[1]
1✔
1006
            Range[2] = 1
1✔
1007
        elif nS == 3:
1008
            Range[0] = <size_t>S[0]
1✔
1009
            Range[1] = <size_t>S[1]
1✔
1010
            Range[2] = <size_t>S[2]
1✔
1011
        else:
1012
            ret = -1
×
1013

1014
        return ret
1✔
1015

1016
    cdef cpp_bool equals(self, SyclQueue q):
1✔
1017
        """ Returns true if the :class:`.SyclQueue` argument ``q`` has the
1018
            same ``._queue_ref`` attribute as this :class:`.SyclQueue`.
1019
        """
1020
        return DPCTLQueue_AreEq(self._queue_ref, q.get_queue_ref())
1✔
1021

1022
    def __eq__(self, other):
1023
        """
1024
        Returns True if two :class:`dpctl.SyclQueue` compared arguments have
1025
        the same underlying ``DPCTLSyclQueueRef`` object.
1026

1027
        Returns:
1028
            bool:
1029
                ``True`` if the two :class:`dpctl.SyclQueue` objects
1030
                point to the same ``DPCTLSyclQueueRef`` object, otherwise
1031
                ``False``.
1032
        """
1033
        if isinstance(other, SyclQueue):
1✔
1034
            return self.equals(<SyclQueue> other)
1✔
1035
        else:
1036
            return False
1✔
1037

1038
    @property
1039
    def backend(self):
1040
        """ Returns the ``backend_type`` enum value for this queue.
1041

1042
        Returns:
1043
            backend_type:
1044
                The backend for the queue.
1045
        """
1046
        cdef _backend_type BE = DPCTLQueue_GetBackend(self._queue_ref)
1✔
1047
        if BE == _backend_type._OPENCL:
1✔
1048
            return backend_type.opencl
1✔
1049
        elif BE == _backend_type._LEVEL_ZERO:
1050
            return backend_type.level_zero
×
1051
        elif BE == _backend_type._CUDA:
1052
            return backend_type.cuda
×
1053
        elif BE == _backend_type._HIP:
1054
            return backend_type.hip
×
1055
        else:
1056
            raise ValueError("Unknown backend type.")
×
1057

1058
    @property
1059
    def sycl_context(self):
1060
        """
1061
        Returns :class:`SyclContext` underlying this queue.
1062

1063
        Returns:
1064
            :class:`SyclContext`
1065
                SYCL context underlying this queue
1066
        """
1067
        return self._context
1✔
1068

1069
    @property
1070
    def sycl_device(self):
1071
        """
1072
        Returns :class:`.SyclDevice` targeted by this queue.
1073

1074
        Returns:
1075
            :class:`SyclDevice`
1076
                SYCL device targeted by this queue
1077
        """
1078
        return self._device
1✔
1079

1080
    cpdef SyclContext get_sycl_context(self):
1✔
1081
        return self._context
1✔
1082

1083
    cpdef SyclDevice get_sycl_device(self):
1✔
1084
        return self._device
1✔
1085

1086
    cdef DPCTLSyclQueueRef get_queue_ref(self):
1✔
1087
        return self._queue_ref
1✔
1088

1089
    def addressof_ref(self):
1✔
1090
        """
1091
        Returns the address of the C API ``DPCTLSyclQueueRef`` pointer as
1092
        integral value of type ``size_t``.
1093

1094
        Returns:
1095
            int:
1096
                The address of the ``DPCTLSyclQueueRef`` object used to create
1097
                this :class:`dpctl.SyclQueue` object cast to ``size_t`` type.
1098
        """
1099
        return <size_t>self._queue_ref
1✔
1100

1101
    cpdef SyclEvent _submit_keep_args_alive(
1✔
1102
        self,
1103
        object args,
1104
        list dEvents
1105
    ):
1106
        """ SyclQueue._submit_keep_args_alive(args, events)
1107

1108
        Keeps objects in ``args`` alive until tasks associated with events
1109
        complete.
1110

1111
        Args:
1112
            args(object):
1113
                Python object to keep alive.
1114
                Typically a tuple with arguments to offloaded tasks
1115
            events(Tuple[dpctl.SyclEvent]):
1116
                Gating events.
1117
                The list or tuple of events associated with tasks
1118
                working on Python objects collected in ``args``.
1119
        Returns:
1120
            dpctl.SyclEvent
1121
               The event associated with the submission of host task.
1122

1123
        Increments reference count of ``args`` and schedules asynchronous
1124
        ``host_task`` to decrement the count once dependent events are
1125
        complete.
1126

1127
        .. note::
1128
            The ``host_task`` attempts to acquire Python GIL, and it is
1129
            known to be unsafe during interpreter shutdown sequence. It is
1130
            thus strongly advised to ensure that all submitted ``host_task``
1131
            complete before the end of the Python script.
1132
        """
1133
        cdef size_t nDE = len(dEvents)
1✔
1134
        cdef DPCTLSyclEventRef *depEvents = NULL
1✔
1135
        cdef PyObject *args_raw = NULL
1✔
1136
        cdef DPCTLSyclEventRef htERef = NULL
1✔
1137
        cdef int status = -1
1✔
1138

1139
        # Create the array of dependent events if any
1140
        if nDE > 0:
1✔
1141
            depEvents = (
1142
                <DPCTLSyclEventRef*>malloc(nDE*sizeof(DPCTLSyclEventRef))
1✔
1143
            )
1144
            if not depEvents:
1✔
1145
                raise MemoryError()
×
1146
            else:
1147
                for idx, de in enumerate(dEvents):
1✔
1148
                    if isinstance(de, SyclEvent):
1✔
1149
                        depEvents[idx] = (<SyclEvent>de).get_event_ref()
1✔
1150
                    else:
1151
                        free(depEvents)
×
1152
                        raise TypeError(
×
1153
                            "A sequence of dpctl.SyclEvent is expected"
1154
                        )
1155

1156
        # increment reference counts to list of arguments
1157
        Py_INCREF(args)
1✔
1158

1159
        # schedule decrement
1160
        args_raw = <PyObject *>args
1✔
1161

1162
        htERef = async_dec_ref(
1✔
1163
            self.get_queue_ref(),
1✔
1164
            &args_raw, 1,
1165
            depEvents, nDE, &status
1166
        )
1167

1168
        free(depEvents)
1✔
1169
        if (status != 0):
1✔
1170
            with nogil:
×
1171
                DPCTLEvent_Wait(htERef)
×
1172
            DPCTLEvent_Delete(htERef)
×
1173
            raise RuntimeError("Could not submit keep_args_alive host_task")
×
1174

1175
        return SyclEvent._create(htERef)
1✔
1176

1177
    cpdef SyclEvent submit_async(
1✔
1178
        self,
1179
        SyclKernel kernel,
1180
        list args,
1181
        list gS,
1182
        list lS=None,
1183
        list dEvents=None
1✔
1184
    ):
1185
        """
1186
        Asynchronously submit :class:`dpctl.program.SyclKernel` for execution.
1187

1188
        Args:
1189
            kernel (dpctl.program.SyclKernel):
1190
                SYCL kernel object
1191
            args (List[object]):
1192
                List of kernel arguments
1193
            gS (List[int]):
1194
                Global iteration range. Must be a list of length 1, 2, or 3.
1195
            lS (List[int], optional):
1196
                Local iteration range. Must be ``None`` or have the same
1197
                length as ``gS`` and each element of ``gS`` must be divisible
1198
                by respective element of ``lS``.
1199
            dEvents (List[dpctl.SyclEvent], optional):
1200
                List of events indicating ordering of this task relative
1201
                to tasks associated with specified events.
1202

1203
        Returns:
1204
            dpctl.SyclEvent:
1205
                An event associated with submission of the kernel.
1206

1207
        .. note::
1208
            One must ensure that the lifetime of all kernel arguments
1209
            extends after the submitted task completes. It is not a concern for
1210
            scalar arguments since they are passed by value, but for
1211
            objects representing USM allocations which are passed to the kernel
1212
            as unified address space pointers.
1213

1214
            One way of accomplishing this is to use
1215
            :meth:`dpctl.SyclQueue._submit_keep_args_alive`.
1216
        """
1217
        cdef void **kargs = NULL
1✔
1218
        cdef _arg_data_type *kargty = NULL
1✔
1219
        cdef DPCTLSyclEventRef *depEvents = NULL
1✔
1220
        cdef DPCTLSyclEventRef Eref = NULL
1✔
1221
        cdef int ret = 0
1✔
1222
        cdef size_t gRange[3]
1223
        cdef size_t lRange[3]
1224
        cdef size_t nGS = len(gS)
1✔
1225
        cdef size_t nLS = len(lS) if lS is not None else 0
1✔
1226
        cdef size_t nDE = len(dEvents) if dEvents is not None else 0
1✔
1227

1228
        # Allocate the arrays to be sent to DPCTLQueue_Submit
1229
        kargs = <void**>malloc(len(args) * sizeof(void*))
1✔
1230
        if not kargs:
1✔
1231
            raise MemoryError()
×
1232
        kargty = (
1233
            <_arg_data_type*>malloc(len(args)*sizeof(_arg_data_type))
1✔
1234
        )
1235
        if not kargty:
1✔
1236
            free(kargs)
×
1237
            raise MemoryError()
×
1238
        # Create the array of dependent events if any
1239
        if dEvents is not None and nDE > 0:
1✔
1240
            depEvents = (
1241
                <DPCTLSyclEventRef*>malloc(nDE*sizeof(DPCTLSyclEventRef))
1✔
1242
            )
1243
            if not depEvents:
1✔
1244
                free(kargs)
×
1245
                free(kargty)
×
1246
                raise MemoryError()
×
1247
            else:
1248
                for idx, de in enumerate(dEvents):
1✔
1249
                    if isinstance(de, SyclEvent):
1✔
1250
                        depEvents[idx] = (<SyclEvent>de).get_event_ref()
1✔
1251
                    else:
1252
                        free(kargs)
×
1253
                        free(kargty)
×
1254
                        free(depEvents)
×
1255
                        raise TypeError(
×
1256
                            "A sequence of dpctl.SyclEvent is expected"
1257
                        )
1258

1259
        # populate the args and argstype arrays
1260
        ret = self._populate_args(args, kargs, kargty)
1✔
1261
        if ret == -1:
1✔
1262
            free(kargs)
×
1263
            free(kargty)
×
1264
            free(depEvents)
×
1265
            raise TypeError("Unsupported type for a kernel argument")
×
1266

1267
        if lS is None:
1✔
1268
            ret = self._populate_range(gRange, gS, nGS)
1✔
1269
            if ret == -1:
1✔
1270
                free(kargs)
×
1271
                free(kargty)
×
1272
                free(depEvents)
×
1273
                raise SyclKernelInvalidRangeError(
×
1274
                    "Range with ", nGS, " not allowed. Range can only have "
×
1275
                    "between one and three dimensions."
1276
                )
1277
            Eref = DPCTLQueue_SubmitRange(
1✔
1278
                kernel.get_kernel_ref(),
1✔
1279
                self.get_queue_ref(),
1✔
1280
                kargs,
1281
                kargty,
1282
                len(args),
1✔
1283
                gRange,
1284
                nGS,
1285
                depEvents,
1286
                nDE
1287
            )
1288
        else:
1289
            ret = self._populate_range(gRange, gS, nGS)
1✔
1290
            if ret == -1:
1✔
1291
                free(kargs)
×
1292
                free(kargty)
×
1293
                free(depEvents)
×
1294
                raise SyclKernelInvalidRangeError(
×
1295
                    "Range with ", nGS, " not allowed. Range can only have "
×
1296
                    "between one and three dimensions."
1297
                )
1298
            ret = self._populate_range(lRange, lS, nLS)
1✔
1299
            if ret == -1:
1✔
1300
                free(kargs)
×
1301
                free(kargty)
×
1302
                free(depEvents)
×
1303
                raise SyclKernelInvalidRangeError(
×
1304
                    "Range with ", nLS, " not allowed. Range can only have "
×
1305
                    "between one and three dimensions."
1306
                )
1307
            if nGS != nLS:
1✔
1308
                free(kargs)
×
1309
                free(kargty)
×
1310
                free(depEvents)
×
1311
                raise ValueError(
×
1312
                    "Local and global ranges need to have same "
1313
                    "number of dimensions."
1314
                )
1315
            Eref = DPCTLQueue_SubmitNDRange(
1✔
1316
                kernel.get_kernel_ref(),
1✔
1317
                self.get_queue_ref(),
1✔
1318
                kargs,
1319
                kargty,
1320
                len(args),
1✔
1321
                gRange,
1322
                lRange,
1323
                nGS,
1324
                depEvents,
1325
                nDE
1326
            )
1327
        free(kargs)
1✔
1328
        free(kargty)
1✔
1329
        free(depEvents)
1✔
1330

1331
        if Eref is NULL:
1✔
1332
            raise SyclKernelSubmitError(
×
1333
                "Kernel submission to Sycl queue failed."
1334
            )
1335

1336
        return SyclEvent._create(Eref)
1✔
1337

1338
    cpdef SyclEvent submit(
1✔
1339
        self,
1340
        SyclKernel kernel,
1341
        list args,
1342
        list gS,
1343
        list lS=None,
1344
        list dEvents=None
1✔
1345
    ):
1346
        """
1347
        Submit :class:`dpctl.program.SyclKernel` for execution.
1348

1349
        Args:
1350
            kernel (dpctl.program.SyclKernel):
1351
                SYCL kernel object
1352
            args (List[object]):
1353
                List of kernel arguments
1354
            gS (List[int]):
1355
                Global iteration range. Must be a list of length 1, 2, or 3.
1356
            lS (List[int], optional):
1357
                Local iteration range. Must be ``None`` or have the same
1358
                length as ``gS`` and each element of ``gS`` must be divisible
1359
                by respective element of ``lS``.
1360
            dEvents (List[dpctl.SyclEvent], optional):
1361
                List of events indicating ordering of this task relative
1362
                to tasks associated with specified events.
1363

1364
        Returns:
1365
            dpctl.SyclEvent:
1366
                An event which is always complete. May be ignored.
1367

1368
        .. note::
1369
            :meth:`dpctl.SyclQueue.submit` is a synchronizing method.
1370
            Use :meth:`dpctl.SyclQueue.submit_async` to avoid synchronization.
1371
        """
1372
        cdef SyclEvent e = self.submit_async(kernel, args, gS, lS, dEvents)
1✔
1373
        e.wait()
1✔
1374
        return e
1✔
1375

1376
    cpdef void wait(self):
1✔
1377
        with nogil:
1✔
1378
            DPCTLQueue_Wait(self._queue_ref)
1✔
1379

1380
    cpdef memcpy(self, dest, src, size_t count):
1✔
1381
        """Copy memory from `src` to `dst`"""
1382
        cdef DPCTLSyclEventRef ERef = NULL
1✔
1383

1384
        ERef = _memcpy_impl(<SyclQueue>self, dest, src, count, NULL, 0)
1✔
1385
        if (ERef is NULL):
1✔
1386
            raise RuntimeError(
×
1387
                "SyclQueue.memcpy operation encountered an error"
1388
            )
1389
        with nogil:
1✔
1390
            DPCTLEvent_Wait(ERef)
1✔
1391
        DPCTLEvent_Delete(ERef)
1✔
1392

1393
    cpdef SyclEvent memcpy_async(
1✔
1394
        self, dest, src, size_t count, list dEvents=None
1✔
1395
    ):
1396
        """Copy memory from ``src`` to ``dst``"""
1397
        cdef DPCTLSyclEventRef ERef = NULL
1✔
1398
        cdef DPCTLSyclEventRef *depEvents = NULL
1✔
1399
        cdef size_t nDE = 0
1✔
1400

1401
        if dEvents is None:
1✔
1402
            ERef = _memcpy_impl(<SyclQueue>self, dest, src, count, NULL, 0)
1✔
1403
        else:
1404
            nDE = len(dEvents)
1✔
1405
            depEvents = (
1406
                <DPCTLSyclEventRef*>malloc(nDE*sizeof(DPCTLSyclEventRef))
1✔
1407
            )
1408
            if depEvents is NULL:
1✔
1409
                raise MemoryError()
×
1410
            else:
1411
                for idx, de in enumerate(dEvents):
1✔
1412
                    if isinstance(de, SyclEvent):
1✔
1413
                        depEvents[idx] = (<SyclEvent>de).get_event_ref()
1✔
1414
                    else:
1415
                        free(depEvents)
×
1416
                        raise TypeError(
×
1417
                            "A sequence of dpctl.SyclEvent is expected"
1418
                        )
1419
            ERef = _memcpy_impl(self, dest, src, count, depEvents, nDE)
1✔
1420
            free(depEvents)
1✔
1421

1422
        if (ERef is NULL):
1✔
1423
            raise RuntimeError(
×
1424
                "SyclQueue.memcpy operation encountered an error"
1425
            )
1426

1427
        return SyclEvent._create(ERef)
1✔
1428

1429
    cpdef prefetch(self, mem, size_t count=0):
1✔
1430
        cdef void *ptr
1431
        cdef DPCTLSyclEventRef ERef = NULL
1✔
1432

1433
        if isinstance(mem, _Memory):
1✔
1434
            ptr = <void*>(<_Memory>mem).get_data_ptr()
1✔
1435
        else:
1436
            raise TypeError("Parameter `mem` should have type _Memory")
1✔
1437

1438
        if (count <=0 or count > mem.nbytes):
1✔
1439
            count = mem.nbytes
×
1440

1441
        ERef = DPCTLQueue_Prefetch(self._queue_ref, ptr, count)
1✔
1442
        if (ERef is NULL):
1✔
1443
            raise RuntimeError("SyclQueue.prefetch encountered an error")
×
1444
        with nogil:
1✔
1445
            DPCTLEvent_Wait(ERef)
1✔
1446
        DPCTLEvent_Delete(ERef)
1✔
1447

1448
    cpdef mem_advise(self, mem, size_t count, int advice):
1✔
1449
        cdef void *ptr
1450
        cdef DPCTLSyclEventRef ERef = NULL
1✔
1451

1452
        if isinstance(mem, _Memory):
1✔
1453
            ptr = <void*>(<_Memory>mem).get_data_ptr()
1✔
1454
        else:
1455
            raise TypeError("Parameter `mem` should have type _Memory")
1✔
1456

1457
        if (count <=0 or count > mem.nbytes):
1✔
1458
            count = mem.nbytes
×
1459

1460
        ERef = DPCTLQueue_MemAdvise(self._queue_ref, ptr, count, advice)
1✔
1461
        if (ERef is NULL):
1✔
1462
            raise RuntimeError(
×
1463
                "SyclQueue.mem_advise operation encountered an error"
1464
            )
1465
        with nogil:
1✔
1466
            DPCTLEvent_Wait(ERef)
1✔
1467
        DPCTLEvent_Delete(ERef)
1✔
1468

1469
    @property
1470
    def is_in_order(self):
1471
        """``True`` if :class:`.SyclQueue`` is in-order,
1472
        ``False`` if it is out-of-order.
1473

1474
        :Example:
1475

1476
            ..code-block:: python
1477

1478
                >>> import dpctl
1479
                >>> q = dpctl.SyclQueue("cpu")
1480
                >>> q.is_in_order
1481
                False
1482
                >>> q = dpctl.SyclQueue("cpu", property="in_order")
1483
                >>> q.is_in_order
1484
                True
1485

1486
        Returns:
1487
            bool:
1488
                Indicates whether this :class:`.SyclQueue` was created
1489
                with ``property="in_order"``.
1490

1491
        .. note::
1492
            Unless requested otherwise, :class:`.SyclQueue` is constructed
1493
            to support out-of-order execution.
1494
        """
1495
        return DPCTLQueue_IsInOrder(self._queue_ref)
1✔
1496

1497
    @property
1498
    def has_enable_profiling(self):
1499
        """
1500
        ``True`` if :class:`.SyclQueue` was constructed with
1501
        ``"enabled_profiling"`` property, ``False`` otherwise.
1502

1503
        :Example:
1504

1505
            ..code-block:: python
1506

1507
                >>> import dpctl
1508
                >>> q = dpctl.SyclQueue("cpu")
1509
                >>> q.has_enable_profiling
1510
                False
1511
                >>> q = dpctl.SyclQueue("cpu", property="enable_profiling")
1512
                >>> q.has_enable_profiling
1513
                True
1514

1515
        Returns:
1516
            bool:
1517
                Whether profiling information for tasks submitted
1518
                to this :class:`.SyclQueue` is being collected.
1519

1520
        .. note::
1521
            Profiling information can be accessed using
1522
            properties
1523
            :attr:`dpctl.SyclEvent.profiling_info_submit`,
1524
            :attr:`dpctl.SyclEvent.profiling_info_start`, and
1525
            :attr:`dpctl.SyclEvent.profiling_info_end`. It is
1526
            also necessary for proper working of
1527
            :class:`dpctl.SyclTimer`.
1528

1529
            Collection of profiling information is not enabled
1530
            by default.
1531
        """
1532
        return DPCTLQueue_HasEnableProfiling(self._queue_ref)
1✔
1533

1534
    @property
1535
    def __name__(self):
1536
        "The name of :class:`dpctl.SyclQueue` object"
1537
        return "SyclQueue"
1✔
1538

1539
    def __repr__(self):
1540
        cdef cpp_bool in_order = DPCTLQueue_IsInOrder(self._queue_ref)
1✔
1541
        cdef cpp_bool en_prof = DPCTLQueue_HasEnableProfiling(self._queue_ref)
1✔
1542
        if in_order or en_prof:
1✔
1543
            prop = []
1✔
1544
            if in_order:
1✔
1545
                prop.append("in_order")
1✔
1546
            if en_prof:
1✔
1547
                prop.append("enable_profiling")
1✔
1548
            return (
1✔
1549
                "<dpctl."
1550
                + self.__name__
1✔
1551
                + " at {}, property={}>".format(hex(id(self)), prop)
1✔
1552
            )
1553
        else:
1554
            return "<dpctl." + self.__name__ + " at {}>".format(hex(id(self)))
1✔
1555

1556
    def __hash__(self):
1557
        """
1558
        Returns a hash value by hashing the underlying ``sycl::queue`` object.
1559

1560
        Returns:
1561
            int:
1562
                Hash value of this :class:`.SyclQueue` instance
1563
        """
1564
        return DPCTLQueue_Hash(self._queue_ref)
1✔
1565

1566
    def _get_capsule(self):
1✔
1567
        cdef DPCTLSyclQueueRef QRef = NULL
1✔
1568
        QRef = DPCTLQueue_Copy(self._queue_ref)
1✔
1569
        if (QRef is NULL):
1✔
1570
            raise ValueError("SyclQueue copy failed.")
×
1571
        return pycapsule.PyCapsule_New(
1✔
1572
            <void *>QRef, "SyclQueueRef", &_queue_capsule_deleter
1✔
1573
        )
1574

1575
    cpdef SyclEvent submit_barrier(self, dependent_events=None):
1✔
1576
        """
1577
        Submits a barrier to this queue.
1578

1579
        Args:
1580
            dependent_events:
1581
                List[dpctl.SyclEvent]:
1582
                    List or tuple of events that must complete
1583
                    before this task may begin execution.
1584

1585
        Returns:
1586
            dpctl.SyclEvent:
1587
                Event associated with the submitted task
1588
        """
1589
        cdef DPCTLSyclEventRef *depEvents = NULL
1✔
1590
        cdef DPCTLSyclEventRef ERef = NULL
1✔
1591
        cdef size_t nDE = 0
1✔
1592
        # Create the array of dependent events if any
1593
        if (dependent_events is None or
1✔
1594
            (isinstance(dependent_events, collections.abc.Sequence) and
1✔
1595
             all([type(de) is SyclEvent for de in dependent_events]))):
1✔
1596
            nDE = 0 if dependent_events is None else len(dependent_events)
1✔
1597
        else:
1598
            raise TypeError(
1✔
1599
                "dependent_events must either None, or a sequence of "
1600
                ":class:`dpctl.SyclEvent` objects")
1601
        if nDE > 0:
1✔
1602
            depEvents = (
1603
                <DPCTLSyclEventRef*>malloc(nDE*sizeof(DPCTLSyclEventRef))
1✔
1604
            )
1605
            if not depEvents:
1✔
1606
                raise MemoryError()
×
1607
            else:
1608
                for idx, de in enumerate(dependent_events):
1✔
1609
                    depEvents[idx] = (<SyclEvent>de).get_event_ref()
1✔
1610

1611
        ERef = DPCTLQueue_SubmitBarrierForEvents(
1✔
1612
            self.get_queue_ref(), depEvents, nDE)
1✔
1613
        if (depEvents is not NULL):
1✔
1614
            free(depEvents)
1✔
1615
        if ERef is NULL:
1✔
1616
            raise SyclKernelSubmitError(
×
1617
                "Barrier submission to Sycl queue failed."
1618
            )
1619

1620
        return SyclEvent._create(ERef)
1✔
1621

1622
    @property
1623
    def name(self):
1624
        """Returns the device name for the device
1625
        associated with this queue.
1626

1627
        Returns:
1628
            str:
1629
                The name of the device as a string.
1630
        """
1631
        return self.sycl_device.name
1✔
1632

1633
    @property
1634
    def driver_version(self):
1635
        """Returns the driver version for the device
1636
        associated with this queue.
1637

1638
        Returns:
1639
            str:
1640
                The driver version of the device as a string.
1641
        """
1642
        return self.sycl_device.driver_version
1✔
1643

1644
    def print_device_info(self):
1✔
1645
        """ Print information about the SYCL device
1646
        associated with this queue.
1647
        """
1648
        self.sycl_device.print_device_info()
1✔
1649

1650

1651
cdef api DPCTLSyclQueueRef SyclQueue_GetQueueRef(SyclQueue q):
1✔
1652
    """
1653
    C-API function to get opaque queue reference from
1654
    :class:`dpctl.SyclQueue` instance.
1655
    """
1656
    return q.get_queue_ref()
1✔
1657

1658

1659
cdef api SyclQueue SyclQueue_Make(DPCTLSyclQueueRef QRef):
1✔
1660
    """
1661
    C-API function to create :class:`dpctl.SyclQueue` instance
1662
    from the given opaque queue reference.
1663
    """
1664
    cdef DPCTLSyclQueueRef copied_QRef = DPCTLQueue_Copy(QRef)
1✔
1665
    return SyclQueue._create(copied_QRef)
1✔
1666

1667
cdef class _WorkGroupMemory:
1668
    def __dealloc__(self):
1669
        if(self._mem_ref):
1✔
1670
            DPCTLWorkGroupMemory_Delete(self._mem_ref)
1✔
1671

1672
cdef class WorkGroupMemory:
1673
    """
1674
    WorkGroupMemory(nbytes)
1675
    Python class representing the ``work_group_memory`` class from the
1676
    Workgroup Memory oneAPI SYCL extension for low-overhead allocation of local
1677
    memory shared by the workitems in a workgroup.
1678

1679
    This class is intended be used as kernel argument when launching kernels.
1680

1681
    This is based on a DPC++ SYCL extension and only available in newer
1682
    versions. Use ``is_available()`` to check availability in your build.
1683

1684
    There are multiple ways to create a `WorkGroupMemory`.
1685

1686
    - If the constructor is invoked with just a single argument, this argument
1687
      is interpreted as the number of bytes to allocated in the shared local
1688
      memory.
1689

1690
    - If the constructor is invoked with two arguments, the first argument is
1691
      interpreted as the datatype of the local memory, using the numpy type
1692
      naming scheme.
1693
      The second argument is interpreted as the number of elements to allocate.
1694
      The number of bytes to allocate is then computed from the byte size of
1695
      the data type and the element count.
1696

1697
    Args:
1698
        args:
1699
            Variadic argument, see class documentation.
1700

1701
    Raises:
1702
        TypeError: In case of incorrect arguments given to constructors,
1703
                   unexpected types of input arguments.
1704
    """
1705
    def __cinit__(self, *args):
1706
        cdef size_t nbytes
1707
        if not DPCTLWorkGroupMemory_Available():
1✔
1708
            raise RuntimeError("Workgroup memory extension not available")
×
1709

1710
        if not (0 < len(args) < 3):
1✔
1711
            raise TypeError("WorkGroupMemory constructor takes 1 or 2 "
×
1712
                            f"arguments, but {len(args)} were given")
×
1713

1714
        if len(args) == 1:
1✔
1715
            if not isinstance(args[0], numbers.Integral):
1✔
1716
                raise TypeError("WorkGroupMemory single argument constructor"
×
1717
                                "expects first argument to be `int`",
1718
                                f"but got {type(args[0])}")
×
1719
            nbytes = <size_t>(args[0])
1✔
1720
        else:
1721
            if not isinstance(args[0], str):
×
1722
                raise TypeError(
×
1723
                    "WorkGroupMemory constructor expects first"
×
1724
                    f"argument to be `str`, but got {type(args[0])}"
×
1725
                )
1726
            if not isinstance(args[1], numbers.Integral):
×
1727
                raise TypeError(
×
1728
                    "WorkGroupMemory constructor expects second"
×
1729
                    f"argument to be `int`, but got {type(args[1])}"
×
1730
                )
1731
            dtype = <str>(args[0])
×
1732
            count = <size_t>(args[1])
×
1733
            if not dtype[0] in ["i", "u", "f"]:
×
1734
                raise TypeError(f"Unrecognized type value: '{dtype}'")
×
1735
            try:
×
1736
                bit_width = int(dtype[1:])
×
1737
            except ValueError:
×
1738
                raise TypeError(f"Unrecognized type value: '{dtype}'")
×
1739

1740
            byte_size = <size_t>bit_width
×
1741
            nbytes = count * byte_size
×
1742

1743
        self._mem_ref = DPCTLWorkGroupMemory_Create(nbytes)
1✔
1744

1745
    # Check whether the work_group_memory extension is available
1746
    @staticmethod
1✔
1747
    def is_available():
1748
        return DPCTLWorkGroupMemory_Available()
1✔
1749

1750
    property _ref:
1751
        """Returns the address of the C API ``DPCTLWorkGroupMemoryRef``
1752
        pointer as a ``size_t``.
1753
        """
1754
        def __get__(self):
1755
            return <size_t>self._mem_ref
1✔
1756

1757

1758
cdef class _RawKernelArg:
1759
    def __dealloc(self):
1✔
1760
        if(self._arg_ref):
×
1761
            DPCTLRawKernelArg_Delete(self._arg_ref)
×
1762

1763

1764
cdef class RawKernelArg:
1765
    """
1766
    RawKernelArg(*args)
1767
    Python class representing the ``raw_kernel_arg`` class from the Raw Kernel
1768
    Argument oneAPI SYCL extension for passing binary data as data to kernels.
1769

1770
    This class is intended to be used as kernel argument when launching kernels.
1771

1772
    This is based on a DPC++ SYCL extension and only available in newer
1773
    versions. Use ``is_available()`` to check availability in your build.
1774

1775
    There are multiple ways to create a ``RawKernelArg``.
1776

1777
    - If the constructor is invoked with just a single argument, this argument
1778
      is expected to expose the Python buffer interface. The raw kernel arg will
1779
      be constructed from the data in that buffer.
1780

1781
    - If the constructor is invoked with two arguments, the first argument is
1782
      interpreted as the number of bytes in the binary argument, while the
1783
      second argument is interpreted as a pointer to the data.
1784

1785
    Note that construction of the ``RawKernelArg`` copies the bytes, so
1786
    modifications made after construction of the ``RawKernelArg`` will not be
1787
    reflected in the kernel launch.
1788

1789
    Args:
1790
        args:
1791
            Variadic argument, see class documentation.
1792

1793
    Raises:
1794
        TypeError: In case of incorrect arguments given to constructurs,
1795
                   unexpected types of input arguments.
1796
    """
1797
    def __cinit__(self, *args):
1798
        cdef void* ptr = NULL
1✔
1799
        cdef size_t count
1800
        cdef int ret_code = 0
1✔
1801
        cdef Py_buffer _buffer
1802
        cdef bint _is_buf
1803

1804
        if not DPCTLRawKernelArg_Available():
1✔
1805
            raise RuntimeError("Raw kernel arg extension not available")
×
1806

1807
        if not (0 < len(args) < 3):
1✔
1808
            raise TypeError("RawKernelArg constructor takes 1 or 2 "
×
1809
                            f"arguments, but {len(args)} were given")
×
1810

1811
        if len(args) == 1:
1✔
1812
            if not _is_buffer(args[0]):
1✔
1813
                raise TypeError("RawKernelArg single argument constructor"
×
1814
                                "expects argument to be buffer",
1815
                                f"but got {type(args[0])}")
×
1816

1817
            ret_code = PyObject_GetBuffer(args[0], &(_buffer),
1✔
1818
                                          PyBUF_SIMPLE | PyBUF_ANY_CONTIGUOUS)
1✔
1819
            if ret_code != 0:  # pragma: no cover
1820
                raise RuntimeError("Could not access buffer")
×
1821

1822
            ptr = _buffer.buf
1✔
1823
            count = _buffer.len
1✔
1824
            _is_buf = True
1✔
1825
        else:
1826
            if not isinstance(args[0], numbers.Integral):
1✔
1827
                raise TypeError("RawKernelArg constructor expects first"
×
1828
                                "argument to be `int`, but got {type(args[0])}")
1829
            if not isinstance(args[1], numbers.Integral):
1✔
1830
                raise TypeError("RawKernelArg constructor expects second"
×
1831
                                "argument to be `int`, but got {type(args[1])}")
1832

1833
            _is_buf = False
1✔
1834
            count = args[0]
1✔
1835
            ptr = <void*>(<unsigned long long>args[1])
1✔
1836

1837
        self._arg_ref = DPCTLRawKernelArg_Create(ptr, count)
1✔
1838
        if(_is_buf):
1✔
1839
            PyBuffer_Release(&(_buffer))
1✔
1840

1841
    @staticmethod
1✔
1842
    def is_available():
1843
        return DPCTLRawKernelArg_Available()
1✔
1844

1845
    property _ref:
1846
        """Returns the address of the C API ``DPCTLRawKernelArgRef`` pointer
1847
        as a ``size_t``.
1848
        """
1849
        def __get__(self):
1850
            return <size_t>self._arg_ref
×
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