From 4afd698eb9d5948ff072d675059105fc982043b0 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Thu, 13 May 2021 18:51:09 -0500 Subject: [PATCH 1/5] Added Python get_usm_pointer_type Used the Cython static method from _Memmory.get_pointer_type in the added function, as well as in the method `get_usm_type`. Added docstrings. ``` Python 3.7.9 (default, Mar 10 2021, 05:18:00) Type 'copyright', 'credits' or 'license' for more information IPython 7.22.0 -- An enhanced Interactive Python. Type '?' for help. In [1]: import dpctl.memory as dpm, dpctl.memory._memory as dpm_m, dpctl In [2]: m = dpm.MemoryUSMDevice(2048, alignment=256) In [3]: dpm_m.get_usm_pointer_type(m._pointer, m.sycl_context) Out[3]: 'device' In [4]: dpm_m.get_usm_pointer_type(m._pointer + 1024, m.sycl_context) Out[4]: 'device' In [5]: m.get_usm_type() Out[5]: 'device' ``` --- dpctl/memory/_memory.pyx | 98 +++++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 16 deletions(-) diff --git a/dpctl/memory/_memory.pyx b/dpctl/memory/_memory.pyx index 6541a315f2..0d93f90d5a 100644 --- a/dpctl/memory/_memory.pyx +++ b/dpctl/memory/_memory.pyx @@ -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 = ( 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 = (syclobj) + return _Memory.get_pointer_type(USMRef, ctx).decode("UTF-8") + elif isinstance(syclobj, SyclQueue): + q = (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 @@ -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 = (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 = (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): """ @@ -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() ) From 3e2ea1c5b7f863cb4536b6f690ab3205054e94e1 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Fri, 14 May 2021 10:02:35 -0500 Subject: [PATCH 2/5] SUAI processing: disallow zero shapes also when strides are given --- dpctl/memory/_sycl_usm_array_interface_utils.pxi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dpctl/memory/_sycl_usm_array_interface_utils.pxi b/dpctl/memory/_sycl_usm_array_interface_utils.pxi index 88982d9b21..4606caeb17 100644 --- a/dpctl/memory/_sycl_usm_array_interface_utils.pxi +++ b/dpctl/memory/_sycl_usm_array_interface_utils.pxi @@ -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: From 46ece5e8af7761d13c00a7ebb1141c877b639965 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Fri, 14 May 2021 10:06:38 -0500 Subject: [PATCH 3/5] Added `dpctl.memory.create_MemoryUSM` The function takes an object with `__sycl_usm_array_interface__` and creates approproate MemoryUSM* object depending the the type of USM alocation the argument represents. Example: ``` In [1]: import dpctl, dpctl.memory as dpm, dpctl.memory._memory as dpm_m In [2]: import dpctl.tensor as dpt In [3]: X = dpt.usm_ndarray((4, 5)) In [4]: dpm_m.create_MemoryUSM(X) Out[4]: In [5]: X.usm_data Out[5]: In [6]: class Duck_USMAllocation: ...: def __init__(self, buf, syclobj): ...: self.buf_ = buf ...: self.syclobj_ = syclobj ...: In [7]: class Duck_USMAllocation: ...: def __init__(self, buf, syclobj): ...: self.buf_ = buf ...: self.syclobj_ = syclobj ...: @property ...: def __sycl_usm_array_interface__(self): ...: iface = self.buf_.__sycl_usm_array_interface__ ...: iface['syclobj'] = self.syclobj_ ...: return iface ...: In [8]: d = Duck_USMAllocation(X, X.sycl_device.filter_string) In [9]: dpm_m.create_MemoryUSM(d) Out[9]: ``` --- dpctl/memory/__init__.py | 14 ++++++-- dpctl/memory/_memory.pyx | 70 ++++++++++++++++++++++++++++++++-------- 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/dpctl/memory/__init__.py b/dpctl/memory/__init__.py index 6fcbeb372e..1717d45d18 100644 --- a/dpctl/memory/__init__.py +++ b/dpctl/memory/__init__.py @@ -30,6 +30,16 @@ `memoryview`, or `array.array` classes. """ -from ._memory import MemoryUSMDevice, MemoryUSMHost, MemoryUSMShared +from ._memory import ( + MemoryUSMDevice, + MemoryUSMHost, + MemoryUSMShared, + create_MemoryUSM, +) -__all__ = ["MemoryUSMDevice", "MemoryUSMHost", "MemoryUSMShared"] +__all__ = [ + "MemoryUSMDevice", + "MemoryUSMHost", + "MemoryUSMShared", + "create_MemoryUSM", +] diff --git a/dpctl/memory/_memory.pyx b/dpctl/memory/_memory.pyx index 0d93f90d5a..a09bd41179 100644 --- a/dpctl/memory/_memory.pyx +++ b/dpctl/memory/_memory.pyx @@ -596,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): @@ -635,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): @@ -675,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): @@ -704,3 +710,41 @@ cdef class MemoryUSMDevice(_Memory): other, self.get_usm_type() ) ) + + +def create_MemoryUSM(obj): + """ + create_MemoryUSM(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) + ) From ea0b5711be1742b444683bb59fee929e3f735bc4 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Fri, 14 May 2021 10:13:10 -0500 Subject: [PATCH 4/5] Improved on __repr__ of USM memory blobs ``` In [1]: import dpctl.memory as dpm In [2]: dpm.MemoryUSMShared(64) Out[2]: ``` --- dpctl/memory/_memory.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpctl/memory/_memory.pyx b/dpctl/memory/_memory.pyx index a09bd41179..c13723195d 100644 --- a/dpctl/memory/_memory.pyx +++ b/dpctl/memory/_memory.pyx @@ -325,7 +325,7 @@ cdef class _Memory: def __repr__(self): return ( - "" + "" .format( self.get_usm_type(), self.nbytes, From 4eac9424c581db43ef18680c5f621799caaa1a21 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Fri, 14 May 2021 19:23:22 -0500 Subject: [PATCH 5/5] Renamed dpctl.memory.create_MemoryUSM to as_usm_memory --- dpctl/memory/__init__.py | 4 ++-- dpctl/memory/_memory.pyx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dpctl/memory/__init__.py b/dpctl/memory/__init__.py index 1717d45d18..7b4032f1d7 100644 --- a/dpctl/memory/__init__.py +++ b/dpctl/memory/__init__.py @@ -34,12 +34,12 @@ MemoryUSMDevice, MemoryUSMHost, MemoryUSMShared, - create_MemoryUSM, + as_usm_memory, ) __all__ = [ "MemoryUSMDevice", "MemoryUSMHost", "MemoryUSMShared", - "create_MemoryUSM", + "as_usm_memory", ] diff --git a/dpctl/memory/_memory.pyx b/dpctl/memory/_memory.pyx index c13723195d..bcf2bdbb57 100644 --- a/dpctl/memory/_memory.pyx +++ b/dpctl/memory/_memory.pyx @@ -712,9 +712,9 @@ cdef class MemoryUSMDevice(_Memory): ) -def create_MemoryUSM(obj): +def as_usm_memory(obj): """ - create_MemoryUSM(obj) + as_usm_memory(obj) Converts Python object with `__sycl_usm_array_interface__` property to one of :class:`.MemoryUSMShared`, :class:`.MemoryUSMDevice`, or