Skip to content

Commit

Permalink
Merge pull request #443 from IntelPython/free-function-to-determinate…
Browse files Browse the repository at this point in the history
…-usm-type

Added free Python function as_usm_memory(obj)
  • Loading branch information
oleksandr-pavlyk authored May 17, 2021
2 parents 31f95d6 + 4eac942 commit 5a5170b
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 32 deletions.
14 changes: 12 additions & 2 deletions dpctl/memory/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@
`memoryview`, or `array.array` classes.
"""
from ._memory import MemoryUSMDevice, MemoryUSMHost, MemoryUSMShared
from ._memory import (
MemoryUSMDevice,
MemoryUSMHost,
MemoryUSMShared,
as_usm_memory,
)

__all__ = ["MemoryUSMDevice", "MemoryUSMHost", "MemoryUSMShared"]
__all__ = [
"MemoryUSMDevice",
"MemoryUSMHost",
"MemoryUSMShared",
"as_usm_memory",
]
170 changes: 140 additions & 30 deletions dpctl/memory/_memory.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,49 @@ def _to_memory(unsigned char[::1] b, str usm_kind):
return res


def get_usm_pointer_type(ptr, syclobj):
"""
get_usm_pointer_type(ptr, syclobj)
Gives the SYCL(TM) USM pointer type, using ``sycl::get_pointer_type``,
returning one of 4 possible strings: 'shared', 'host', 'device',
or 'unknown'.
Args:
ptr: int
A pointer stored as size_t Python integer.
syclobj: :class:`dpctl.SyclContext` or :class:`dpctl.SyclQueue`
Python object providing :class:`dpctl.SyclContext` against which
to query for the pointer type.
Returns:
'unknown' if the pointer does not represent USM allocation made using
the given context. Otherwise, returns 'shared', 'device', or 'host'
type of the allocation.
"""
cdef const char* kind
cdef SyclContext ctx
cdef SyclQueue q
cdef DPCTLSyclUSMRef USMRef = NULL
try:
USMRef = <DPCTLSyclUSMRef>(<size_t> ptr)
except Exception as e:
raise TypeError(
"First argument {} could not be converted to Python integer of "
"size_t".format(ptr)
) from e
if isinstance(syclobj, SyclContext):
ctx = <SyclContext>(syclobj)
return _Memory.get_pointer_type(USMRef, ctx).decode("UTF-8")
elif isinstance(syclobj, SyclQueue):
q = <SyclQueue>(syclobj)
ctx = q.get_sycl_context()
return _Memory.get_pointer_type(USMRef, ctx).decode("UTF-8")
raise TypeError(
"Second argument {} is expected to be an instance of "
"SyclContext or SyclQueue".format(syclobj)
)


cdef class _Memory:
""" Internal class implementing methods common to
MemoryUSMShared, MemoryUSMDevice, MemoryUSMHost
Expand Down Expand Up @@ -282,7 +325,7 @@ cdef class _Memory:

