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

IntelPython / dpctl / 16568940056

28 Jul 2025 12:24PM UTC coverage: 85.894% (+0.01%) from 85.882%
16568940056

Pull #2109

github

web-flow
Merge f0c7c427a into 0dbd49579
Pull Request #2109: Extend build_locally.py with `--target-cuda` and `--target-hip` arguments

3228 of 3880 branches covered (83.2%)

Branch coverage included in aggregate %.

12238 of 14126 relevant lines covered (86.63%)

5854.02 hits per line

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

93.13
/dpctl/memory/_sycl_usm_array_interface_utils.pxi
1
#                      Data Parallel Control (dpctl)
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
cdef bint _valid_usm_ptr_and_context(DPCTLSyclUSMRef ptr, SyclContext ctx):
1✔
18
    usm_type = _Memory.get_pointer_type(ptr, ctx)
1✔
19
    return usm_type in (b"shared", b"device", b"host")
1✔
20

21

22
cdef DPCTLSyclQueueRef _queue_ref_copy_from_SyclQueue(
×
23
    DPCTLSyclUSMRef ptr, SyclQueue q
24
):
25
    """ Check that USM ptr is consistent with SYCL context in the queue,
26
    and return a copy of QueueRef if so, or NULL otherwise.
27
    """
28
    cdef SyclContext ctx = q.get_sycl_context()
1✔
29
    if (_valid_usm_ptr_and_context(ptr, ctx)):
1✔
30
        return DPCTLQueue_Copy(q.get_queue_ref())
1✔
31
    else:
32
        return NULL
×
33

34

35
cdef DPCTLSyclQueueRef _queue_ref_copy_from_USMRef_and_SyclContext(
1✔
36
    DPCTLSyclUSMRef ptr, SyclContext ctx
37
):
38
    """ Obtain device from pointer and sycl context, use
39
        context and device to create a queue from which this memory
40
        can be accessible.
41
    """
42
    cdef SyclDevice dev = _Memory.get_pointer_device(ptr, ctx)
1✔
43
    cdef DPCTLSyclContextRef CRef = ctx.get_context_ref()
1✔
44
    cdef DPCTLSyclDeviceRef DRef = dev.get_device_ref()
1✔
45
    return DPCTLQueue_Create(CRef, DRef, NULL, 0)
1✔
46

47

48
cdef DPCTLSyclQueueRef get_queue_ref_from_ptr_and_syclobj(
×
49
        DPCTLSyclUSMRef ptr, object syclobj
50
):
51
    """ Constructs queue from pointer and syclobject from
52
        __sycl_usm_array_interface__
53
    """
54
    cdef SyclContext ctx
55
    if type(syclobj) is SyclQueue:
1✔
56
        return _queue_ref_copy_from_SyclQueue(ptr, <SyclQueue> syclobj)
1✔
57
    elif type(syclobj) is SyclContext:
1✔
58
        ctx = <SyclContext>syclobj
1✔
59
        return _queue_ref_copy_from_USMRef_and_SyclContext(ptr, ctx)
1✔
60
    elif type(syclobj) is str:
1✔
61
        q = SyclQueue(syclobj)
1✔
62
        return _queue_ref_copy_from_SyclQueue(ptr, <SyclQueue> q)
1✔
63
    elif pycapsule.PyCapsule_IsValid(syclobj, "SyclQueueRef"):
1✔
64
        q = SyclQueue(syclobj)
1✔
65
        return _queue_ref_copy_from_SyclQueue(ptr, <SyclQueue> q)
1✔
66
    elif pycapsule.PyCapsule_IsValid(syclobj, "SyclContextRef"):
1✔
67
        ctx = <SyclContext>SyclContext(syclobj)
1✔
68
        return _queue_ref_copy_from_USMRef_and_SyclContext(ptr, ctx)
1✔
69
    elif hasattr(syclobj, "_get_capsule"):
1✔
70
        cap = syclobj._get_capsule()
1✔
71
        if pycapsule.PyCapsule_IsValid(cap, "SyclQueueRef"):
1✔
72
            q = SyclQueue(cap)
