Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added free Python function as_usm_memory(obj) #443

Merged
merged 5 commits into from
May 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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