Skip to content

Commit a286cc3

Browse files
committed
Allow tying an svm_allocation to a queue
1 parent 8c15afc commit a286cc3

3 files changed

Lines changed: 60 additions & 9 deletions

File tree

pyopencl/__init__.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,12 +1146,13 @@ def memory_map_exit(self, exc_type, exc_val, exc_tb):
11461146
if get_cl_header_version() >= (2, 0):
11471147
svmallocation_old_init = SVMAllocation.__init__
11481148

1149-
def svmallocation_init(self, ctx, size, alignment, flags, _interface=None):
1149+
def svmallocation_init(self, ctx, size, alignment, flags, _interface=None,
1150+
queue=None):
11501151
"""
11511152
:arg ctx: a :class:`Context`
11521153
:arg flags: some of :class:`svm_mem_flags`.
11531154
"""
1154-
svmallocation_old_init(self, ctx, size, alignment, flags)
1155+
svmallocation_old_init(self, ctx, size, alignment, flags, queue)
11551156

11561157
# mem_flags.READ_ONLY applies to kernels, not the host
11571158
read_write = True
@@ -1996,7 +1997,7 @@ def enqueue_svm_migratemem(queue, svms, flags, wait_for=None):
19961997
wait_for)
19971998

19981999

1999-
def svm_empty(ctx, flags, shape, dtype, order="C", alignment=None):
2000+
def svm_empty(ctx, flags, shape, dtype, order="C", alignment=None, queue=None):
20002001
"""Allocate an empty :class:`numpy.ndarray` of the given *shape*, *dtype*
20012002
and *order*. (See :func:`numpy.empty` for the meaning of these arguments.)
20022003
The array will be allocated in shared virtual memory belonging
@@ -2014,6 +2015,10 @@ def svm_empty(ctx, flags, shape, dtype, order="C", alignment=None):
20142015
will likely want to wrap the returned array in an :class:`SVM` tag.
20152016
20162017
.. versionadded:: 2016.2
2018+
2019+
.. versionchanged:: 2022.2
2020+
2021+
*queue* argument added.
20172022
"""
20182023

20192024
dtype = np.dtype(dtype)
@@ -2060,7 +2065,8 @@ def svm_empty(ctx, flags, shape, dtype, order="C", alignment=None):
20602065
if alignment is None:
20612066
alignment = itemsize
20622067

2063-
svm_alloc = SVMAllocation(ctx, nbytes, alignment, flags, _interface=interface)
2068+
svm_alloc = SVMAllocation(ctx, nbytes, alignment, flags, _interface=interface,
2069+
queue=queue)
20642070
return np.asarray(svm_alloc)
20652071

20662072

src/wrap_cl.hpp

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3562,16 +3562,28 @@ namespace pyopencl
35623562
};
35633563

35643564

3565-
class svm_allocation : noncopyable
3565+
class svm_allocation
35663566
{
35673567
private:
35683568
std::shared_ptr<context> m_context;
35693569
void *m_allocation;
3570+
command_queue_ref m_queue;
3571+
// FIXME Should keep a list of events so that we can wait for users
3572+
// to finish in the case of out-of-order queues.
35703573

35713574
public:
3572-
svm_allocation(std::shared_ptr<context> const &ctx, size_t size, cl_uint alignment, cl_svm_mem_flags flags)
3575+
svm_allocation(std::shared_ptr<context> const &ctx, size_t size, cl_uint alignment,
3576+
cl_svm_mem_flags flags, const command_queue *queue = nullptr)
35733577
: m_context(ctx)
35743578
{
3579+
if (queue)
3580+
{
3581+
m_queue.set(queue->data());
3582+
if (!is_queue_in_order(m_queue.data()))
3583+
throw error("SVMAllocation.__init__", CL_INVALID_VALUE,
3584+
"supplying an out-of-order queue to SVMAllocation is invalid");
3585+
}
3586+
35753587
PYOPENCL_PRINT_CALL_TRACE("clSVMalloc");
35763588
m_allocation = clSVMAlloc(
35773589
ctx->data(),
@@ -3581,6 +3593,9 @@ namespace pyopencl
35813593
throw pyopencl::error("clSVMAlloc", CL_OUT_OF_RESOURCES);
35823594
}
35833595

3596+
svm_allocation(const svm_allocation &) = delete;
3597+
svm_allocation &operator=(const svm_allocation &) = delete;
3598+
35843599
~svm_allocation()
35853600
{
35863601
if (m_allocation)
@@ -3593,8 +3608,20 @@ namespace pyopencl
35933608
throw error("SVMAllocation.release", CL_INVALID_VALUE,
35943609
"trying to double-unref svm allocation");
35953610

3596-
clSVMFree(m_context->data(), m_allocation);
3597-
m_allocation = nullptr;
3611+
if (m_queue.is_valid())
3612+
{
3613+
PYOPENCL_CALL_GUARDED_CLEANUP(clEnqueueSVMFree, (
3614+
m_queue.data(), 1, &m_allocation,
3615+
nullptr, nullptr,
3616+
0, nullptr, nullptr));
3617+
m_queue.reset();
3618+
}
3619+
else
3620+
{
3621+
PYOPENCL_PRINT_CALL_TRACE("clSVMFree");
3622+
clSVMFree(m_context->data(), m_allocation);
3623+
m_allocation = nullptr;
3624+
}
35983625
}
35993626

36003627
void enqueue_release(command_queue &queue, py::object py_wait_for)
@@ -3634,6 +3661,16 @@ namespace pyopencl
36343661
{
36353662
return m_allocation != other.m_allocation;
36363663
}
3664+
3665+
void bind_to_queue(command_queue const &queue)
3666+
{
3667+
m_queue.set(queue.data());
3668+
}
3669+
3670+
void unbind_from_queue()
3671+
{
3672+
m_queue.reset();
3673+
}
36373674
};
36383675

36393676

src/wrap_cl_part_2.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,13 @@ void pyopencl_expose_part_2(py::module &m)
305305
{
306306
typedef svm_allocation cls;
307307
py::class_<cls>(m, "SVMAllocation", py::dynamic_attr())
308-
.def(py::init<std::shared_ptr<context>, size_t, cl_uint, cl_svm_mem_flags>())
308+
.def(py::init<std::shared_ptr<context>, size_t, cl_uint, cl_svm_mem_flags, const command_queue *>(),
309+
py::arg("context"),
310+
py::arg("size"),
311+
py::arg("alignment"),
312+
py::arg("flags"),
313+
py::arg("queue").none(true)=py::none()
314+
)
309315
.DEF_SIMPLE_METHOD(release)
310316
.def("enqueue_release", &cls::enqueue_release,
311317
":returns: a :class:`pyopencl.Event`\n\n"
@@ -314,6 +320,8 @@ void pyopencl_expose_part_2(py::module &m)
314320
.def(py::self == py::self)
315321
.def(py::self != py::self)
316322
.def("__hash__", &cls::ptr_as_int)
323+
.DEF_SIMPLE_METHOD(bind_to_queue)
324+
.DEF_SIMPLE_METHOD(unbind_from_queue)
317325
;
318326
}
319327

0 commit comments

Comments
 (0)