1✔
73
            return _queue_ref_copy_from_SyclQueue(ptr, <SyclQueue> q)
1✔
74
        elif pycapsule.PyCapsule_IsValid(cap, "SyclContextRef"):
1✔
75
            ctx = <SyclContext>SyclContext(cap)
1✔
76
            return _queue_ref_copy_from_USMRef_and_SyclContext(ptr, ctx)
1✔
77
        else:
78
            return NULL
×
79
    else:
80
        return NULL
1✔
81

82

83
cdef object _pointers_from_shape_and_stride(
×
84
    int nd, object ary_shape, Py_ssize_t itemsize,
85
    Py_ssize_t ary_offset, object ary_strides
86
):
87
    """
88
    Internal utility: for given array data about shape/layout/element
89
    compute left-most displacement when enumerating all elements of the array
90
    and the number of bytes of memory between the left-most and right-most
91
    displacements.
92

93
    Returns: tuple(min_disp, nbytes)
94
    """
95
    cdef Py_ssize_t nelems = 1
1✔
96
    cdef Py_ssize_t min_disp = 0
1✔
97
    cdef Py_ssize_t max_disp = 0
1✔
98
    cdef int i
99
    cdef Py_ssize_t sh_i = 0
1✔
100
    cdef Py_ssize_t str_i = 0
1✔
101
    if (nd > 0):
1✔
102
        if (ary_strides is None):
1✔
103
            nelems = 1
1✔
104
            for si in ary_shape:
1✔
105
                sh_i = int(si)
1✔
106
                if (sh_i < 0):
1✔
107
                    raise ValueError("Array shape elements need to be positive")
1✔
108
                nelems = nelems * sh_i
1✔
109
            return (ary_offset, max(nelems, 1) * itemsize)
1✔
110
        else:
111
            min_disp = ary_offset
1✔
112
            max_disp = ary_offset
1✔
113
            for i in range(nd):
1✔
114
                str_i = int(ary_strides[i])
1✔
115
                sh_i = int(ary_shape[i])
1✔
116
                if (sh_i < 0):
1✔
117
                    raise ValueError("Array shape elements need to be positive")
1✔
118
                if (sh_i > 0):
1✔
119
                    if (str_i > 0):
1✔
120
                        max_disp += str_i * (sh_i - 1)
1✔
121
                    else:
122
                        min_disp += str_i * (sh_i - 1)
1✔
123
                else:
124
                    nelems = 0
×
125
            if nelems == 0:
1✔
126
                return (ary_offset, itemsize)
×
127
            return (min_disp, (max_disp - min_disp + 1) * itemsize)
1✔
128
    elif (nd == 0):
1✔
129
        return (ary_offset, itemsize)
1✔
130
    else:
131
        raise ValueError("Array dimensions can not be negative")
×
132

133

134
cdef class _USMBufferData:
135
    """
136
    Internal data struct populated from parsing
137
    `__sycl_usm_array_interface__` dictionary
138
    """
139
    cdef DPCTLSyclUSMRef p
140
    cdef int writable
141
    cdef object dt
142
    cdef Py_ssize_t itemsize
143
    cdef Py_ssize_t nbytes
144
    cdef SyclQueue queue
145

146
    @staticmethod
×
147
    cdef _USMBufferData from_sycl_usm_ary_iface(dict ary_iface):
148
        cdef object ary_data_tuple = ary_iface.get("data", None)
1✔
149
        cdef object ary_typestr = ary_iface.get("typestr", None)
1✔
150
        cdef object ary_shape = ary_iface.get("shape", None)
1✔
151
        cdef object ary_strides = ary_iface.get("strides", None)
1✔
152
        cdef object ary_syclobj = ary_iface.get("syclobj", None)
1✔
153
        cdef Py_ssize_t ary_offset = ary_iface.get("offset", 0)
1✔
154
        cdef int ary_version = ary_iface.get("version", 0)
1✔
155
        cdef size_t arr_data_ptr = 0
1✔
156
        cdef DPCTLSyclUSMRef memRef = NULL
1✔
157
        cdef Py_ssize_t itemsize = -1
1✔
158
        cdef int writable = -1
