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

IntelPython / dpctl / 14222426726

02 Apr 2025 02:39PM UTC coverage: 86.307% (-0.07%) from 86.379%
14222426726

Pull #2038

github

web-flow
Merge 301707497 into 67317b094
Pull Request #2038: Add support for raw_kernel_arg extension

3018 of 3716 branches covered (81.22%)

Branch coverage included in aggregate %.

46 of 67 new or added lines in 3 files covered. (68.66%)

1 existing line in 1 file now uncovered.

12160 of 13870 relevant lines covered (87.67%)

7005.24 hits per line

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

75.68
/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_DECREF, 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(DPCTLSyclQueueRef, PyObject **, size_t, DPCTLSyclEventRef *, size_t, int *) nogil
94

95

96
__all__ = [
1✔
97
    "SyclQueue",
98
    "SyclKernelInvalidRangeError",
99
    "SyclKernelSubmitError",
100
    "SyclQueueCreationError",
101
]
102

103

104
_logger = logging.getLogger(__name__)
1✔
105

106

107
cdef class kernel_arg_type_attribute:
108
    cdef str parent_name
109
    cdef str attr_name
110
    cdef int attr_value
111

112
    def __cinit__(self, str parent, str name, int value):
113
        self.parent_name = parent
1✔
114
        self.attr_name = name
1✔
115
        self.attr_value = value
1✔
116

117
    def __repr__(self):
118
        return f"<{self.parent_name}.{self.attr_name}: {self.attr_value}>"
1✔
119

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

123
    @property
124
    def name(self):
125
        return self.attr_name
1✔
126

127
    @property
128
    def value(self):
129
        return self.attr_value
1✔
130

131

132
cdef class LocalAccessor:
133
    """
134
    LocalAccessor(dtype, shape)
135

136
    Python class for specifying the dimensionality and type of a
137
    ``sycl::local_accessor``, to be used as a kernel argument type.
138

139
    Args:
140
        dtype (str):
141
            the data type of the local memory.
142
            The permitted values are
143

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

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

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

187
       if dtype == 'i1':
×
188
           self.lacc.dpctl_type_id = _arg_data_type._INT8_T
×
189
       elif dtype == 'u1':
×
190
           self.lacc.dpctl_type_id = _arg_data_type._UINT8_T
×
191
       elif dtype == 'i2':
×
192
           self.lacc.dpctl_type_id = _arg_data_type._INT16_T
×
193
       elif dtype == 'u2':
×
194
           self.lacc.dpctl_type_id = _arg_data_type._UINT16_T
×
195
       elif dtype == 'i4':
×
196
           self.lacc.dpctl_type_id = _arg_data_type._INT32_T
×
197
       elif dtype == 'u4':
×
198
           self.lacc.dpctl_type_id = _arg_data_type._UINT32_T
×
199
       elif dtype == 'i8':
×
200
           self.lacc.dpctl_type_id = _arg_data_type._INT64_T
×
201
       elif dtype == 'u8':
×
202
           self.lacc.dpctl_type_id = _arg_data_type._UINT64_T
×
203
       elif dtype == 'f4':
×
204
           self.lacc.dpctl_type_id = _arg_data_type._FLOAT
×
205
       elif dtype == 'f8':
×
206
           self.lacc.dpctl_type_id = _arg_data_type._DOUBLE
×
207
       else:
208
           raise ValueError(f"Unrecognized type value: '{dtype}'")
×
209

210
    def __repr__(self):
211
        return f"LocalAccessor({self.lacc.ndim})"
×
212

213
    cdef size_t addressof(self):
1✔
214
        """
215
        Returns the address of the _md_local_accessor for this LocalAccessor
216
        cast to ``size_t``.
217
        """
218
        return <size_t>&self.lacc
×
219

220

221
cdef class _kernel_arg_type:
222
    """
223
    An enumeration of supported kernel argument types in
224
    :func:`dpctl.SyclQueue.submit`
225
    """
226
    cdef str _name
227

228
    def __cinit__(self):
229
        self._name = "kernel_arg_type"
1✔
230

231

232
    @property
233
    def __name__(self):
234
        return self._name
1✔
235

236
    def __repr__(self):
237
        return "<enum 'kernel_arg_type'>"
1✔
238

239
    def __str__(self):
240
        return "<enum 'kernel_arg_type'>"
1✔
241

242
    @property
243
    def dpctl_int8(self):
244
        cdef str p_name = "dpctl_int8"
1✔
245
        return kernel_arg_type_attribute(
1✔
246
            self._name,
247
            p_name,
248
            _arg_data_type._INT8_T
1✔
249
        )
250

251
    @property
252
    def dpctl_uint8(self):
253
        cdef str p_name = "dpctl_uint8"
1✔
254
        return kernel_arg_type_attribute(
1✔
255
            self._name,
256
            p_name,
257
            _arg_data_type._UINT8_T
1✔
258
        )
259

260
    @property
261
    def dpctl_int16(self):
262
        cdef str p_name = "dpctl_int16"
1✔
263
        return kernel_arg_type_attribute(
1✔
264
            self._name,
265
            p_name,
266
            _arg_data_type._INT16_T
1✔
267
        )
268

269
    @property
270
    def dpctl_uint16(self):
271
        cdef str p_name = "dpctl_uint16"
1✔
272
        return kernel_arg_type_attribute(
1✔
273
            self._name,
274
            p_name,
275
            _arg_data_type._UINT16_T
1✔
276
        )
277

278
    @property
279
    def dpctl_int32(self):
280
        cdef str p_name = "dpctl_int32"
1✔
281
        return kernel_arg_type_attribute(
1✔
282
            self._name,
283
            p_name,
284
            _arg_data_type._INT32_T
1✔
285
        )
286

287
    @property
288
    def dpctl_uint32(self):
289
        cdef str p_name = "dpctl_uint32"
1✔
290
        return kernel_arg_type_attribute(
1✔
291
            self._name,
292
            p_name,
293
            _arg_data_type._UINT32_T
1✔
294
        )
295

296
    @property
297
    def dpctl_int64(self):
298
        cdef str p_name = "dpctl_int64"
1✔
299
        return kernel_arg_type_attribute(
1✔
300
            self._name,
301
            p_name,
302
            _arg_data_type._INT64_T
1✔
303
        )
304

305
    @property
306
    def dpctl_uint64(self):
307
        cdef str p_name = "dpctl_uint64"
1✔
308
        return kernel_arg_type_attribute(
1✔
309
            self._name,
310
            p_name,
311
            _arg_data_type._UINT64_T
1✔
312
        )
313

314
    @property
315
    def dpctl_float32(self):
316
        cdef str p_name = "dpctl_float32"
1✔
317
        return kernel_arg_type_attribute(
1✔
318
            self._name,
319
            p_name,
320
            _arg_data_type._FLOAT
1✔
321
        )
322

323
    @property
324
    def dpctl_float64(self):
325
        cdef str p_name = "dpctl_float64"
1✔
326
        return kernel_arg_type_attribute(
1✔
327
            self._name,
328
            p_name,
329
            _arg_data_type._DOUBLE
1✔
330
        )
331

332
    @property
333
    def dpctl_void_ptr(self):
334
        cdef str p_name = "dpctl_void_ptr"
1✔
335
        return kernel_arg_type_attribute(
1✔
336
            self._name,
337
            p_name,
338
            _arg_data_type._VOID_PTR
1✔
339
        )
340

341
    @property
342
    def dpctl_local_accessor(self):
343
        cdef str p_name = "dpctl_local_accessor"
1✔
344
        return kernel_arg_type_attribute(
1✔
345
            self._name,
346
            p_name,
347
            _arg_data_type._LOCAL_ACCESSOR
1✔
348
        )
349

350
    @property
351
    def dpctl_work_group_memory(self):
352
        cdef str p_name = "dpctl_work_group_memory"
1✔
353
        return kernel_arg_type_attribute(
1✔
354
            self._name,
355
            p_name,
356
            _arg_data_type._WORK_GROUP_MEMORY
1✔
357
        )
358

359
    @property
360
    def dpctl_raw_kernel_arg(self):
361
        cdef str p_name = "dpctl_raw_kernel_arg"
1✔
362
        return kernel_arg_type_attribute(
1✔
363
            self._name,
364
            p_name,
365
            _arg_data_type._RAW_KERNEL_ARG
1✔
366
        )
367

368

369
kernel_arg_type = _kernel_arg_type()
1✔
370

371

372
cdef class SyclKernelSubmitError(Exception):
373
    """
