Skip to content

Commit 83b7359

Browse files
Merge pull request #430 from IntelPython/feature/create_MemoryObject_from_external_allocation
Static method of _Memory to create from external allocation
2 parents 20f88f1 + 7247207 commit 83b7359

File tree

3 files changed

+165
-14
lines changed

3 files changed

+165
-14
lines changed

dpctl-capi/source/dpctl_sycl_usm_interface.cpp

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,24 +44,48 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(void, DPCTLSyclUSMRef)
4444
__dpctl_give DPCTLSyclUSMRef
4545
DPCTLmalloc_shared(size_t size, __dpctl_keep const DPCTLSyclQueueRef QRef)
4646
{
47-
auto Q = unwrap(QRef);
48-
auto Ptr = malloc_shared(size, *Q);
49-
return wrap(Ptr);
47+
if (!QRef) {
48+
std::cerr << "Input QRef is nullptr\n";
49+
return nullptr;
50+
}
51+
try {
52+
auto Q = unwrap(QRef);
53+
auto Ptr = malloc_shared(size, *Q);
54+
return wrap(Ptr);
55+
} catch (feature_not_supported const &fns) {
56+
std::cerr << fns.what() << '\n';
57+
return nullptr;
58+
}
5059
}
5160

5261
__dpctl_give DPCTLSyclUSMRef
5362
DPCTLaligned_alloc_shared(size_t alignment,
5463
size_t size,
5564
__dpctl_keep const DPCTLSyclQueueRef QRef)
5665
{
57-
auto Q = unwrap(QRef);
58-
auto Ptr = aligned_alloc_shared(alignment, size, *Q);
59-
return wrap(Ptr);
66+
if (!QRef) {
67+
std::cerr << "Input QRef is nullptr\n";
68+
return nullptr;
69+
}
70+
try {
71+
auto Q = unwrap(QRef);
72+
auto Ptr = aligned_alloc_shared(alignment, size, *Q);
73+
return wrap(Ptr);
74+
} catch (feature_not_supported const &fns) {
75+
std::cerr << fns.what() << '\n';
76+
return nullptr;
77+
}
6078
}
6179

6280
__dpctl_give DPCTLSyclUSMRef
6381
DPCTLmalloc_host(size_t size, __dpctl_keep const DPCTLSyclQueueRef QRef)
6482
{
83+
if (!QRef) {
84+
std::cerr << "Input QRef is nullptr\n";
85+
return nullptr;
86+
}
87+
// SYCL 2020 spec: for devices without aspect::usm_host_allocations:
88+
// undefined behavior
6589
auto Q = unwrap(QRef);
6690
auto Ptr = malloc_host(size, *Q);
6791
return wrap(Ptr);
@@ -72,6 +96,12 @@ DPCTLaligned_alloc_host(size_t alignment,
7296
size_t size,
7397
__dpctl_keep const DPCTLSyclQueueRef QRef)
7498
{
99+
if (!QRef) {
100+
std::cerr << "Input QRef is nullptr\n";
101+
return nullptr;
102+
}
103+
// SYCL 2020 spec: for devices without aspect::usm_host_allocations:
104+
// undefined behavior
75105
auto Q = unwrap(QRef);
76106
auto Ptr = aligned_alloc_host(alignment, size, *Q);
77107
return wrap(Ptr);
@@ -80,24 +110,50 @@ DPCTLaligned_alloc_host(size_t alignment,
80110
__dpctl_give DPCTLSyclUSMRef
81111
DPCTLmalloc_device(size_t size, __dpctl_keep const DPCTLSyclQueueRef QRef)
82112
{
83-
auto Q = unwrap(QRef);
84-
auto Ptr = malloc_device(size, *Q);
85-
return wrap(Ptr);
113+
if (!QRef) {
114+
std::cerr << "Input QRef is nullptr\n";
115+
return nullptr;
116+
}
117+
try {
118+
auto Q = unwrap(QRef);
119+
auto Ptr = malloc_device(size, *Q);
120+
return wrap(Ptr);
121+
} catch (feature_not_supported const &fns) {
122+
std::cerr << fns.what() << '\n';
123+
return nullptr;
124+
}
86125
}
87126

88127
__dpctl_give DPCTLSyclUSMRef
89128
DPCTLaligned_alloc_device(size_t alignment,
90129
size_t size,
91130
__dpctl_keep const DPCTLSyclQueueRef QRef)
92131
{
93-
auto Q = unwrap(QRef);
94-
auto Ptr = aligned_alloc_device(alignment, size, *Q);
95-
return wrap(Ptr);
132+
if (!QRef) {
133+
std::cerr << "Input QRef is nullptr\n";
134+
return nullptr;
135+
}
136+
try {
137+
auto Q = unwrap(QRef);
138+
auto Ptr = aligned_alloc_device(alignment, size, *Q);
139+
return wrap(Ptr);
140+
} catch (feature_not_supported const &fns) {
141+
std::cerr << fns.what() << '\n';
142+
return nullptr;
143+
}
96144
}
97145

98146
void DPCTLfree_with_queue(__dpctl_take DPCTLSyclUSMRef MRef,
99147
__dpctl_keep const DPCTLSyclQueueRef QRef)
100148
{
149+
if (!QRef) {
150+
std::cerr << "Input QRef is nullptr\n";
151+
return;
152+
}
153+
if (!MRef) {
154+
std::cerr << "Input MRef is nullptr, nothing to free\n";
155+
return;
156+
}
101157
auto Ptr = unwrap(MRef);
102158
auto Q = unwrap(QRef);
103159
free(Ptr, *Q);
@@ -106,6 +162,14 @@ void DPCTLfree_with_queue(__dpctl_take DPCTLSyclUSMRef MRef,
106162
void DPCTLfree_with_context(__dpctl_take DPCTLSyclUSMRef MRef,
107163
__dpctl_keep const DPCTLSyclContextRef CRef)
108164
{
165+
if (!CRef) {
166+
std::cerr << "Input CRef is nullptr\n";
167+
return;
168+
}
169+
if (!MRef) {
170+
std::cerr << "Input MRef is nullptr, nothing to free\n";
171+
return;
172+
}
109173
auto Ptr = unwrap(MRef);
110174
auto C = unwrap(CRef);
111175
free(Ptr, *C);
@@ -114,6 +178,14 @@ void DPCTLfree_with_context(__dpctl_take DPCTLSyclUSMRef MRef,
114178
const char *DPCTLUSM_GetPointerType(__dpctl_keep const DPCTLSyclUSMRef MRef,
115179
__dpctl_keep const DPCTLSyclContextRef CRef)
116180
{
181+
if (!CRef) {
182+
std::cerr << "Input CRef is nullptr\n";
183+
return "unknown";
184+
}
185+
if (!MRef) {
186+
std::cerr << "Input MRef is nullptr\n";
187+
return "unknown";
188+
}
117189
auto Ptr = unwrap(MRef);
118190
auto C = unwrap(CRef);
119191

@@ -134,6 +206,15 @@ DPCTLSyclDeviceRef
134206
DPCTLUSM_GetPointerDevice(__dpctl_keep const DPCTLSyclUSMRef MRef,
135207
__dpctl_keep const DPCTLSyclContextRef CRef)
136208
{
209+
if (!CRef) {
210+
std::cerr << "Input CRef is nullptr\n";
211+
return nullptr;
212+
}
213+
if (!MRef) {
214+
std::cerr << "Input MRef is nullptr\n";
215+
return nullptr;
216+
}
217+
137218
auto Ptr = unwrap(MRef);
138219
auto C = unwrap(CRef);
139220

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)