Skip to content

Commit 5a5170b

Browse files
Merge pull request #443 from IntelPython/free-function-to-determinate-usm-type
Added free Python function as_usm_memory(obj)
2 parents 31f95d6 + 4eac942 commit 5a5170b

File tree

3 files changed

+154
-32
lines changed

3 files changed

+154
-32
lines changed

dpctl/memory/__init__.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@
3030
`memoryview`, or `array.array` classes.
3131
3232
"""
33-
from ._memory import MemoryUSMDevice, MemoryUSMHost, MemoryUSMShared
33+
from ._memory import (
34+
MemoryUSMDevice,
35+
MemoryUSMHost,
36+
MemoryUSMShared,
37+
as_usm_memory,
38+
)
3439

35-
__all__ = ["MemoryUSMDevice", "MemoryUSMHost", "MemoryUSMShared"]
40+
__all__ = [
41+
"MemoryUSMDevice",
42+
"MemoryUSMHost",
43+
"MemoryUSMShared",
44+
"as_usm_memory",
45+
]

dpctl/memory/_memory.pyx

Lines changed: 140 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,49 @@ def _to_memory(unsigned char[::1] b, str usm_kind):
116116
return res
117117

118118

119+
def get_usm_pointer_type(ptr, syclobj):
120+
"""
121+
get_usm_pointer_type(ptr, syclobj)
122+
123+
Gives the SYCL(TM) USM pointer type, using ``sycl::get_pointer_type``,
124+
returning one of 4 possible strings: 'shared', 'host', 'device',
125+
or 'unknown'.
126+
127+
Args:
128+
ptr: int
129+
A pointer stored as size_t Python integer.
130+
syclobj: :class:`dpctl.SyclContext` or :class:`dpctl.SyclQueue`
131+
Python object providing :class:`dpctl.SyclContext` against which
132+
to query for the pointer type.
133+
Returns:
134+
'unknown' if the pointer does not represent USM allocation made using
135+
the given context. Otherwise, returns 'shared', 'device', or 'host'
136+
type of the allocation.
137+
"""
138+
cdef const char* kind
139+
cdef SyclContext ctx
140+
cdef SyclQueue q
141+
cdef DPCTLSyclUSMRef USMRef = NULL
142+
try:
143+
USMRef = <DPCTLSyclUSMRef>(<size_t> ptr)
144+
except Exception as e:
145+
raise TypeError(
146+
"First argument {} could not be converted to Python integer of "
147+
"size_t".format(ptr)
148+
) from e
149+
if isinstance(syclobj, SyclContext):
150+
ctx = <SyclContext>(syclobj)
151+
return _Memory.get_pointer_type(USMRef, ctx).decode("UTF-8")
152+
elif isinstance(syclobj, SyclQueue):
153+
q = <SyclQueue>(syclobj)
154+
ctx = q.get_sycl_context()
155+
return _Memory.get_pointer_type(USMRef, ctx).decode("UTF-8")
156+
raise TypeError(
157+
"Second argument {} is expected to be an instance of "
158+
"SyclContext or SyclQueue".format(syclobj)
159+
)
160+
161+
119162
cdef class _Memory:
120163
""" Internal class implementing methods common to
121164
MemoryUSMShared, MemoryUSMDevice, MemoryUSMHost
@@ -282,7 +325,7 @@ cdef class _Memory:
282325