374
    A ``SyclKernelSubmitError`` exception is raised when
375
    the provided :class:`.program.SyclKernel` could not be
376
    submitted to the :class:`.SyclQueue`.
377

378
    """
379
    pass
380

381

382
cdef class SyclKernelInvalidRangeError(Exception):
383
    """
384
    A ``SyclKernelInvalidRangeError`` is raised when the provided
385
    range has less than one or more than three dimensions.
386
    """
387
    pass
388

389

390
cdef class SyclQueueCreationError(Exception):
391
    """
392
    A ``SyclQueueCreationError`` exception is raised when a
393
    :class:`.SyclQueue` could not be created.
394

395
    :class:`.SyclQueue` creation can fail if the filter
396
    string is invalid, or the backend or device type values are not supported.
397

398
    """
399
    pass
400

401

402
cdef int _parse_queue_properties(object prop) except *:
1✔
403
    cdef int res = 0
1✔
404
    cdef object props
405
    if isinstance(prop, int):
1✔
406
        return <int>prop
1✔
407
    if not isinstance(prop, (tuple, list)):
1✔
408
        props = (prop, )
1✔
409
    else:
410
        props = prop
1✔
411
    for p in props:
1✔
412
        if isinstance(p, int):
1✔
413
            res = res | <int> p
1✔
414
        elif isinstance(p, str):
1✔
415
            if (p == "in_order"):
1✔
416
                res = res | _queue_property_type._IN_ORDER
1✔
417
            elif (p == "enable_profiling"):
1✔
418
                res = res | _queue_property_type._ENABLE_PROFILING
1✔
419
            elif (p == "default"):
1✔
420
                res = res | _queue_property_type._DEFAULT_PROPERTY
1✔
421
            else:
422
                raise ValueError(
1✔
423
                    (
424
                        "queue property '{}' is not understood, "
425
                        "expecting 'in_order', 'enable_profiling', or 'default'"
426
                    ).format(prop)
1✔
427
                )
428
        else:
429
            raise ValueError(
1✔
430
                "queue property '{}' is not understood.".format(prop)
1✔
431
            )
432
    return res
1✔
433

434

435
cdef void _queue_capsule_deleter(object o) noexcept:
1✔
436
    cdef DPCTLSyclQueueRef QRef = NULL
1✔
437
    if pycapsule.PyCapsule_IsValid(o, "SyclQueueRef"):
1✔
438
        QRef = <DPCTLSyclQueueRef> pycapsule.PyCapsule_GetPointer(
1✔
439
            o, "SyclQueueRef"
440
        )
441
        DPCTLQueue_Delete(QRef)
1✔
442
    elif pycapsule.PyCapsule_IsValid(o, "used_SyclQueueRef"):
1✔
443
        QRef = <DPCTLSyclQueueRef> pycapsule.PyCapsule_GetPointer(
1✔
444
            o, "used_SyclQueueRef"
445
        )
446
        DPCTLQueue_Delete(QRef)
1✔
447

448

449
cdef bint _is_buffer(object o):
1✔
450
    return PyObject_CheckBuffer(o)
1✔
451

452

453
cdef DPCTLSyclEventRef _memcpy_impl(
1✔
454
     SyclQueue q,
455
     object dst,
456
     object src,
457
     size_t byte_count,
458
     DPCTLSyclEventRef *dep_events,
459
     size_t dep_events_count
460
) except *:
461
    cdef void *c_dst_ptr = NULL
1✔
462
    cdef void *c_src_ptr = NULL
1✔
463
    cdef DPCTLSyclEventRef ERef = NULL
1✔
464
    cdef Py_buffer src_buf_view
465
    cdef Py_buffer dst_buf_view
466
    cdef bint src_is_buf = False
1✔
467
    cdef bint dst_is_buf = False
1✔
468
    cdef int ret_code = 0
1✔
469

470
    if isinstance(src, _Memory):
1✔
471
        c_src_ptr = <void*>(<_Memory>src).get_data_ptr()
1✔
472
    elif _is_buffer(src):
1✔
473
        ret_code = PyObject_GetBuffer(src, &src_buf_view, PyBUF_SIMPLE | PyBUF_ANY_CONTIGUOUS)
1✔
474
        if ret_code != 0: # pragma: no cover
475
            raise RuntimeError("Could not access buffer")
×
476
        c_src_ptr = src_buf_view.buf
1✔
477
        src_is_buf = True
1✔
478
    else:
479
        raise TypeError(
1✔
480
             "Parameter `src` should have either type "
481
             "`dpctl.memory._Memory` or a type that "
482
             "supports Python buffer protocol"
483
       )
484

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

502
    if dep_events_count == 0 or dep_events is NULL:
1✔
503
        ERef = DPCTLQueue_Memcpy(q._queue_ref, c_dst_ptr, c_src_ptr, byte_count)
1✔
504
    else:
505
        ERef = DPCTLQueue_MemcpyWithEvents(
1✔
506
            q._queue_ref,
507
            c_dst_ptr,
508
            c_src_ptr,
509
            byte_count,
510
            dep_events,
511
            dep_events_count
1✔
512
        )
513

514
    if src_is_buf:
1✔
515
        PyBuffer_Release(&src_buf_view)
1✔
516
    if dst_is_buf:
1✔
517
        PyBuffer_Release(&dst_buf_view)
1✔
518

519
    return ERef
1✔
520

521

522
cdef class _SyclQueue:
523
    """ Barebone data owner class used by SyclQueue.
524
    """
525
    def __dealloc__(self):
526
        if (self._queue_ref):
1✔
527
            DPCTLQueue_Delete(self._queue_ref)
1✔
528
        # self._context is a Python object and will be GC-ed
529
        # self._device is a Python object
530

531

532
cdef class SyclQueue(_SyclQueue):
533
    """
534
    SyclQueue(*args, **kwargs)
535
    Python class representing ``sycl::queue``.
536

537
    There are multiple ways to create a :class:`dpctl.SyclQueue` object:
538

539
    - Invoking the constructor with no arguments creates a context using
540
      the default selector.
541

542
    :Example:
543
        .. code-block:: python
544

545
            import dpctl
546

547
            # Create a default SyclQueue
548
            q = dpctl.SyclQueue()
549
            print(q.sycl_device)
550

551
    - Invoking the constructor with specific filter selector string that
552
      creates a queue for the device corresponding to the filter string.
553

554
    :Example:
555
        .. code-block:: python
556

557
            import dpctl
558

559
            # Create in-order SyclQueue for either gpu, or cpu device
560
            q = dpctl.SyclQueue("gpu,cpu", property="in_order")
561
            print([q.sycl_device.is_gpu, q.sycl_device.is_cpu])
562

563
    - Invoking the constructor with a :class:`dpctl.SyclDevice` object
564
      creates a queue for that device, automatically finding/creating
565
      a :class:`dpctl.SyclContext` for the given device.