def __repr__(self):
return (
"<SYCL(TM) USM-{} allocated memory block of {} bytes at {}>"
"<SYCL(TM) USM-{} allocation of {} bytes at {}>"
.format(
self.get_usm_type(),
self.nbytes,
Expand Down Expand Up @@ -316,31 +359,37 @@ cdef class _Memory:
return iface

def get_usm_type(self, syclobj=None):
"""
get_usm_type(syclobj=None)
Returns the type of USM allocation using Sycl context carried by
`syclobj` keyword argument. Value of None is understood to query
against `self.sycl_context` - the context used to create the
allocation.
"""
cdef const char* kind
cdef SyclContext ctx
cdef SyclQueue q
if syclobj is None:
ctx = self._context
kind = DPCTLUSM_GetPointerType(
self.memory_ptr, ctx.get_context_ref()
)
return _Memory.get_pointer_type(
self.memory_ptr, ctx
).decode("UTF-8")
elif isinstance(syclobj, SyclContext):
ctx = <SyclContext>(syclobj)
kind = DPCTLUSM_GetPointerType(
self.memory_ptr, ctx.get_context_ref()
)
return _Memory.get_pointer_type(
self.memory_ptr, ctx
).decode("UTF-8")
elif isinstance(syclobj, SyclQueue):
q = <SyclQueue>(syclobj)
ctx = q.get_sycl_context()
kind = DPCTLUSM_GetPointerType(
self.memory_ptr, ctx.get_context_ref()
)
else:
raise ValueError(
"syclobj keyword can be either None, or an instance of "
"SyclContext or SyclQueue"
)
return kind.decode('UTF-8')
return _Memory.get_pointer_type(
self.memory_ptr, ctx
).decode("UTF-8")
raise TypeError(
"syclobj keyword can be either None, or an instance of "
"SyclContext or SyclQueue"
)

cpdef copy_to_host(self, obj=None):
"""
Expand Down Expand Up @@ -457,7 +506,24 @@ cdef class _Memory:

@staticmethod
cdef bytes get_pointer_type(DPCTLSyclUSMRef p, SyclContext ctx):
"""Returns USM-type of given pointer `p` in given sycl context `ctx`"""
"""
get_pointer_type(p, ctx)
Gives the SYCL(TM) USM pointer type, using ``sycl::get_pointer_type``,
returning one of 4 possible strings: 'shared', 'host', 'device', or
'unknown'.
Args:
p: DPCTLSyclUSMRef
A pointer to test the type of.
ctx: :class:`dpctl.SyclContext`
Python object providing :class:`dpctl.SyclContext` against
which to query for the pointer type.
Returns:
b'unknown' if the pointer does not represent USM allocation made
using the given context. Otherwise, returns b'shared', b'device',
or b'host' type of the allocation.
"""
cdef const char * usm_type = DPCTLUSM_GetPointerType(
p, ctx.get_context_ref()
)
Expand Down Expand Up @@ -530,12 +596,14 @@ cdef class MemoryUSMShared(_Memory):
allocates nbytes of USM shared memory.
Non-positive alignments are not used (malloc_shared is used instead).
For the queue=None cast the `dpctl.SyclQueue()` is used to allocate memory.
MemoryUSMShared(usm_obj) constructor create instance from `usm_obj`
expected to implement `__sycl_usm_array_interface__` protocol and exposing
a contiguous block of USM memory of USM shared type. Using copy=True to
perform a copy if USM type is other than 'shared'.
For the queue=None case the ``dpctl.SyclQueue()`` is used to allocate
memory.
MemoryUSMShared(usm_obj) constructor creates instance from `usm_obj`
expected to implement `__sycl_usm_array_interface__` protocol and to expose
a contiguous block of USM shared allocation. Use `copy=True` to
perform a copy if USM type of the allocation represented by the argument
is other than 'shared'.
"""
def __cinit__(self, other, *, Py_ssize_t alignment=0,
SyclQueue queue=None, int copy=False):
Expand Down Expand Up @@ -569,12 +637,14 @@ cdef class MemoryUSMHost(_Memory):
allocates nbytes of USM host memory.
Non-positive alignments are not used (malloc_host is used instead).
For the queue=None case `dpctl.SyclQueue()` is used to allocate memory.
For the queue=None case the ``dpctl.SyclQueue()`` is used to allocate
memory.
MemoryUSMDevice(usm_obj) constructor create instance from `usm_obj`
expected to implement `__sycl_usm_array_interface__` protocol and exposing
a contiguous block of USM memory of USM host type. Using copy=True to
perform a copy if USM type is other than 'host'.
expected to implement `__sycl_usm_array_interface__` protocol and to expose
a contiguous block of USM host allocation. Use `copy=True` to
perform a copy if USM type of the allocation represented by the argument
is other than 'host'.
"""
def __cinit__(self, other, *, Py_ssize_t alignment=0,
SyclQueue queue=None, int copy=False):
Expand Down Expand Up @@ -609,12 +679,14 @@ cdef class MemoryUSMDevice(_Memory):
allocates nbytes of USM device memory.
Non-positive alignments are not used (malloc_device is used instead).
For the queue=None cast the `dpctl.SyclQueue()` is used to allocate memory.
For the queue=None case the ``dpctl.SyclQueue()`` is used to allocate
memory.
MemoryUSMDevice(usm_obj) constructor create instance from `usm_obj`
expected to implement `__sycl_usm_array_interface__` protocol and exposing
a contiguous block of USM memory of USM device type. Using copy=True to
perform a copy if USM type is other than 'device'.
a contiguous block of USM device allocation. Use `copy=True` to
perform a copy if USM type of the allocation represented by the argument
is other than 'device'.
"""
def __cinit__(self, other, *, Py_ssize_t alignment=0,
SyclQueue queue=None, int copy=False):
Expand All @@ -638,3 +710,41 @@ cdef class MemoryUSMDevice(_Memory):
other, self.get_usm_type()
)
)


def as_usm_memory(obj):
"""
as_usm_memory(obj)
Converts Python object with `__sycl_usm_array_interface__` property
to one of :class:`.MemoryUSMShared`, :class:`.MemoryUSMDevice`, or
:class:`.MemoryUSMHost` instances depending on the type of USM allocation
they represent.
Raises:
ValueError
When object does not expose the `__sycl_usm_array_interface__`,
or it is malformed
TypeError
When unexpected types of entries in the interface are encountered
SyclQueueCreationError
When a :class:`dpctl.SyclQueue` could not be created from the
information given by the interface
"""
cdef _Memory res = _Memory.__new__(_Memory)
cdef str kind
res._cinit_empty()
res._cinit_other(obj)
kind = res.get_usm_type()
if kind == "shared":
return MemoryUSMShared(res)
elif kind == "device":
return MemoryUSMDevice(res)
elif kind == "host":
return MemoryUSMHost(res)
else:
raise ValueError(
"Could not determine the type "
"USM allocation represented by argument {}".
format(obj)
)
2 changes: 2 additions & 0 deletions dpctl/memory/_sycl_usm_array_interface_utils.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ cdef object _pointers_from_shape_and_stride(
for i in range(nd):
str_i = int(ary_strides[i])
sh_i = int(ary_shape[i])
if (sh_i <= 0):
raise ValueError("Array shape elements need to be positive")
if (str_i > 0):
max_disp += str_i * (sh_i - 1)
else:
Expand Down

0 comments on commit 5a5170b

Please sign in to comment.