283326
def __repr__(self):
284327
return (
285-
"<SYCL(TM) USM-{} allocated memory block of {} bytes at {}>"
328+
"<SYCL(TM) USM-{} allocation of {} bytes at {}>"
286329
.format(
287330
self.get_usm_type(),
288331
self.nbytes,
@@ -316,31 +359,37 @@ cdef class _Memory:
316359
return iface
317360

318361
def get_usm_type(self, syclobj=None):
362+
"""
363+
get_usm_type(syclobj=None)
364+
365+
Returns the type of USM allocation using Sycl context carried by
366+
`syclobj` keyword argument. Value of None is understood to query
367+
against `self.sycl_context` - the context used to create the
368+
allocation.
369+
"""
319370
cdef const char* kind
320371
cdef SyclContext ctx
321372
cdef SyclQueue q
322373
if syclobj is None:
323374
ctx = self._context
324-
kind = DPCTLUSM_GetPointerType(
325-
self.memory_ptr, ctx.get_context_ref()
326-
)
375+
return _Memory.get_pointer_type(
376+
self.memory_ptr, ctx
377+
).decode("UTF-8")
327378
elif isinstance(syclobj, SyclContext):
328379
ctx = <SyclContext>(syclobj)
329-
kind = DPCTLUSM_GetPointerType(
330-
self.memory_ptr, ctx.get_context_ref()
331-
)
380+
return _Memory.get_pointer_type(
381+
self.memory_ptr, ctx
382+
).decode("UTF-8")
332383
elif isinstance(syclobj, SyclQueue):
333384
q = <SyclQueue>(syclobj)
334385
ctx = q.get_sycl_context()
335-
kind = DPCTLUSM_GetPointerType(
336-
self.memory_ptr, ctx.get_context_ref()
337-
)
338-
else:
339-
raise ValueError(
340-
"syclobj keyword can be either None, or an instance of "
341-
"SyclContext or SyclQueue"
342-
)
343-
return kind.decode('UTF-8')
386+
return _Memory.get_pointer_type(
387+
self.memory_ptr, ctx
388+
).decode("UTF-8")
389+
raise TypeError(
390+
"syclobj keyword can be either None, or an instance of "
391+
"SyclContext or SyclQueue"
392+
)
344393

345394
cpdef copy_to_host(self, obj=None):
346395
"""
@@ -457,7 +506,24 @@ cdef class _Memory:
457506

458507
@staticmethod
459508
cdef bytes get_pointer_type(DPCTLSyclUSMRef p, SyclContext ctx):
460-
"""Returns USM-type of given pointer `p` in given sycl context `ctx`"""
509+
"""
510+
get_pointer_type(p, ctx)
511+
512+
Gives the SYCL(TM) USM pointer type, using ``sycl::get_pointer_type``,
513+
returning one of 4 possible strings: 'shared', 'host', 'device', or
514+
'unknown'.
515+
516+
Args:
517+
p: DPCTLSyclUSMRef
518+
A pointer to test the type of.
519+
ctx: :class:`dpctl.SyclContext`
520+
Python object providing :class:`dpctl.SyclContext` against
521+
which to query for the pointer type.
522+
Returns:
523+
b'unknown' if the pointer does not represent USM allocation made
524+
using the given context. Otherwise, returns b'shared', b'device',
525+
or b'host' type of the allocation.
526+
"""
461527
cdef const char * usm_type = DPCTLUSM_GetPointerType(
462528
p, ctx.get_context_ref()
463529
)
@@ -530,12 +596,14 @@ cdef class MemoryUSMShared(_Memory):
530596
allocates nbytes of USM shared memory.
531597
532598
Non-positive alignments are not used (malloc_shared is used instead).
533-
For the queue=None cast the `dpctl.SyclQueue()` is used to allocate memory.
534-
535-
MemoryUSMShared(usm_obj) constructor create instance from `usm_obj`
536-
expected to implement `__sycl_usm_array_interface__` protocol and exposing
537-
a contiguous block of USM memory of USM shared type. Using copy=True to
538-
perform a copy if USM type is other than 'shared'.
599+
For the queue=None case the ``dpctl.SyclQueue()`` is used to allocate
600+
memory.
601+
602+
MemoryUSMShared(usm_obj) constructor creates instance from `usm_obj`
603+
expected to implement `__sycl_usm_array_interface__` protocol and to expose
604+
a contiguous block of USM shared allocation. Use `copy=True` to
605+
perform a copy if USM type of the allocation represented by the argument
606+
is other than 'shared'.
539607
"""
540608
def __cinit__(self, other, *, Py_ssize_t alignment=0,
541609
SyclQueue queue=None, int copy=False):
@@ -569,12 +637,14 @@ cdef class MemoryUSMHost(_Memory):
569637
allocates nbytes of USM host memory.
570638
571639
Non-positive alignments are not used (malloc_host is used instead).
572-
For the queue=None case `dpctl.SyclQueue()` is used to allocate memory.
640+
For the queue=None case the ``dpctl.SyclQueue()`` is used to allocate
641+
memory.
573642
574643
MemoryUSMDevice(usm_obj) constructor create instance from `usm_obj`
575-
expected to implement `__sycl_usm_array_interface__` protocol and exposing
576-
a contiguous block of USM memory of USM host type. Using copy=True to
577-
perform a copy if USM type is other than 'host'.
644+
expected to implement `__sycl_usm_array_interface__` protocol and to expose
645+
a contiguous block of USM host allocation. Use `copy=True` to
646+
perform a copy if USM type of the allocation represented by the argument
647+
is other than 'host'.
578648
"""
579649
def __cinit__(self, other, *, Py_ssize_t alignment=0,
580650
SyclQueue queue=None, int copy=False):
@@ -609,12 +679,14 @@ cdef class MemoryUSMDevice(_Memory):
609679
allocates nbytes of USM device memory.
610680
611681
Non-positive alignments are not used (malloc_device is used instead).
612-
For the queue=None cast the `dpctl.SyclQueue()` is used to allocate memory.
682+
For the queue=None case the ``dpctl.SyclQueue()`` is used to allocate
683+
memory.
613684
614685
MemoryUSMDevice(usm_obj) constructor create instance from `usm_obj`
615686
expected to implement `__sycl_usm_array_interface__` protocol and exposing
616-
a contiguous block of USM memory of USM device type. Using copy=True to
617-
perform a copy if USM type is other than 'device'.
687+
a contiguous block of USM device allocation. Use `copy=True` to
688+
perform a copy if USM type of the allocation represented by the argument
689+
is other than 'device'.
618690
"""
619691
def __cinit__(self, other, *, Py_ssize_t alignment=0,
620692
SyclQueue queue=None, int copy=False):
@@ -638,3 +710,41 @@ cdef class MemoryUSMDevice(_Memory):
638710
other, self.get_usm_type()
639711
)
640712
)
713+
714+
715+
def as_usm_memory(obj):
716+
"""
717+
as_usm_memory(obj)
718+
719+
Converts Python object with `__sycl_usm_array_interface__` property
720+
to one of :class:`.MemoryUSMShared`, :class:`.MemoryUSMDevice`, or
721+
:class:`.MemoryUSMHost` instances depending on the type of USM allocation
722+
they represent.
723+
724+
Raises:
725+
ValueError
726+
When object does not expose the `__sycl_usm_array_interface__`,
727+
or it is malformed
728+
TypeError
729+
When unexpected types of entries in the interface are encountered
730+
SyclQueueCreationError
731+
When a :class:`dpctl.SyclQueue` could not be created from the
732+
information given by the interface
733+
"""
734+
cdef _Memory res = _Memory.__new__(_Memory)
735+
cdef str kind
736+
res._cinit_empty()
737+
res._cinit_other(obj)
738+
kind = res.get_usm_type()
739+
if kind == "shared":
740+
return MemoryUSMShared(res)
741+
elif kind == "device":
742+
return MemoryUSMDevice(res)
743+
elif kind == "host":
744+
return MemoryUSMHost(res)
745+
else:
746+
raise ValueError(
747+
"Could not determine the type "
748+
"USM allocation represented by argument {}".
749+
format(obj)
750+
)

dpctl/memory/_sycl_usm_array_interface_utils.pxi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ cdef object _pointers_from_shape_and_stride(
8989
for i in range(nd):
9090
str_i = int(ary_strides[i])
9191
sh_i = int(ary_shape[i])
92+
if (sh_i <= 0):
93+
raise ValueError("Array shape elements need to be positive")
9294
if (str_i > 0):
9395
max_disp += str_i * (sh_i - 1)
9496
else:

0 commit comments

Comments
 (0)