566

567
    :Example:
568
        .. code-block:: python
569

570
            import dpctl
571

572
            d = dpctl.SyclDevice("gpu")
573
            q = dpctl.SyclQueue(d)
574
            ctx = q.sycl_context
575
            print(q.sycl_device == d)
576
            print(any([ d == ctx_d for ctx_d in ctx.get_devices()]))
577

578
    - Invoking the constructor with a :class:`dpctl.SyclContext` and a
579
      :class:`dpctl.SyclDevice` creates a queue for given context and
580
      device.
581

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

585
            import dpctl
586

587
            # Create a CPU device using the opencl driver
588
            cpu_d = dpctl.SyclDevice("opencl:cpu")
589
            # Partition the CPU device into sub-devices with two cores each.
590
            sub_devices = cpu_d.create_sub_devices(partition=2)
591
            # Create a context common to all the sub-devices.
592
            ctx = dpctl.SyclContext(sub_devices)
593
            # create a queue for each sub-device using the common context
594
            queues = [dpctl.SyclQueue(ctx, sub_d) for sub_d in sub_devices]
595

596
    - Invoking the constructor with a named ``PyCapsule`` with the name
597
      **"SyclQueueRef"** that carries a pointer to a ``sycl::queue``
598
      object. The capsule will be renamed upon successful consumption
599
      to ensure one-time use. A new named capsule can be constructed by
600
      using :func:`dpctl.SyclQueue._get_capsule` method.
601

602
    Args:
603
        ctx (:class:`dpctl.SyclContext`, optional): Sycl context to create
604
            :class:`dpctl.SyclQueue` from. If not specified, a single-device
605
            context will be created from the specified device.
606
        dev (str, :class:`dpctl.SyclDevice`, capsule, optional): Sycl device
607
             to create :class:`dpctl.SyclQueue` from. If not specified, sycl
608
             device selected by ``sycl::default_selector`` is used.
609
             The argument must be explicitly specified if `ctxt` argument is
610
             provided.
611

612
             If `dev` is a named ``PyCapsule`` called **"SyclQueueRef"** and
613
             `ctxt` is not specified, :class:`dpctl.SyclQueue` instance is
614
             created from foreign `sycl::queue` object referenced by the
615
             capsule.
616
        property (str, tuple(str), list(str), optional): Defaults to None.
617
                The argument can be either "default", "in_order",
618
                "enable_profiling", or a tuple containing these.
619

620
    Raises:
621
        SyclQueueCreationError: If the :class:`dpctl.SyclQueue` object
622
                                creation failed.
623
        TypeError: In case of incorrect arguments given to constructors,
624
                   unexpected types of input arguments, or in the case the input
625
                   capsule contained a null pointer or could not be renamed.
626

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

716
    cdef int _init_queue_from__SyclQueue(self, _SyclQueue other):
1✔
717
        """ Copy data container _SyclQueue fields over.
718
        """
719
        cdef DPCTLSyclQueueRef QRef = DPCTLQueue_Copy(other._queue_ref)
1✔
720
        if (QRef is NULL):
1✔
721
            return -4
×
722
        self._queue_ref = QRef
1✔
723
        self._context = other._context
1✔
724
        self._device = other._device
1✔
725

726
    cdef int _init_queue_from_DPCTLSyclDeviceRef(
1✔
727
        self, DPCTLSyclDeviceRef DRef, int props
728
    ):
729
        """
730
        Initializes self by creating SyclQueue with specified error handler and
731
        specified properties from the given device instance. SyclContext is
732
        looked-up by DPCTL from a cache to avoid repeated construction of new
733
        context for performance reasons.
734

735
        Returns: 0 : normal execution
736
                -3 : Context creation/look-up failed
737
                -4 : queue could not be created from context,device, error
738
                     handler and properties
739
        """
740
        cdef DPCTLSyclContextRef CRef
741
        cdef DPCTLSyclQueueRef QRef
742

743
        CRef = DPCTLDeviceMgr_GetCachedContext(DRef)
1✔
744
        if (CRef is NULL):
1✔
745
            # look-up failed (was not a root device?)
746
            # create a new context
747
            CRef = DPCTLContext_Create(DRef, NULL, 0)
1✔
748
            if (CRef is NULL):
1✔
749
                DPCTLDevice_Delete(DRef)
×
750
                return -3
×
751
        QRef = DPCTLQueue_Create(
1✔
752
            CRef,
753
            DRef,
754
            NULL,
755
            props
756
        )
757
        if QRef is NULL:
1✔
758
            DPCTLContext_Delete(CRef)
×
759
            DPCTLDevice_Delete(DRef)
×
760
            return -4
×
761
        _dev = SyclDevice._create(DRef)
1✔
762
        _ctxt = SyclContext._create(CRef)
1✔
763
        self._device = _dev
1✔
764
        self._context = _ctxt
1✔
765
        self._queue_ref = QRef
1✔
766
        return 0  # normal return
1✔
767

768
    cdef int _init_queue_from_filter_string(self, const char *c_str, int props):
1✔
769
        """
770
        Initializes self from filter string, error handler and properties.
771
        Creates device from device selector, then calls helper function above.
772

773
        Returns:
774
             0 : normal execution
775
            -1 : filter selector could not be created (malformed?)
776
            -2 : Device could not be created from filter selector
777
            -3 : Context creation/look-up failed
778
            -4 : queue could not be created from context,device, error handler
779
                 and properties
780
        """
781
        cdef DPCTLSyclDeviceSelectorRef DSRef = NULL
1✔
782
        cdef DPCTLSyclDeviceRef DRef = NULL
1✔
783
        cdef int ret = 0
1✔
784

785
        DSRef = DPCTLFilterSelector_Create(c_str)
1✔
786
        if DSRef is NULL:
1✔
787
            ret = -1  # Filter selector failed to be created
1✔
788
        else:
789
            DRef = DPCTLDevice_CreateFromSelector(DSRef)
1✔
790
            DPCTLDeviceSelector_Delete(DSRef)
1✔
791
            if (DRef is NULL):
1✔
792
                ret = -2  # Device could not be created
1✔
793
            else:
794
                ret = self._init_queue_from_DPCTLSyclDeviceRef(DRef, props)
1✔
795
        return ret
1✔
796

797
    cdef int _init_queue_from_device(self, SyclDevice dev, int props):
1✔
798
        cdef DPCTLSyclDeviceRef DRef = NULL
1✔
799
        # The DRef will be stored in self._device and freed when self._device
800
        # is garbage collected.
801
        DRef = DPCTLDevice_Copy(dev.get_device_ref())
1✔
802
        if (DRef is NULL):
1✔
803
            return -2  # Device could not be created
×
804
        else:
805
            return self._init_queue_from_DPCTLSyclDeviceRef(DRef, props)
1✔
806

807
    cdef int _init_queue_default(self, int props):
1✔
808
        cdef DPCTLSyclDeviceSelectorRef DSRef = DPCTLDefaultSelector_Create()
1✔
809
        cdef int ret = 0
1✔
810
        # The DRef will be stored in self._device and freed when self._device
811
        # is garbage collected.
812
        DRef = DPCTLDevice_CreateFromSelector(DSRef)
1✔
813
        DPCTLDeviceSelector_Delete(DSRef)
1✔
814
        if (DRef is NULL):
1✔
815
            ret = -2  # Device could not be created
×
816
        else:
817
            ret = self._init_queue_from_DPCTLSyclDeviceRef(DRef, props)
1✔
818
        return ret
1✔
819

820
    cdef int _init_queue_from_context_and_device(
1✔
821
        self, SyclContext ctxt, SyclDevice dev, int props
822
    ):
