Skip to content

Commit a51973c

Browse files
Change _Memory object's memory ownership model
The _Memory object acquires additional field void * _opaque_ptr. This pointer is the pointer to std::shared_ptr<void> with a deleter class to delete USM allocations. The pointer is opaque to retain C-API of Py_MemoryObject. If _opaque_ptr is NULL, refobj field is assumed to be responsible for USM deallocation. api Memory_GetOpaquePointer is added to access the opaque pointer. A test in test_sycl_usm is modified to reflect factual changes in the behavior of _Memory type.
1 parent c6f5f79 commit a51973c

File tree

7 files changed

+189
-51
lines changed

7 files changed

+189
-51
lines changed

dpctl/_sycl_queue.pyx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ cdef DPCTLSyclEventRef _memcpy_impl(
342342
cdef unsigned char[::1] dst_host_buf = None
343343

344344
if isinstance(src, _Memory):
345-
c_src_ptr = <void*>(<_Memory>src).memory_ptr
345+
c_src_ptr = <void*>(<_Memory>src).get_data_ptr()
346346
elif _is_buffer(src):
347347
src_host_buf = src
348348
c_src_ptr = <void *>&src_host_buf[0]
@@ -354,7 +354,7 @@ cdef DPCTLSyclEventRef _memcpy_impl(
354354
)
355355

356356
if isinstance(dst, _Memory):
357-
c_dst_ptr = <void*>(<_Memory>dst).memory_ptr
357+
c_dst_ptr = <void*>(<_Memory>dst).get_data_ptr()
358358
elif _is_buffer(dst):
359359
dst_host_buf = dst
360360
c_dst_ptr = <void *>&dst_host_buf[0]
@@ -1265,7 +1265,7 @@ cdef class SyclQueue(_SyclQueue):
12651265
cdef DPCTLSyclEventRef ERef = NULL
12661266

12671267
if isinstance(mem, _Memory):
1268-
ptr = <void*>(<_Memory>mem).memory_ptr
1268+
ptr = <void*>(<_Memory>mem).get_data_ptr()
12691269
else:
12701270
raise TypeError("Parameter `mem` should have type _Memory")
12711271

@@ -1285,7 +1285,7 @@ cdef class SyclQueue(_SyclQueue):
12851285
cdef DPCTLSyclEventRef ERef = NULL
12861286

12871287
if isinstance(mem, _Memory):
1288-
ptr = <void*>(<_Memory>mem).memory_ptr
1288+
ptr = <void*>(<_Memory>mem).get_data_ptr()
12891289
else:
12901290
raise TypeError("Parameter `mem` should have type _Memory")
12911291

dpctl/memory/CMakeLists.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

2-
file(GLOB _cython_sources *.pyx)
3-
foreach(_cy_file ${_cython_sources})
4-
get_filename_component(_trgt ${_cy_file} NAME_WLE)
5-
build_dpctl_ext(${_trgt} ${_cy_file} "dpctl/memory")
6-
target_link_libraries(DpctlCAPI INTERFACE ${_trgt}_headers)
7-
endforeach()
2+
set(_cy_file ${CMAKE_CURRENT_SOURCE_DIR}/_memory.pyx)
3+
get_filename_component(_trgt ${_cy_file} NAME_WLE)
4+
build_dpctl_ext(${_trgt} ${_cy_file} "dpctl/memory" SYCL)
5+
# _memory include _opaque_smart_ptr.hpp
6+
target_include_directories(${_trgt} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
7+
target_link_libraries(DpctlCAPI INTERFACE ${_trgt}_headers)

dpctl/memory/_memory.pxd

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ cdef DPCTLSyclQueueRef get_queue_ref_from_ptr_and_syclobj(
3333

3434

3535
cdef public api class _Memory [object Py_MemoryObject, type Py_MemoryType]:
36-
cdef DPCTLSyclUSMRef memory_ptr
36+
cdef DPCTLSyclUSMRef _memory_ptr
37+
cdef void* _opaque_ptr
3738
cdef Py_ssize_t nbytes
3839
cdef SyclQueue queue
3940
cdef object refobj
@@ -50,6 +51,8 @@ cdef public api class _Memory [object Py_MemoryObject, type Py_MemoryType]:
5051
cpdef memset(self, unsigned short val=*)
5152

5253
cpdef bytes tobytes(self)
54+
cdef DPCTLSyclUSMRef get_data_ptr(self)
55+
cdef void * get_opaque_ptr(self)
5356

5457
@staticmethod
5558
cdef SyclDevice get_pointer_device(

dpctl/memory/_memory.pyx

Lines changed: 63 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ __all__ = [
7878

7979
include "_sycl_usm_array_interface_utils.pxi"
8080

81+
cdef extern from "_opaque_smart_ptr.hpp":
82+
void * OpaqueSmartPtr_Make(void *, DPCTLSyclQueueRef) nogil
83+
void * OpaqueSmartPtr_Copy(void *) nogil
84+
void OpaqueSmartPtr_Delete(void *) nogil
85+
void * OpaqueSmartPtr_Get(void *) nogil
86+
8187
class USMAllocationError(Exception):
8288
"""
8389
An exception raised when Universal Shared Memory (USM) allocation
@@ -152,7 +158,8 @@ cdef class _Memory:
152158
MemoryUSMShared, MemoryUSMDevice, MemoryUSMHost
153159
"""
154160
cdef _cinit_empty(self):
155-
self.memory_ptr = NULL
161+
self._memory_ptr = NULL
162+
self._opaque_ptr = NULL
156163
self.nbytes = 0
157164
self.queue = None
158165
self.refobj = None
@@ -198,7 +205,8 @@ cdef class _Memory:
198205
)
199206

200207
if (p):
201-
self.memory_ptr = p
208+
self._memory_ptr = p
209+
self._opaque_ptr = OpaqueSmartPtr_Make(p, QRef)
202210
self.nbytes = nbytes
203211
self.queue = queue
204212
else:
@@ -214,18 +222,22 @@ cdef class _Memory:
214222
cdef _Memory other_mem
215223
if isinstance(other, _Memory):
216224
other_mem = <_Memory> other
217-
self.memory_ptr = other_mem.memory_ptr
218225
self.nbytes = other_mem.nbytes
219226
self.queue = other_mem.queue
220-
if other_mem.refobj is None:
221-
self.refobj = other
227+
if other_mem._opaque_ptr is NULL:
228+
self._memory_ptr = other_mem._memory_ptr
229+
self._opaque_ptr = NULL
230+
self.refobj = other.reference_obj
222231
else:
223-
self.refobj = other_mem.refobj
232+
self._memory_ptr = other_mem._memory_ptr
233+
self._opaque_ptr = OpaqueSmartPtr_Copy(other_mem._opaque_ptr)
234+
self.refobj = None
224235
elif hasattr(other, '__sycl_usm_array_interface__'):
225236
other_iface = other.__sycl_usm_array_interface__
226237
if isinstance(other_iface, dict):
227238
other_buf = _USMBufferData.from_sycl_usm_ary_iface(other_iface)
228-
self.memory_ptr = other_buf.p
239+
self._opaque_ptr = NULL
240+
self._memory_ptr = <DPCTLSyclUSMRef>other_buf.p
229241
self.nbytes = other_buf.nbytes
230242
self.queue = other_buf.queue
231243
self.refobj = other
@@ -241,23 +253,25 @@ cdef class _Memory:
241253
)
242254

243255
def __dealloc__(self):
244-
if (self.refobj is None):
245-
if self.memory_ptr:
246-
if (type(self.queue) is SyclQueue):
247-
DPCTLfree_with_queue(
248-
self.memory_ptr, self.queue.get_queue_ref()
249-
)
256+
if not (self._opaque_ptr is NULL):
257+
OpaqueSmartPtr_Delete(self._opaque_ptr)
250258
self._cinit_empty()
251259

260+
cdef DPCTLSyclUSMRef get_data_ptr(self):
261+
return self._memory_ptr
262+
263+
cdef void* get_opaque_ptr(self):
264+
return self._opaque_ptr
265+
252266
cdef _getbuffer(self, Py_buffer *buffer, int flags):
253267
# memory_ptr is Ref which is pointer to SYCL type. For USM it is void*.
254268
cdef SyclContext ctx = self._context
255269
cdef _usm_type UsmTy = DPCTLUSM_GetPointerType(
256-
self.memory_ptr, ctx.get_context_ref()
270+
self._memory_ptr, ctx.get_context_ref()
257271
)
258272
if UsmTy == _usm_type._USM_DEVICE:
259273
raise ValueError("USM Device memory is not host accessible")
260-
buffer.buf = <char*>self.memory_ptr
274+
buffer.buf = <void *>self._memory_ptr
261275
buffer.format = 'B' # byte
262276
buffer.internal = NULL # see References
263277
buffer.itemsize = 1
@@ -285,7 +299,7 @@ cdef class _Memory:
285299
represented as Python integer.
286300
"""
287301
def __get__(self):
288-
return <size_t>(self.memory_ptr)
302+
return <size_t>(self._memory_ptr)
289303

290304
property _context:
291305
""":class:`dpctl.SyclContext` the USM pointer is bound to. """
@@ -333,7 +347,7 @@ cdef class _Memory:
333347
.format(
334348
self.get_usm_type(),
335349
self.nbytes,
336-
hex(<object>(<size_t>self.memory_ptr))
350+
hex(<object>(<size_t>self._memory_ptr))
337351
)
338352
)
339353

@@ -377,7 +391,7 @@ cdef class _Memory:
377391
"""
378392
def __get__(self):
379393
cdef dict iface = {
380-
"data": (<size_t>(<void *>self.memory_ptr),
394+
"data": (<size_t>(<void *>self._memory_ptr),
381395
True), # bool(self.writable)),
382396
"shape": (self.nbytes,),
383397
"strides": None,
@@ -402,18 +416,18 @@ cdef class _Memory:
402416
if syclobj is None:
403417
ctx = self._context
404418
return _Memory.get_pointer_type(
405-
self.memory_ptr, ctx
419+
self._memory_ptr, ctx
406420
).decode("UTF-8")
407421
elif isinstance(syclobj, SyclContext):
408422
ctx = <SyclContext>(syclobj)
409423
return _Memory.get_pointer_type(
410-
self.memory_ptr, ctx
424+
self._memory_ptr, ctx
411425
).decode("UTF-8")
412426
elif isinstance(syclobj, SyclQueue):
413427
q = <SyclQueue>(syclobj)
414428
ctx = q.get_sycl_context()
415429
return _Memory.get_pointer_type(
416-
self.memory_ptr, ctx
430+
self._memory_ptr, ctx
417431
).decode("UTF-8")
418432
raise TypeError(
419433
"syclobj keyword can be either None, or an instance of "
@@ -435,18 +449,18 @@ cdef class _Memory:
435449
if syclobj is None:
436450
ctx = self._context
437451
return _Memory.get_pointer_type_enum(
438-
self.memory_ptr, ctx
452+
self._memory_ptr, ctx
439453
)
440454
elif isinstance(syclobj, SyclContext):
441455
ctx = <SyclContext>(syclobj)
442456
return _Memory.get_pointer_type_enum(
443-
self.memory_ptr, ctx
457+
self._memory_ptr, ctx
444458
)
445459
elif isinstance(syclobj, SyclQueue):
446460
q = <SyclQueue>(syclobj)
447461
ctx = q.get_sycl_context()
448462
return _Memory.get_pointer_type_enum(
449-
self.memory_ptr, ctx
463+
self._memory_ptr, ctx
450464
)
451465
raise TypeError(
452466
"syclobj keyword can be either None, or an instance of "
@@ -475,8 +489,8 @@ cdef class _Memory:
475489
# call kernel to copy from
476490
ERef = DPCTLQueue_Memcpy(
477491
self.queue.get_queue_ref(),
478-
<void *>&host_buf[0], # destination
479-
<void *>self.memory_ptr, # source
492+
<void *>&host_buf[0], # destination
493+
<void *>self._memory_ptr, # source
480494
<size_t>self.nbytes
481495
)
482496
with nogil: DPCTLEvent_Wait(ERef)
@@ -500,8 +514,8 @@ cdef class _Memory:
500514
# call kernel to copy from
501515
ERef = DPCTLQueue_Memcpy(
502516
self.queue.get_queue_ref(),
503-
<void *>self.memory_ptr, # destination
504-
<void *>&host_buf[0], # source
517+
<void *>self._memory_ptr, # destination
518+
<void *>&host_buf[0], # source
505519
<size_t>buf_len
506520
)
507521
with nogil: DPCTLEvent_Wait(ERef)
@@ -542,16 +556,16 @@ cdef class _Memory:
542556
if (same_contexts):
543557
ERef = DPCTLQueue_Memcpy(
544558
this_queue.get_queue_ref(),
545-
<void *>self.memory_ptr,
559+
<void *>self._memory_ptr,
546560
<void *>src_buf.p,
547561
<size_t>src_buf.nbytes
548562
)
549563
with nogil: DPCTLEvent_Wait(ERef)
550564
DPCTLEvent_Delete(ERef)
551565
else:
552566
copy_via_host(
553-
<void *>self.memory_ptr, this_queue, # dest
554-
<void *>src_buf.p, src_queue, # src
567+
<void *>self._memory_ptr, this_queue, # dest
568+
<void *>src_buf.p, src_queue, # src
555569
<size_t>src_buf.nbytes
556570
)
557571
else:
@@ -565,7 +579,7 @@ cdef class _Memory:
565579

566580
ERef = DPCTLQueue_Memset(
567581
self.queue.get_queue_ref(),
568-
<void *>self.memory_ptr, # destination
582+
<void *>self._memory_ptr, # destination
569583
<int> val,
570584
self.nbytes)
571585

@@ -703,20 +717,29 @@ cdef class _Memory:
703717
res = _Memory.__new__(_Memory)
704718
_mem = <_Memory> res
705719
_mem._cinit_empty()
706-
_mem.memory_ptr = USMRef
707720
_mem.nbytes = nbytes
708721
QRef_copy = DPCTLQueue_Copy(QRef)
709722
if QRef_copy is NULL:
710723
raise ValueError("Referenced queue could not be copied.")
711724
try:
712-
_mem.queue = SyclQueue._create(QRef_copy) # consumes the copy
725+
# _create steals ownership of QRef_copy
726+
_mem.queue = SyclQueue._create(QRef_copy)
713727
except dpctl.SyclQueueCreationError as sqce:
714728
raise ValueError(
715729
"SyclQueue object could not be created from "
716730
"copy of referenced queue"
717731
) from sqce
718-
_mem.refobj = memory_owner
719-
return mem_ty(res)
732+
if memory_owner is None:
733+
_mem._memory_ptr = USMRef
734+
# assume ownership of USM allocation via smart pointer
735+
_mem._opaque_ptr = OpaqueSmartPtr_Make(<void *>USMRef, QRef)
736+
_mem.refobj = None
737+
else:
738+
_mem._memory_ptr = USMRef
739+
_mem._opaque_ptr = NULL
740+
_mem.refobj = memory_owner
741+
_out = mem_ty(<object>_mem)
742+
return _out
720743

721744

722745
cdef class MemoryUSMShared(_Memory):
@@ -908,10 +931,13 @@ def as_usm_memory(obj):
908931
format(obj)
909932
)
910933

934+
cdef api void * Memory_GetOpaquePointer(_Memory obj):
935+
"Opaque pointer value"
936+
return obj.get_opaque_ptr()
911937

912938
cdef api DPCTLSyclUSMRef Memory_GetUsmPointer(_Memory obj):
913939
"Pointer of USM allocation"
914-
return obj.memory_ptr
940+
return obj.get_data_ptr()
915941

916942
cdef api DPCTLSyclContextRef Memory_GetContextRef(_Memory obj):
917943
"Context reference to which USM allocation is bound"

0 commit comments

Comments
 (0)