Skip to content

Commit 8fed78b

Browse files
Static method of _Memory to create from external allocation
Method takes USMRef, number of bytes and queue reference. If USMRef is bound to context in the queue and USM type comes back not 'unknown', appropriate MemoryUSM* object is created which assumes ownership of this memory. Optional `memory_owner` keyword argument may be specified to set the recorded reference object to something other than None (signaling that _Memory is responsible for memory deallocation). This can be used to create MemoryUSM* Python object from natively allocated memory, populate it, but leave deallocation to the caller. It could also be set to a PyCapsule object that carries a custom deleter.
1 parent 5a60bd0 commit 8fed78b

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

dpctl/memory/_memory.pxd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ cdef public class _Memory [object Py_MemoryObject, type Py_MemoryType]:
5555
DPCTLSyclUSMRef p, SyclContext ctx)
5656
@staticmethod
5757
cdef public bytes get_pointer_type(DPCTLSyclUSMRef p, SyclContext ctx)
58+
@staticmethod
59+
cdef public object create_from_usm_pointer_size_qref(
60+
DPCTLSyclUSMRef USMRef,
61+
Py_ssize_t nbytes,
62+
DPCTLSyclQueueRef QRef,
63+
object memory_owner=*
64+
)
5865

5966

6067
cdef public class MemoryUSMShared(_Memory) [object PyMemoryUSMSharedObject,

dpctl/memory/_memory.pyx

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,19 @@ from dpctl._backend cimport ( # noqa: E211
3232
DPCTLaligned_alloc_device,
3333
DPCTLaligned_alloc_host,
3434
DPCTLaligned_alloc_shared,
35+
DPCTLContext_Delete,
3536
DPCTLfree_with_queue,
3637
DPCTLmalloc_device,
3738
DPCTLmalloc_host,
3839
DPCTLmalloc_shared,
3940
DPCTLQueue_Copy,
4041
DPCTLQueue_Create,
4142
DPCTLQueue_Delete,
43+
DPCTLQueue_GetContext,
4244
DPCTLQueue_Memcpy,
4345
DPCTLSyclContextRef,
4446
DPCTLSyclDeviceRef,
47+
DPCTLSyclUSMRef,
4548
DPCTLUSM_GetPointerDevice,
4649
DPCTLUSM_GetPointerType,
4750
)
@@ -106,7 +109,8 @@ def _to_memory(unsigned char[::1] b, str usm_kind):
106109
else:
107110
raise ValueError(
108111
"Unrecognized usm_kind={} stored in the "
109-
"pickle".format(usm_kind))
112+
"pickle".format(usm_kind)
113+
)
110114
res.copy_from_host(b)
111115

112116
return res
@@ -214,7 +218,7 @@ cdef class _Memory:
214218
self.memory_ptr, ctx.get_context_ref()
215219
)
216220
if kind == b'device':
217-
raise ValueError('USM Device memory is not host accessible')
221+
raise ValueError("USM Device memory is not host accessible")
218222
buffer.buf = <char*>self.memory_ptr
219223
buffer.format = 'B' # byte
220224
buffer.internal = NULL # see References
@@ -431,6 +435,65 @@ cdef class _Memory:
431435

432436
return <bytes>usm_type
433437

438+
@staticmethod
439+
cdef object create_from_usm_pointer_size_qref(
440+
DPCTLSyclUSMRef USMRef, Py_ssize_t nbytes,
441+
DPCTLSyclQueueRef QRef, object memory_owner=None
442+
):
443+
r"""
444+
Create appropriate `MemoryUSM*` object from pre-allocated
445+
USM memory bound to SYCL context in the reference SYCL queue.
446+
447+
Memory will be freed by `MemoryUSM*` object for default
448+
value of memory_owner keyword. The non-default value should
449+
be an object whose dealloc slot frees the memory.
450+
451+
The object may not be a no-op dummy Python object to
452+
delay freeing the memory until later times.
453+
"""
454+
cdef const char *usm_type
455+
cdef DPCTLSyclContextRef CRef = NULL
456+
cdef DPCTLSyclQueueRef QRef_copy = NULL
457+
cdef _Memory _mem
458+
cdef object mem_ty
459+
if nbytes <= 0:
460+
raise ValueError("Number of bytes must must be positive")
461+
if (QRef is NULL):
462+
raise TypeError("Argument DPCTLSyclQueueRef is NULL")
463+
CRef = DPCTLQueue_GetContext(QRef)
464+
if (CRef is NULL):
465+
raise ValueError("Could not retrieve context from QRef")
466+
usm_type = DPCTLUSM_GetPointerType(USMRef, CRef)
467+
DPCTLContext_Delete(CRef)
468+
if usm_type == b"shared":
469+
mem_ty = MemoryUSMShared
470+
elif usm_type == b"device":
471+
mem_ty = MemoryUSMDevice
472+
elif usm_type == b"host":
473+
mem_ty = MemoryUSMHost
474+
else:
475+
raise ValueError(
476+
"Argument pointer is not bound to "
477+
"context in the given queue"
478+
)
479+
res = _Memory.__new__(_Memory)
480+
_mem = <_Memory> res
481+
_mem._cinit_empty()
482+
_mem.memory_ptr = USMRef
483+
_mem.nbytes = nbytes
484+
QRef_copy = DPCTLQueue_Copy(QRef)
485+
if QRef_copy is NULL:
486+
raise ValueError("Referenced queue could not be copied.")
487+
try:
488+
_mem.queue = SyclQueue._create(QRef_copy) # consumes the copy
489+
except dpctl.SyclQueueCreationError as sqce:
490+
raise ValueError(
491+
"SyclQueue object could not be created from "
492+
"copy of referenced queue"
493+
) from sqce
494+
_mem.refobj = memory_owner
495+
return mem_ty(res)
496+
434497

435498
cdef class MemoryUSMShared(_Memory):
436499
"""

0 commit comments

Comments
 (0)