823
        cdef DPCTLSyclContextRef CRef = NULL
1✔
824
        cdef DPCTLSyclDeviceRef DRef = NULL
1✔
825
        cdef DPCTLSyclQueueRef QRef = NULL
1✔
826
        CRef = ctxt.get_context_ref()
1✔
827
        DRef = dev.get_device_ref()
1✔
828
        QRef = DPCTLQueue_Create(
1✔
829
            CRef,
830
            DRef,
831
            NULL,
832
            props
833
        )
834
        if (QRef is NULL):
1✔
835
            return -4
1✔
836
        self._device = dev
1✔
837
        self._context = ctxt
1✔
838
        self._queue_ref = QRef
1✔
839
        return 0  # normal return
1✔
840

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

883
    @staticmethod
884
    cdef SyclQueue _create(DPCTLSyclQueueRef qref):
1✔
885
        """
886
        This function calls ``DPCTLQueue_Delete(qref)``.
887
        The user of this function must pass a copy to keep the
888
        qref argument alive.
889
        """
890
        if qref is NULL:
1✔
891
            raise SyclQueueCreationError("Queue creation failed.")
×
892
        cdef _SyclQueue ret = _SyclQueue.__new__(_SyclQueue)
1✔
893
        ret._context = SyclContext._create(DPCTLQueue_GetContext(qref))
1✔
894
        ret._device = SyclDevice._create(DPCTLQueue_GetDevice(qref))
1✔
895
        ret._queue_ref = qref
1✔
896
        # ret is a temporary, and will call DPCTLQueue_Delete(qref)
897
        return SyclQueue(ret)
1✔
898

899
    @staticmethod
900
    cdef SyclQueue _create_from_context_and_device(
1✔
901
        SyclContext ctx, SyclDevice dev, int props=0
902
    ):
903
        """
904
        Static factory method to create :class:`dpctl.SyclQueue` instance
905
        from given :class:`dpctl.SyclContext`, :class:`dpctl.SyclDevice`
906
        and optional integer ``props`` encoding the queue properties.
907
        """
908
        cdef _SyclQueue ret = _SyclQueue.__new__(_SyclQueue)
1✔
909
        cdef DPCTLSyclContextRef cref = ctx.get_context_ref()
1✔
910
        cdef DPCTLSyclDeviceRef dref = dev.get_device_ref()
1✔
911
        cdef DPCTLSyclQueueRef qref = NULL
1✔
912

913
        qref = DPCTLQueue_Create(
1✔
914
            cref,
915
            dref,
916
            NULL,
917
            props
918
        )
919
        if qref is NULL:
1✔
920
            raise SyclQueueCreationError("Queue creation failed.")
×
921
        ret._queue_ref = qref
1✔
922
        ret._context = ctx
1✔
923
        ret._device = dev
1✔
924
        return SyclQueue(ret)
1✔
925

926
    cdef int _populate_args(
1✔
927
        self,
928
        list args,
929
        void **kargs,
930
        _arg_data_type *kargty
931
    ):
932
        cdef int ret = 0
1✔
933
        for idx, arg in enumerate(args):
1✔
934
            if isinstance(arg, ctypes.c_char):
1✔
935
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
×
936
                kargty[idx] = _arg_data_type._INT8_T
×
937
            elif isinstance(arg, ctypes.c_uint8):
1✔
938
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
×
939
                kargty[idx] = _arg_data_type._UINT8_T
×
940
            elif isinstance(arg, ctypes.c_short):
1✔
941
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
942
                kargty[idx] = _arg_data_type._INT16_T
1✔
943
            elif isinstance(arg, ctypes.c_ushort):
1✔
944
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
×
945
                kargty[idx] = _arg_data_type._UINT16_T
×
946
            elif isinstance(arg, ctypes.c_int):
1✔
947
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
948
                kargty[idx] = _arg_data_type._INT32_T
1✔
949
            elif isinstance(arg, ctypes.c_uint):
1✔
950
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
951
                kargty[idx] = _arg_data_type._UINT32_T
1✔
952
            elif isinstance(arg, ctypes.c_longlong):
1✔
953
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
954
                kargty[idx] = _arg_data_type._INT64_T
1✔
955
            elif isinstance(arg, ctypes.c_ulonglong):
1✔
956
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
957
                kargty[idx] = _arg_data_type._UINT64_T
1✔
958
            elif isinstance(arg, ctypes.c_float):
1✔
959
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
960
                kargty[idx] = _arg_data_type._FLOAT
1✔
961
            elif isinstance(arg, ctypes.c_double):
1✔
962
                kargs[idx] = <void*><size_t>(ctypes.addressof(arg))
1✔
963
                kargty[idx] = _arg_data_type._DOUBLE
1✔
964
            elif isinstance(arg, _Memory):
1✔
965
                kargs[idx]= <void*>(<size_t>arg._pointer)
1✔
966
                kargty[idx] = _arg_data_type._VOID_PTR
1✔
967
            elif isinstance(arg, WorkGroupMemory):
1✔
968
                kargs[idx] = <void*>(<size_t>arg._ref)
1✔
969
                kargty[idx] = _arg_data_type._WORK_GROUP_MEMORY
1✔
970
            elif isinstance(arg, LocalAccessor):
×
971
                kargs[idx] = <void*>((<LocalAccessor>arg).addressof())
×
972
                kargty[idx] = _arg_data_type._LOCAL_ACCESSOR
×
NEW
973
            elif isinstance(arg, RawKernelArg):
×
NEW
974
                kargs[idx] = <void*>(<size_t>arg._ref)
×
NEW
975
                kargty[idx] = _arg_data_type._RAW_KERNEL_ARG
×
976
            else:
977
                ret = -1
×
978
        return ret
1✔
979

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

982
        cdef int ret = 0
1✔
983

984
        if nS == 1:
1✔
985
            Range[0] = <size_t>S[0]
1✔
986
            Range[1] = 1
1✔
987
            Range[2] = 1
1✔
988
        elif nS == 2:
989
            Range[0] = <size_t>S[0]
1✔
990
            Range[1] = <size_t>S[1]
1✔
991
            Range[2] = 1
1✔
992
        elif nS == 3:
993
            Range[0] = <size_t>S[0]
1✔
994
            Range[1] = <size_t>S[1]
1✔
995
            Range[2] = <size_t>S[2]
1✔
996
        else:
997
            ret = -1
×
998

999
        return ret
1✔
1000

1001
    cdef cpp_bool equals(self, SyclQueue q):
1✔
1002
        """ Returns true if the :class:`.SyclQueue` argument ``q`` has the
1003
            same ``._queue_ref`` attribute as this :class:`.SyclQueue`.
1004
        """
1005
        return DPCTLQueue_AreEq(self._queue_ref, q.get_queue_ref())
1✔
1006

1007
    def __eq__(self, other):
1008
        """
1009
        Returns True if two :class:`dpctl.SyclQueue` compared arguments have
1010
        the same underlying ``DPCTLSyclQueueRef`` object.
1011

1012
        Returns:
1013
            bool:
1014
                ``True`` if the two :class:`dpctl.SyclQueue` objects
1015
                point to the same ``DPCTLSyclQueueRef`` object, otherwise
1016
                ``False``.
1017
        """
1018
        if isinstance(other, SyclQueue):
1✔
1019
            return self.equals(<SyclQueue> other)
1✔
1020
        else:
1021
            return False
1✔
1022

1023
    @property
1024
    def backend(self):
1025
        """ Returns the ``backend_type`` enum value for this queue.
1026

1027
        Returns:
1028
            backend_type:
1029
                The backend for the queue.
1030
        """
1031
        cdef _backend_type BE = DPCTLQueue_GetBackend(self._queue_ref)