1✔
159
        cdef int nd = -1
1✔
160
        cdef DPCTLSyclQueueRef QRef = NULL
1✔
161
        cdef object dt
162
        cdef _USMBufferData buf
163
        cdef SyclDevice dev
164
        cdef SyclContext ctx
165

166
        if ary_version != 1:
1✔
167
            raise ValueError(("__sycl_usm_array_interface__ is malformed:"
1✔
168
                              " dict('version': {}) is unexpected."
169
                              " The only recognized version is 1.").format(
1✔
170
                                  ary_version))
1✔
171
        if not ary_data_tuple or len(ary_data_tuple) != 2:
1✔
172
            raise ValueError("__sycl_usm_array_interface__ is malformed:"
1✔
173
                             " 'data' field is required, and must be a tuple"
174
                             " (usm_pointer, is_writable_boolean).")
175
        arr_data_ptr = <size_t>ary_data_tuple[0]
1✔
176
        writable = 1 if ary_data_tuple[1] else 0
1✔
177
        # Check that memory and syclobj are consistent:
178
        # (USM pointer is bound to this sycl context)
179
        memRef = <DPCTLSyclUSMRef>arr_data_ptr
1✔
180
        QRef = get_queue_ref_from_ptr_and_syclobj(memRef, ary_syclobj)
1✔
181
        if (QRef is NULL):
1✔
182
            raise ValueError("__sycl_usm_array_interface__ is malformed:"
1✔
183
                             " 'data' field is not consistent with 'syclobj'"
184
                             " field, the pointer {} is not bound to"
185
                             " SyclContext derived from"
186
                             " dict('syclobj': {}).".format(
1✔
187
                                 hex(arr_data_ptr), ary_syclobj))
1✔
188
        # shape must be present
189
        if ary_shape is None or not (
1✔
190
                isinstance(ary_shape, collections.abc.Sized) and
1✔
191
                isinstance(ary_shape, collections.abc.Iterable)):
1✔
192
            DPCTLQueue_Delete(QRef)
1✔
193
            raise ValueError("Shape entry is a required element of "
1✔
194
                             "`__sycl_usm_array_interface__` dictionary")
195
        nd = len(ary_shape)
1✔
196
        try:
1✔
197
            dt = np.dtype(ary_typestr)
1✔
198
            if (dt.hasobject or not (np.issubdtype(dt.type, np.number) or
1✔
199
                                     dt.type is np.bool_)):
1✔
200
                DPCTLQueue_Delete(QRef)
1✔
201
                raise TypeError("Only integer types, floating and complex "
1✔
202
                                "floating types are supported.")
203
            itemsize = <Py_ssize_t> (dt.itemsize)
1✔
204
        except TypeError as e:
1✔
205
            raise ValueError(
1✔
206
                "__sycl_usm_array_interface__ is malformed:"
207
                " dict('typestr': {}) is unexpected. ".format(ary_typestr)
1✔
208
            ) from e
1✔
209

210
        if (ary_strides is None or (
1✔
211
                isinstance(ary_strides, collections.abc.Sized) and
1✔
212
                isinstance(ary_strides, collections.abc.Iterable) and
1✔
213
                len(ary_strides) == nd)):
1✔
214
            min_disp, nbytes = _pointers_from_shape_and_stride(
1✔
215
                nd, ary_shape, itemsize, ary_offset, ary_strides)
216
        else:
217
            DPCTLQueue_Delete(QRef)
1✔
218
            raise ValueError("__sycl_usm_array_interface__ is malformed: "
1✔
219
                             "'strides' must be a tuple or "
220
                             "list of the same length as shape")
221

222
        buf = _USMBufferData.__new__(_USMBufferData)
1✔
223
        buf.p = <DPCTLSyclUSMRef>(
1✔
224
            arr_data_ptr + (<Py_ssize_t>min_disp) * itemsize)
1✔
225
        buf.writable = writable
1✔
226
        buf.itemsize = itemsize
1✔
227
        buf.nbytes = <Py_ssize_t> nbytes
1✔
228

229
        buf.queue = SyclQueue._create(QRef)
1✔
230

231
        return buf
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc