Skip to content

Add wrapper for SYCL queue::memcpy(). #70

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions backends/include/dppl_sycl_queue_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,16 @@ DPPLQueue_GetDevice (__dppl_keep const DPPLSyclQueueRef QRef);
DPPL_API
void DPPLQueue_Delete (__dppl_take DPPLSyclQueueRef QRef);

/*!
* @brief C-API wrapper for sycl::queue::memcpy. It waits an event.
*
* @param QRef An opaque pointer to the sycl queue.
* @param Dest An USM pointer to the destination memory.
* @param Src An USM pointer to the source memory.
* @param Count A number of bytes to copy.
*/
DPPL_API
void DPPLQueue_Memcpy (__dppl_keep const DPPLSyclQueueRef QRef,
void *Dest, const void *Src, size_t Count);

DPPL_C_EXTERN_C_END
8 changes: 8 additions & 0 deletions backends/source/dppl_sycl_queue_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,11 @@ void DPPLQueue_Delete (__dppl_take DPPLSyclQueueRef QRef)
{
delete unwrap(QRef);
}

void DPPLQueue_Memcpy (__dppl_take const DPPLSyclQueueRef QRef,
void *Dest, const void *Src, size_t Count)
{
auto Q = unwrap(QRef);
auto event = Q->memcpy(Dest, Src, Count);
event.wait();
}
46 changes: 46 additions & 0 deletions dpctl/_memory.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
##===--------------- _memory.pxd - dpctl module --------*- Cython -*-------===##
##
## Data Parallel Control (dpCtl)
##
## Copyright 2020 Intel Corporation
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
##===----------------------------------------------------------------------===##

# distutils: language = c++
# cython: language_level=3

from .backend cimport DPPLSyclUSMRef
from ._sycl_core cimport SyclQueue


cdef class Memory:
cdef DPPLSyclUSMRef memory_ptr
cdef Py_ssize_t nbytes
cdef SyclQueue queue

cdef _cinit(self, Py_ssize_t nbytes, ptr_type, SyclQueue queue)
cdef _getbuffer(self, Py_buffer *buffer, int flags)


cdef class MemoryUSMShared(Memory):
pass


cdef class MemoryUSMHost(Memory):
pass


cdef class MemoryUSMDevice(Memory):
pass
3 changes: 0 additions & 3 deletions dpctl/_memory.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ from cpython cimport Py_buffer


cdef class Memory:
cdef DPPLSyclUSMRef memory_ptr
cdef Py_ssize_t nbytes
cdef SyclQueue queue

cdef _cinit(self, Py_ssize_t nbytes, ptr_type, SyclQueue queue):
cdef DPPLSyclUSMRef p
Expand Down
1 change: 1 addition & 0 deletions dpctl/_sycl_core.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,4 @@ cdef class SyclQueue:
cpdef SyclContext get_sycl_context (self)
cpdef SyclDevice get_sycl_device (self)
cdef DPPLSyclQueueRef get_queue_ref (self)
cpdef memcpy (self, dest, src, int count)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean cdef ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For c part of cpdef to be efficient, dest and src need have type declarations. Looks like they can only be Memory objects.

The method does not use self at all, so should it be a static method of the class?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method uses self in code DPPLQueue_memcpy(self.queue_ptr, c_dest, c_src, count).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it would be better to not expose memcpy as a stand-alone symbol, but rather make it two method copyto and copyfrom of Memory object. That way it could copy to/from another Memory object, or host memory of any object that supports a buffer protocol.

3 changes: 3 additions & 0 deletions dpctl/backend.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ cdef extern from "dppl_sycl_queue_interface.h":
except+
cdef DPPLSyclDeviceRef DPPLQueue_GetDevice (const DPPLSyclQueueRef Q) \
except +
cdef void DPPLQueue_Memcpy (const DPPLSyclQueueRef Q,
void *Dest, const void *Src, size_t Count) \
except +


cdef extern from "dppl_sycl_queue_manager.h":
Expand Down
19 changes: 18 additions & 1 deletion dpctl/sycl_core.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
from __future__ import print_function
from enum import Enum, auto
import logging
from dpctl.backend cimport *
from .backend cimport *
from ._memory cimport Memory


_logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -132,6 +133,22 @@ cdef class SyclQueue:
cdef DPPLSyclQueueRef get_queue_ref (self):
return self.queue_ptr

cpdef memcpy (self, dest, src, int count):
cdef void *c_dest
cdef void *c_src

if isinstance(dest, Memory):
c_dest = <void*>(<Memory>dest).memory_ptr
else:
raise TypeError("Parameter dest should be Memory.")

if isinstance(src, Memory):
c_src = <void*>(<Memory>src).memory_ptr
else:
raise TypeError("Parameter src should be Memory.")

DPPLQueue_Memcpy(self.queue_ptr, c_dest, c_src, count)


cdef class _SyclQueueManager:
def _set_as_current_queue (self, device_ty, device_id):
Expand Down
70 changes: 70 additions & 0 deletions dpctl/tests/test_sycl_queue_memcpy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
##===---------- test_sycl_queue_manager.py - dpctl -------*- Python -*----===##
##
## Data Parallel Control (dpCtl)
##
## Copyright 2020 Intel Corporation
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
##===----------------------------------------------------------------------===##
###
### \file
### Defines unit test cases for the SyclQueue.memcpy in sycl_core.pyx.
##===----------------------------------------------------------------------===##

import dpctl
import unittest



class TestQueueMemcpy (unittest.TestCase):

def _create_memory (self):
nbytes = 1024
queue = dpctl.get_current_queue()
mobj = dpctl._memory.MemoryUSMShared(nbytes, queue)
return mobj

def test_memcpy_copy_usm_to_usm (self):
mobj1 = self._create_memory()
mobj2 = self._create_memory()
q = dpctl.get_current_queue()

mv1 = memoryview(mobj1)
mv2 = memoryview(mobj2)

mv1[:3] = b'123'

q.memcpy(mobj2, mobj1, 3)

self.assertEqual(mv2[:3], b'123')

def test_memcpy_type_error (self):
mobj = self._create_memory()
q = dpctl.get_current_queue()

with self.assertRaises(TypeError) as cm:
q.memcpy(None, mobj, 3)

self.assertEqual(type(cm.exception), TypeError)
self.assertEqual(str(cm.exception), "Parameter dest should be Memory.")

with self.assertRaises(TypeError) as cm:
q.memcpy(mobj, None, 3)

self.assertEqual(type(cm.exception), TypeError)
self.assertEqual(str(cm.exception), "Parameter src should be Memory.")


if __name__ == '__main__':
unittest.main()
8 changes: 8 additions & 0 deletions dpctl/tests/test_sycl_usm.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ def test_memory_gpu_context (self):
self.assertTrue(usm_type in ['unknown', 'shared'])


def test_buffer_protocol (self):
mobj = self._create_memory()
mv1 = memoryview(mobj)
mv2 = memoryview(mobj)
self.assertEqual(mv1, mv2)


class TestMemoryUSMBase:
""" Base tests for MemoryUSM* """

Expand Down Expand Up @@ -116,5 +123,6 @@ class TestMemoryUSMDevice(TestMemoryUSMBase, unittest.TestCase):
MemoryUSMClass = MemoryUSMDevice
usm_type = 'device'


if __name__ == '__main__':
unittest.main()