1✔
1032
        if BE == _backend_type._OPENCL:
1✔
1033
            return backend_type.opencl
1✔
1034
        elif BE == _backend_type._LEVEL_ZERO:
1035
            return backend_type.level_zero
×
1036
        elif BE == _backend_type._CUDA:
1037
            return backend_type.cuda
×
1038
        elif BE == _backend_type._HIP:
1039
            return backend_type.hip
×
1040
        else:
1041
            raise ValueError("Unknown backend type.")
×
1042

1043
    @property
1044
    def sycl_context(self):
1045
        """
1046
        Returns :class:`SyclContext` underlying this queue.
1047

1048
        Returns:
1049
            :class:`SyclContext`
1050
                SYCL context underlying this queue
1051
        """
1052
        return self._context
1✔
1053

1054
    @property
1055
    def sycl_device(self):
1056
        """
1057
        Returns :class:`.SyclDevice` targeted by this queue.
1058

1059
        Returns:
1060
            :class:`SyclDevice`
1061
                SYCL device targeted by this queue
1062
        """
1063
        return self._device
1✔
1064

1065
    cpdef SyclContext get_sycl_context(self):
1✔
1066
        return self._context
1✔
1067

1068
    cpdef SyclDevice get_sycl_device(self):
1✔
1069
        return self._device
1✔
1070

1071
    cdef DPCTLSyclQueueRef get_queue_ref(self):
1✔
1072
        return self._queue_ref
1✔
1073

1074
    def addressof_ref(self):
1✔
1075
        """
1076
        Returns the address of the C API ``DPCTLSyclQueueRef`` pointer as
1077
        integral value of type ``size_t``.
1078

1079
        Returns:
1080
            int:
1081
                The address of the ``DPCTLSyclQueueRef`` object used to create
1082
                this :class:`dpctl.SyclQueue` object cast to ``size_t`` type.
1083
        """
1084
        return <size_t>self._queue_ref
1✔
1085

1086

1087
    cpdef SyclEvent _submit_keep_args_alive(
1✔
1088
        self,
1089
        object args,
1090
        list dEvents
1091
    ):
1092
        """ SyclQueue._submit_keep_args_alive(args, events)
1093

1094
        Keeps objects in ``args`` alive until tasks associated with events
1095
        complete.
1096

1097
        Args:
1098
            args(object):
1099
                Python object to keep alive.
1100
                Typically a tuple with arguments to offloaded tasks
1101
            events(Tuple[dpctl.SyclEvent]):
1102
                Gating events.
1103
                The list or tuple of events associated with tasks
1104
                working on Python objects collected in ``args``.
1105
        Returns:
1106
            dpctl.SyclEvent
1107
               The event associated with the submission of host task.
1108

1109
        Increments reference count of ``args`` and schedules asynchronous
1110
        ``host_task`` to decrement the count once dependent events are
1111
        complete.
1112

1113
        .. note::
1114
            The ``host_task`` attempts to acquire Python GIL, and it is
1115
            known to be unsafe during interpreter shutdown sequence. It is
1116
            thus strongly advised to ensure that all submitted ``host_task``
1117
            complete before the end of the Python script.
1118
        """
1119
        cdef size_t nDE = len(dEvents)
1✔
1120
        cdef DPCTLSyclEventRef *depEvents = NULL
1✔
1121
        cdef PyObject *args_raw = NULL
1✔
1122
        cdef DPCTLSyclEventRef htERef = NULL
1✔
1123
        cdef int status = -1
1✔
1124

1125
        # Create the array of dependent events if any
1126
        if nDE > 0:
1✔
1127
            depEvents = (
1128
                <DPCTLSyclEventRef*>malloc(nDE*sizeof(DPCTLSyclEventRef))
1✔
1129
            )
1130
            if not depEvents:
1✔
1131
                raise MemoryError()
×
1132
            else:
1133
                for idx, de in enumerate(dEvents):
1✔
1134
                    if isinstance(de, SyclEvent):
1✔
1135
                        depEvents[idx] = (<SyclEvent>de).get_event_ref()
1✔
1136
                    else:
1137
                        free(depEvents)
×
1138
                        raise TypeError(
×
1139
                            "A sequence of dpctl.SyclEvent is expected"
1140
                        )
1141

1142
        # increment reference counts to list of arguments
1143
        Py_INCREF(args)
1✔
1144

1145
        # schedule decrement
1146
        args_raw = <PyObject *>args
1✔
1147

1148
        htERef = async_dec_ref(
1✔
1149
            self.get_queue_ref(),
1✔
1150
            &args_raw, 1,
1151
            depEvents, nDE, &status
1152
        )
1153

1154
        free(depEvents)
1✔
1155
        if (status != 0):
1✔
1156
            with nogil: DPCTLEvent_Wait(htERef)
×
1157
            DPCTLEvent_Delete(htERef)
×
1158
            raise RuntimeError("Could not submit keep_args_alive host_task")
×
1159

1160
        return SyclEvent._create(htERef)
1✔
1161

1162

1163
    cpdef SyclEvent submit_async(
1✔
1164
        self,
1165
        SyclKernel kernel,
1166
        list args,
1167
        list gS,
1168
        list lS=None,
1169
        list dEvents=None
1✔
1170
    ):
1171
        """
1172
        Asynchronously submit :class:`dpctl.program.SyclKernel` for execution.
1173

1174
        Args:
1175
            kernel (dpctl.program.SyclKernel):
1176
                SYCL kernel object
1177
            args (List[object]):
1178
                List of kernel arguments
1179
            gS (List[int]):
1180
                Global iteration range. Must be a list of length 1, 2, or 3.
1181
            lS (List[int], optional):
1182
                Local iteration range. Must be ``None`` or have the same
1183
                length as ``gS`` and each element of ``gS`` must be divisible
1184
                by respective element of ``lS``.
1185
            dEvents (List[dpctl.SyclEvent], optional):
1186
                List of events indicating ordering of this task relative
1187
                to tasks associated with specified events.
1188

1189
        Returns:
1190
            dpctl.SyclEvent:
1191
                An event associated with submission of the kernel.
1192

1193
        .. note::
1194
            One must ensure that the lifetime of all kernel arguments
1195
            extends after the submitted task completes. It is not a concern for
1196
            scalar arguments since they are passed by value, but for
1197
            objects representing USM allocations which are passed to the kernel
1198
            as unified address space pointers.
1199

1200
            One way of accomplishing this is to use
1201
            :meth:`dpctl.SyclQueue._submit_keep_args_alive`.
1202
        """
1203
        cdef void **kargs = NULL
1✔
1204
        cdef _arg_data_type *kargty = NULL
1✔
1205
        cdef DPCTLSyclEventRef *depEvents = NULL
1✔
1206
        cdef DPCTLSyclEventRef Eref = NULL
1✔
1207
        cdef DPCTLSyclEventRef htEref = NULL
1✔
1208
        cdef int ret = 0
1✔
1209
        cdef size_t gRange[3]
1210
        cdef size_t lRange[3]
1211
        cdef size_t nGS = len(gS)
1✔
1212
        cdef size_t nLS = len(lS) if lS is not None else 0
1✔
1213
        cdef size_t nDE = len(dEvents) if dEvents is not None else 0
1✔
1214
        cdef PyObject *args_raw = NULL
1✔
1215
        cdef ssize_t i = 0
1✔
1216

1217
        # Allocate the arrays to be sent to DPCTLQueue_Submit
1218
        kargs = <void**>malloc(len(args) * sizeof(void*))
1✔
1219
        if not kargs:
1✔
1220
            raise MemoryError()
×
1221
        kargty = (
1222
            <_arg_data_type*>malloc(len(args)*sizeof(_arg_data_type))
1✔
1223
        )
1224
        if not kargty:
1✔
1225
            free(kargs)
×
1226
            raise MemoryError()
×
1227
        # Create the array of dependent events if any
1228
        if dEvents is not None and nDE > 0:
1✔
1229
            depEvents = (
1230
                <DPCTLSyclEventRef*>malloc(nDE*sizeof(DPCTLSyclEventRef))
1✔
1231
            )
1232
            if not depEvents:
1✔
1233
                free(kargs)
×
1234
                free(kargty)
×
1235
                raise MemoryError()
×
1236
            else:
1237
                for idx, de in enumerate(dEvents):
1✔
1238
                    if isinstance(de, SyclEvent):
1✔
1239
                        depEvents[idx] = (<SyclEvent>de).get_event_ref()
1✔
1240
                    else:
1241
                        free(kargs)
×
1242
                        free(kargty)
×
1243
                        free(depEvents)
×
1244
                        raise TypeError(
×
1245
                            "A sequence of dpctl.SyclEvent is expected"
1246
                        )
1247

1248
        # populate the args and argstype arrays
1249
        ret = self._populate_args(args, kargs, kargty)
1✔
1250
        if ret == -1:
1✔
1251
            free(kargs)
×
1252
            free(kargty)
×
1253
            free(depEvents)
×
1254
            raise TypeError("Unsupported type for a kernel argument")
×
1255

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

1320
        if Eref is NULL:
1✔
1321
            raise SyclKernelSubmitError(
×
1322
                "Kernel submission to Sycl queue failed."
1323
            )
1324

1325
        return SyclEvent._create(Eref)
1✔
1326

1327
    cpdef SyclEvent submit(
1✔
1328
        self,
1329
        SyclKernel kernel,
1330
        list args,
1331
        list gS,
1332
        list lS=None,
1333
        list dEvents=None
1✔
1334
    ):
1335
        """
1336
        Submit :class:`dpctl.program.SyclKernel` for execution.
1337

1338
        Args:
1339
            kernel (dpctl.program.SyclKernel):
1340
                SYCL kernel object
1341
            args (List[object]):
1342
                List of kernel arguments
1343
            gS (List[int]):
1344
                Global iteration range. Must be a list of length 1, 2, or 3.
1345
            lS (List[int], optional):
1346
                Local iteration range. Must be ``None`` or have the same
1347
                length as ``gS`` and each element of ``gS`` must be divisible
1348
                by respective element of ``lS``.
1349
            dEvents (List[dpctl.SyclEvent], optional):
1350
                List of events indicating ordering of this task relative
1351
                to tasks associated with specified events.
1352

1353
        Returns:
1354
            dpctl.SyclEvent:
1355
                An event which is always complete. May be ignored.
1356

1357
        .. note::
1358
            :meth:`dpctl.SyclQueue.submit` is a synchronizing method.
1359
            Use :meth:`dpctl.SyclQueue.submit_async` to avoid synchronization.
1360
        """
1361
        cdef SyclEvent e = self.submit_async(kernel, args, gS, lS, dEvents)
1✔
1362
        e.wait()
1✔
1363
        return e
1✔
1364

1365
    cpdef void wait(self):
1✔
1366
        with nogil: DPCTLQueue_Wait(self._queue_ref)
1✔
1367

1368
    cpdef memcpy(self, dest, src, size_t count):
1✔
1369
        """Copy memory from `src` to `dst`"""
1370
        cdef DPCTLSyclEventRef ERef = NULL
1✔
1371

1372
        ERef = _memcpy_impl(<SyclQueue>self, dest, src, count, NULL, 0)
1✔
1373
        if (ERef is NULL):
1✔
1374
            raise RuntimeError(
×
1375
                "SyclQueue.memcpy operation encountered an error"
1376
            )
1377
        with nogil: DPCTLEvent_Wait(ERef)
1✔
1378
        DPCTLEvent_Delete(ERef)
1✔
1379

1380
    cpdef SyclEvent memcpy_async(self, dest, src, size_t count, list dEvents=None):
1✔
1381
        """Copy memory from ``src`` to ``dst``"""
1382
        cdef DPCTLSyclEventRef ERef = NULL
1✔
1383
        cdef DPCTLSyclEventRef *depEvents = NULL
1✔
1384
        cdef size_t nDE = 0
1✔
1385

1386
        if dEvents is None:
1✔
1387
            ERef = _memcpy_impl(<SyclQueue>self, dest, src, count, NULL, 0)
1✔
1388
        else:
1389
            nDE = len(dEvents)
1✔
1390
            depEvents = (
1391
                <DPCTLSyclEventRef*>malloc(nDE*sizeof(DPCTLSyclEventRef))
1✔
1392
            )
1393
            if depEvents is NULL:
1✔
1394
                raise MemoryError()
×
1395
            else:
1396
                for idx, de in enumerate(dEvents):
1✔
1397
                    if isinstance(de, SyclEvent):
1✔
1398
                        depEvents[idx] = (<SyclEvent>de).get_event_ref()
1✔
1399
                    else:
1400
                        free(depEvents)
×
1401
                        raise TypeError(
×
1402
                            "A sequence of dpctl.SyclEvent is expected"
1403
                        )
1404
            ERef = _memcpy_impl(self, dest, src, count, depEvents, nDE)
1✔
1405
            free(depEvents)
1✔
1406

1407
        if (ERef is NULL):
1✔
1408
            raise RuntimeError(
×
1409
                "SyclQueue.memcpy operation encountered an error"
1410
            )
1411

1412
        return SyclEvent._create(ERef)
1✔
1413

1414
    cpdef prefetch(self, mem, size_t count=0):
1✔
1415
        cdef void *ptr
1416
        cdef DPCTLSyclEventRef ERef = NULL
1✔
1417

1418
        if isinstance(mem, _Memory):
1✔
1419
            ptr = <void*>(<_Memory>mem).get_data_ptr()
1✔
1420
        else:
1421
            raise TypeError("Parameter `mem` should have type _Memory")
1✔
1422

1423
        if (count <=0 or count > mem.nbytes):
1✔
1424
            count = mem.nbytes
×
1425

1426
        ERef = DPCTLQueue_Prefetch(self._queue_ref, ptr, count)
1✔
1427
        if (ERef is NULL):
1✔
1428
            raise RuntimeError(
×
1429
                "SyclQueue.prefetch encountered an error"
1430
            )
1431
        with nogil: DPCTLEvent_Wait(ERef)
1✔
1432
        DPCTLEvent_Delete(ERef)
1✔
1433

1434
    cpdef mem_advise(self, mem, size_t count, int advice):
1✔
1435
        cdef void *ptr
1436
        cdef DPCTLSyclEventRef ERef = NULL
1✔
1437

1438
        if isinstance(mem, _Memory):
1✔
1439
            ptr = <void*>(<_Memory>mem).get_data_ptr()
1✔
1440
        else:
1441
            raise TypeError("Parameter `mem` should have type _Memory")
1✔
1442

1443
        if (count <=0 or count > mem.nbytes):
1✔
1444
            count = mem.nbytes
×
1445

1446
        ERef = DPCTLQueue_MemAdvise(self._queue_ref, ptr, count, advice)
1✔
1447
        if (ERef is NULL):
1✔
1448
            raise RuntimeError(
×
1449
                "SyclQueue.mem_advise operation encountered an error"
1450
            )
1451
        with nogil: DPCTLEvent_Wait(ERef)
1✔
1452
        DPCTLEvent_Delete(ERef)
1✔
1453

1454
    @property
1455
    def is_in_order(self):
1456
        """``True`` if :class:`.SyclQueue`` is in-order,
1457
        ``False`` if it is out-of-order.
1458

1459
        :Example:
1460

1461
            ..code-block:: python
1462

1463
                >>> import dpctl
1464
                >>> q = dpctl.SyclQueue("cpu")
1465
                >>> q.is_in_order
1466
                False
1467
                >>> q = dpctl.SyclQueue("cpu", property="in_order")
1468
                >>> q.is_in_order
1469
                True
1470

1471
        Returns:
1472
            bool:
1473
                Indicates whether this :class:`.SyclQueue` was created
1474
                with ``property="in_order"``.
1475

1476
        .. note::
1477
            Unless requested otherwise, :class:`.SyclQueue` is constructed
1478
            to support out-of-order execution.
1479
        """
1480
        return DPCTLQueue_IsInOrder(self._queue_ref)
1✔
1481

1482
    @property
1483
    def has_enable_profiling(self):
1484
        """
1485
        ``True`` if :class:`.SyclQueue` was constructed with
1486
        ``"enabled_profiling"`` property, ``False`` otherwise.
1487

1488
        :Example:
1489

1490
            ..code-block:: python
1491

1492
                >>> import dpctl
1493
                >>> q = dpctl.SyclQueue("cpu")
1494
                >>> q.has_enable_profiling
1495
                False
1496
                >>> q = dpctl.SyclQueue("cpu", property="enable_profiling")
1497
                >>> q.has_enable_profiling
1498
                True
1499

1500
        Returns:
1501
            bool:
1502
                Whether profiling information for tasks submitted
1503
                to this :class:`.SyclQueue` is being collected.
1504

1505
        .. note::
1506
            Profiling information can be accessed using
1507
            properties
1508
            :attr:`dpctl.SyclEvent.profiling_info_submit`,
1509
            :attr:`dpctl.SyclEvent.profiling_info_start`, and
1510
            :attr:`dpctl.SyclEvent.profiling_info_end`. It is
1511
            also necessary for proper working of
1512
            :class:`dpctl.SyclTimer`.
1513

1514
            Collection of profiling information is not enabled
1515
            by default.
1516
        """
1517
        return DPCTLQueue_HasEnableProfiling(self._queue_ref)
1✔
1518

1519
    @property
1520
    def __name__(self):
1521
        "The name of :class:`dpctl.SyclQueue` object"
1522
        return "SyclQueue"
1✔
1523

1524
    def __repr__(self):
1525
        cdef cpp_bool in_order = DPCTLQueue_IsInOrder(self._queue_ref)
1✔
1526
        cdef cpp_bool en_prof = DPCTLQueue_HasEnableProfiling(self._queue_ref)
1✔
1527
        if in_order or en_prof:
1✔
1528
            prop = []
1✔
1529
            if in_order:
1✔
1530
                prop.append("in_order")
1✔
1531
            if en_prof:
1✔
1532
                prop.append("enable_profiling")
1✔
1533
            return (
1✔
1534
                "<dpctl."
1535
                + self.__name__
1✔
1536
                + " at {}, property={}>".format(hex(id(self)), prop)
1✔
1537
            )
1538
        else:
1539
            return "<dpctl." + self.__name__ + " at {}>".format(hex(id(self)))
1✔
1540

1541
    def __hash__(self):
1542
        """
1543
        Returns a hash value by hashing the underlying ``sycl::queue`` object.
1544

1545
        Returns:
1546
            int:
1547
                Hash value of this :class:`.SyclQueue` instance
1548
        """
1549
        return DPCTLQueue_Hash(self._queue_ref)
1✔
1550

1551
    def _get_capsule(self):
1✔
1552
        cdef DPCTLSyclQueueRef QRef = NULL
1✔
1553
        QRef = DPCTLQueue_Copy(self._queue_ref)
1✔
1554
        if (QRef is NULL):
1✔
1555
            raise ValueError("SyclQueue copy failed.")
×
1556
        return pycapsule.PyCapsule_New(
1✔
1557
            <void *>QRef, "SyclQueueRef", &_queue_capsule_deleter
1✔
1558
        )
1559

1560
    cpdef SyclEvent submit_barrier(self, dependent_events=None):
1✔
1561
        """
1562
        Submits a barrier to this queue.
1563

1564
        Args:
1565
            dependent_events:
1566
                List[dpctl.SyclEvent]:
1567
                    List or tuple of events that must complete
1568
                    before this task may begin execution.
1569

1570
        Returns:
1571
            dpctl.SyclEvent:
1572
                Event associated with the submitted task
1573
        """
1574
        cdef DPCTLSyclEventRef *depEvents = NULL
1✔
1575
        cdef DPCTLSyclEventRef ERef = NULL
1✔
1576
        cdef size_t nDE = 0
1✔
1577
        # Create the array of dependent events if any
1578
        if (dependent_events is None or
1✔
1579
            (isinstance(dependent_events, collections.abc.Sequence) and
1✔
1580
             all([type(de) is SyclEvent for de in dependent_events]))):
1✔
1581
            nDE = 0 if dependent_events is None else len(dependent_events)
1✔
1582
        else:
1583
            raise TypeError(
1✔
1584
                "dependent_events must either None, or a sequence of "
1585
                ":class:`dpctl.SyclEvent` objects")
1586
        if nDE > 0:
1✔
1587
            depEvents = (
1588
                <DPCTLSyclEventRef*>malloc(nDE*sizeof(DPCTLSyclEventRef))
1✔
1589
            )
1590
            if not depEvents:
1✔
1591
                raise MemoryError()
×
1592
            else:
1593
                for idx, de in enumerate(dependent_events):
1✔
1594
                    depEvents[idx] = (<SyclEvent>de).get_event_ref()
1✔
1595

1596
        ERef = DPCTLQueue_SubmitBarrierForEvents(
1✔
1597
            self.get_queue_ref(), depEvents, nDE)
1✔
1598
        if (depEvents is not NULL):
1✔
1599
            free(depEvents)
1✔
1600
        if ERef is NULL:
1✔
1601
            raise SyclKernelSubmitError(
×
1602
                "Barrier submission to Sycl queue failed."
1603
            )
1604

1605
        return SyclEvent._create(ERef)
1✔
1606

1607
    @property
1608
    def name(self):
1609
        """Returns the device name for the device
1610
        associated with this queue.
1611

1612
        Returns:
1613
            str:
1614
                The name of the device as a string.
1615
        """
1616
        return self.sycl_device.name
1✔
1617

1618
    @property
1619
    def driver_version(self):
1620
        """Returns the driver version for the device
1621
        associated with this queue.
1622

1623
        Returns:
1624
            str:
1625
                The driver version of the device as a string.
1626
        """
1627
        return self.sycl_device.driver_version
1✔
1628

1629
    def print_device_info(self):
1✔
1630
        """ Print information about the SYCL device
1631
        associated with this queue.
1632
        """
1633
        self.sycl_device.print_device_info()
1✔
1634

1635

1636
cdef api DPCTLSyclQueueRef SyclQueue_GetQueueRef(SyclQueue q):
1✔
1637
    """
1638
    C-API function to get opaque queue reference from
1639
    :class:`dpctl.SyclQueue` instance.
1640
    """
1641
    return q.get_queue_ref()
1✔
1642

1643

1644
cdef api SyclQueue SyclQueue_Make(DPCTLSyclQueueRef QRef):
1✔
1645
    """
1646
    C-API function to create :class:`dpctl.SyclQueue` instance
1647
    from the given opaque queue reference.
1648
    """
1649
    cdef DPCTLSyclQueueRef copied_QRef = DPCTLQueue_Copy(QRef)
1✔
1650
    return SyclQueue._create(copied_QRef)
1✔
1651

1652
cdef class _WorkGroupMemory:
1653
    def __dealloc__(self):
1654
        if(self._mem_ref):
1✔
1655
            DPCTLWorkGroupMemory_Delete(self._mem_ref)
1✔
1656

1657
cdef class WorkGroupMemory:
1658
    """
1659
    WorkGroupMemory(nbytes)
1660
    Python class representing the ``work_group_memory`` class from the
1661
    Workgroup Memory oneAPI SYCL extension for low-overhead allocation of local
1662
    memory shared by the workitems in a workgroup.
1663

1664
    This class is intended be used as kernel argument when launching kernels.
1665

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

1669
    There are multiple ways to create a `WorkGroupMemory`.
1670

1671
    - If the constructor is invoked with just a single argument, this argument
1672
      is interpreted as the number of bytes to allocated in the shared local
1673
      memory.
1674

1675
    - If the constructor is invoked with two arguments, the first argument is
1676
      interpreted as the datatype of the local memory, using the numpy type
1677
      naming scheme.
1678
      The second argument is interpreted as the number of elements to allocate.
1679
      The number of bytes to allocate is then computed from the byte size of
1680
      the data type and the element count.
1681

1682
    Args:
1683
        args:
1684
            Variadic argument, see class documentation.
1685

1686
    Raises:
1687
        TypeError: In case of incorrect arguments given to constructors,
1688
                   unexpected types of input arguments.
1689
    """
1690
    def __cinit__(self, *args):
1691
        cdef size_t nbytes
1692
        if not DPCTLWorkGroupMemory_Available():
1✔
1693
            raise RuntimeError("Workgroup memory extension not available")
×
1694

1695
        if not (0 < len(args) < 3):
1✔
1696
            raise TypeError("WorkGroupMemory constructor takes 1 or 2 "
×
1697
                            f"arguments, but {len(args)} were given")
×
1698

1699
        if len(args) == 1:
1✔
1700
            if not isinstance(args[0], numbers.Integral):
1✔
1701
                raise TypeError("WorkGroupMemory single argument constructor"
×
1702
                                "expects first argument to be `int`",
1703
                                f"but got {type(args[0])}")
×
1704
            nbytes = <size_t>(args[0])
1✔
1705
        else:
1706
            if not isinstance(args[0], str):
×
1707
                raise TypeError("WorkGroupMemory constructor expects first"
×
1708
                                f"argument to be `str`, but got {type(args[0])}")
×
1709
            if not isinstance(args[1], numbers.Integral):
×
1710
                raise TypeError("WorkGroupMemory constructor expects second"
×
1711
                                f"argument to be `int`, but got {type(args[1])}")
×
1712
            dtype = <str>(args[0])
×
1713
            count = <size_t>(args[1])
×
1714
            if not dtype[0] in ["i", "u", "f"]:
×
1715
                raise TypeError(f"Unrecognized type value: '{dtype}'")
×
1716
            try:
×
1717
                bit_width = int(dtype[1:])
×
1718
            except ValueError:
×
1719
                raise TypeError(f"Unrecognized type value: '{dtype}'")
×
1720

1721
            byte_size = <size_t>bit_width
×
1722
            nbytes = count * byte_size
×
1723

1724
        self._mem_ref = DPCTLWorkGroupMemory_Create(nbytes)
1✔
1725

1726
    """Check whether the work_group_memory extension is available"""
1727
    @staticmethod
1✔
1728
    def is_available():
1729
        return DPCTLWorkGroupMemory_Available()
1✔
1730

1731
    property _ref:
1732
        """Returns the address of the C API ``DPCTLWorkGroupMemoryRef``
1733
        pointer as a ``size_t``.
1734
        """
1735
        def __get__(self):
1736
            return <size_t>self._mem_ref
1✔
1737

1738

1739
cdef class _RawKernelArg:
1740
    def __dealloc(self):
1✔
NEW
1741
        if(self._arg_ref):
×
NEW
1742
            DPCTLRawKernelArg_Delete(self._arg_ref)
×
NEW
1743
        if(self._is_buf):
×
NEW
1744
            PyBuffer_Release(&(self._buf))
×
1745

1746
cdef class RawKernelArg:
1747
    """
1748
    RawKernelArg(*args)
1749
    Python class representing the ``raw_kernel_arg`` class from the Raw Kernel
1750
    Argument oneAPI SYCL extension for passing binary data as data to kernels.
1751

1752
    This class is intended to be used as kernel argument when launching kernels.
1753

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

1757
    There are multiple ways to create a ``RawKernelArg``.
1758

1759
    - If the constructor is invoked with just a single argument, this argument
1760
      is expected to expose the Python buffer interface. The raw kernel arg will
1761
      be constructed from the data in that buffer.
1762

1763
    - If the constructor is invoked with two arguments, the first argument is
1764
      interpreted as the number of bytes in the binary argument, while the
1765
      second argument is interpreted as a pointer to the data. Note that the
1766
      raw kernel arg does not own or copy the data, so the pointed-to object
1767
      must be kept alive by the user until kernel launch.
1768

1769
    Args:
1770
        args:
1771
            Variadic argument, see class documentation.
1772

1773
    Raises:
1774
        TypeError: In case of incorrect arguments given to constructurs,
1775
                   unexpected types of input arguments.
1776
    """
1777
    def __cinit__(self, *args):
1778
        cdef void* ptr = NULL
1✔
1779
        cdef size_t count
1780
        cdef int ret_code = 0
1✔
1781

1782
        if not DPCTLRawKernelArg_Available():
1✔
NEW
1783
            raise RuntimeError("Raw kernel arg extension not available")
×
1784

1785
        if not (0 < len(args) < 3):
1✔
NEW
1786
            raise TypeError("RawKernelArg constructor takes 1 or 2 "
×
NEW
1787
                            f"arguments, but {len(args)} were given")
×
1788

1789
        if len(args) == 1:
1✔
1790
            if not _is_buffer(args[0]):
1✔
NEW
1791
                raise TypeError("RawKernelArg single argument constructor"
×
1792
                                "expects argument to be buffer",
NEW
1793
                                f"but got {type(args[0])}")
×
1794

1795
            ret_code = PyObject_GetBuffer(args[0], &(self._buf), PyBUF_SIMPLE | PyBUF_ANY_CONTIGUOUS)
1✔
1796
            if ret_code != 0: # pragma: no cover
NEW
1797
                raise RuntimeError("Could not access buffer")
×
1798

1799
            ptr = self._buf.buf
1✔
1800
            count = self._buf.len
1✔
1801
            self._is_buf = True
1✔
1802
        else:
1803
            if not isinstance(args[0], numbers.Integral):
1✔
NEW
1804
                raise TypeError("RawKernelArg constructor expects first"
×
1805
                                "argument to be `int`, but got {type(args[0])}")
1806
            if not isinstance(args[1], numbers.Integral):
1✔
NEW
1807
                raise TypeError("RawKernelArg constructor expects second"
×
1808
                                "argument to be `int`, but got {type(args[1])}")
1809

1810
            self._is_buf = False
1✔
1811
            count = args[0]
1✔
1812
            ptr = <void*>(<unsigned long long>args[1])
1✔
1813

1814
        self._arg_ref = DPCTLRawKernelArg_Create(ptr, count)
1✔
1815

1816
    """Check whether the raw_kernel_arg extension is available"""
1817
    @staticmethod
1✔
1818
    def is_available():
1819
        return DPCTLRawKernelArg_Available();
1✔
1820

1821
    property _ref:
1822
        """Returns the address of the C API ``DPCTLRawKernelArgRef`` pointer
1823
        as a ``size_t``.
1824
        """
1825
        def __get__(self):
NEW
1826
            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