From defc264e68470e0ff9c582bf9495392b8b82f819 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Tue, 15 Sep 2020 10:32:59 +0300 Subject: [PATCH 01/41] Move _memory.pyx --- dppl/_memory.pyx | 154 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 dppl/_memory.pyx diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx new file mode 100644 index 0000000000..4d6639a0c4 --- /dev/null +++ b/dppl/_memory.pyx @@ -0,0 +1,154 @@ +import dppl + +from cython.operator cimport dereference as deref + +from cpython.pycapsule cimport PyCapsule_GetPointer +from cpython cimport Py_buffer + +cdef extern from "CL/sycl.hpp" namespace "cl::sycl::usm": + cdef enum alloc: + host 'cl::sycl::usm::alloc::host' + device 'cl::sycl::usm::alloc::device' + shared 'cl::sycl::usm::alloc::shared' + unknown 'cl::sycl::usm::alloc::unknown' + +cdef extern from "CL/sycl.hpp" namespace "cl::sycl": + cdef cppclass context nogil: + pass + + cdef cppclass queue nogil: + context get_context() nogil + pass + + cdef void* malloc_shared(Py_ssize_t, queue&) nogil + cdef void free(void *, queue&) nogil + cdef alloc get_pointer_type(void *, context&) nogil + + +cdef class SyclQueue: + cdef object queue_cap + cdef queue q + + def __cinit__(self): + cdef void* q_ptr + self.queue_cap = dppl.get_current_queue() + q_ptr = PyCapsule_GetPointer(self.queue_cap, NULL) + if (q_ptr): + self.q = deref(q_ptr) + else: + raise ValueError("NULL pointer returned by the Capsule") + + def get_pointer_type(self, Py_ssize_t p): + cdef context ctx = self.q.get_context() + cdef void * p_ptr = p + + ptr_type = get_pointer_type(p_ptr, ctx) + if (ptr_type == alloc.shared): + return "shared" + elif (ptr_type == alloc.host): + return "host" + elif (ptr_type == alloc.device): + return "device" + else: + return "unknown" + + property get_capsule: + def __get__(self): + return self.queue_cap + + cdef queue get_queue(self): + return self.q + + +cdef class Memory: + cdef void* _ptr + cdef Py_ssize_t nbytes + cdef object queue_cap + + def __cinit__(self, Py_ssize_t nbytes): + cdef object q_cap + cdef void* queue_ptr + cdef void* p + + self._ptr = NULL + self.queue_cap = None + self.nbytes = 0 + + if (nbytes > 0): + q_cap = dppl.get_current_queue() + queue_ptr = PyCapsule_GetPointer(q_cap, NULL) + p = malloc_shared(nbytes, deref(queue_ptr)) + if (p): + self._ptr = p + self.nbytes = nbytes + self.queue_cap = q_cap + else: + raise RuntimeError("Null memory pointer returned") + else: + raise ValueError("Non-positive number of bytes found.") + + def __dealloc__(self): + cdef void* queue_ptr + + if (self._ptr): + queue_ptr = PyCapsule_GetPointer(self.queue_cap, NULL) + free(self._ptr, deref(queue_ptr)) + self._ptr = NULL + self.nbytes = 0 + self.queue_cap = None + + def __getbuffer__(self, Py_buffer *buffer, int flags): + buffer.buf = self._ptr + buffer.format = 'B' # byte + buffer.internal = NULL # see References + buffer.itemsize = 1 + buffer.len = self.nbytes + buffer.ndim = 1 + buffer.obj = self + buffer.readonly = 0 + buffer.shape = &self.nbytes + buffer.strides = &buffer.itemsize + buffer.suboffsets = NULL # for pointer arrays only + + property pointer: + def __get__(self): + return (self._ptr) + + property nbytes: + def __get__(self): + return self.nbytes + + property _queue: + def __get__(self): + return self.queue_cap + + def __repr__(self): + return "".format(self.nbytes, hex((self._ptr))) + + def _usm_type(self, qcaps=None): + cdef void *q_ptr + cdef alloc ptr_type + + _cap = qcaps if (qcaps) else self.queue_cap + q_ptr = PyCapsule_GetPointer(_cap, NULL) + ptr_type = get_pointer_type(self._ptr, deref(q_ptr).get_context()) + if (ptr_type == alloc.shared): + return "shared" + elif (ptr_type == alloc.host): + return "host" + elif (ptr_type == alloc.device): + return "device" + else: + return "unknown" + +# cdef void* _ptr +# cdef Py_ssize_t nbytes +# cdef object queue_cap + + @staticmethod + cdef Memory create(void *p, Py_ssize_t nbytes, object queue_cap): + cdef Memory ret = Memory.__new__() + ret._ptr = p + ret.nbytes = nbytes + ret.q_cap = queue_cap + return ret From 8b811c593d661b3d190fde6c1e160438e170d8b6 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Tue, 15 Sep 2020 10:54:56 +0300 Subject: [PATCH 02/41] Import setuptools before Cython. Otherwise, both might disagree about the class to use. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a7c209ee3c..b0f188327e 100644 --- a/setup.py +++ b/setup.py @@ -25,8 +25,8 @@ import sys import versioneer -from Cython.Build import cythonize from setuptools import setup, Extension, find_packages +from Cython.Build import cythonize import numpy as np From 07042585f52c65ec2f55259e5bb08320d8d8c9b4 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Tue, 15 Sep 2020 15:50:28 +0300 Subject: [PATCH 03/41] Add dppl._memory Cython module. --- setup.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/setup.py b/setup.py index b0f188327e..76a7070412 100644 --- a/setup.py +++ b/setup.py @@ -104,17 +104,22 @@ def getpyexts(): elif IS_WIN: runtime_library_dirs = [] - exts = cythonize(Extension('dppl._sycl_core', - [os.path.abspath('dppl/sycl_core.pyx'),], - depends=[dppl_sycl_interface_include,], - include_dirs=[np.get_include(), - dppl_sycl_interface_include], - extra_compile_args=eca + get_other_cxxflags(), - extra_link_args=ela, - libraries=libs, - library_dirs=librarys, - runtime_library_dirs=runtime_library_dirs, - language='c++')) + extension_args = { + "depends": [dppl_sycl_interface_include,], + "include_dirs": [np.get_include(), dppl_sycl_interface_include], + "extra_compile_args": eca + get_other_cxxflags(), + "extra_link_args": ela, "libraries": libs, "library_dirs": librarys, + "runtime_library_dirs": runtime_library_dirs, "language": 'c++', + } + + extensions = [ + Extension('dppl._sycl_core', [os.path.abspath('dppl/sycl_core.pyx'),], + **extension_args), + Extension('dppl._memory', [os.path.abspath('dppl/_memory.pyx'),], + **extension_args), + ] + + exts = cythonize(extensions) return exts setup( From e57927dd4960ca1fd502277307ee3bbfc9bef8fd Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Tue, 15 Sep 2020 15:51:35 +0300 Subject: [PATCH 04/41] Run dppl/tests/dppl_tests too when run all unit tests. --- dppl/tests/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dppl/tests/__init__.py b/dppl/tests/__init__.py index b7d39c5dfd..6bd91b208f 100644 --- a/dppl/tests/__init__.py +++ b/dppl/tests/__init__.py @@ -1 +1,2 @@ from .test_dump_functions import * +from .dppl_tests import * From 267492f0021cb3e0407db58e2afc4d4161c75f47 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Tue, 15 Sep 2020 17:17:48 +0300 Subject: [PATCH 05/41] Add tests for memory manager. --- dppl/tests/dppl_tests/__init__.py | 3 +- .../dppl_tests/test_sycl_memory_manager.py | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 dppl/tests/dppl_tests/test_sycl_memory_manager.py diff --git a/dppl/tests/dppl_tests/__init__.py b/dppl/tests/dppl_tests/__init__.py index adcaad3954..7017278251 100644 --- a/dppl/tests/dppl_tests/__init__.py +++ b/dppl/tests/dppl_tests/__init__.py @@ -1 +1,2 @@ -from .test_sycl_queue_manager import * \ No newline at end of file +from .test_sycl_queue_manager import * +from .test_sycl_memory_manager import * diff --git a/dppl/tests/dppl_tests/test_sycl_memory_manager.py b/dppl/tests/dppl_tests/test_sycl_memory_manager.py new file mode 100644 index 0000000000..06114984ed --- /dev/null +++ b/dppl/tests/dppl_tests/test_sycl_memory_manager.py @@ -0,0 +1,45 @@ +##===---------- test_sycl_queue_manager.py - dppl -------*- Python -*-----===## +## +## Python Data Parallel Processing Library (PyDPPL) +## +## 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. +## +##===----------------------------------------------------------------------===## + +import unittest +import dppl +import dppl._memory as mem + + +class TestMemory (unittest.TestCase): + # @unittest.skipIf(not dppl.has_sycl_platforms, "No SYCL platforms available") + def test_memory_create (self): + nbytes = 1024 + mobj = mem.Memory(nbytes) + self.assertEqual(mobj.nbytes, nbytes) + + # Without context + self.assertEqual(mem.SyclQueue().get_pointer_type(mobj.pointer), 'shared') + self.assertEqual(mobj._usm_type(), 'shared') + + # CPU context + with dppl.device_context(dppl.device_type.cpu): + self.assertEqual(mem.SyclQueue().get_pointer_type(mobj.pointer), 'unknown') + self.assertEqual(mobj._usm_type(), 'shared') + + # GPU context + with dppl.device_context(dppl.device_type.gpu): + self.assertEqual(mem.SyclQueue().get_pointer_type(mobj.pointer), 'unknown') + self.assertEqual(mobj._usm_type(), 'shared') From 5ff3eb083619eac408a0e16d444c9ed79a73802d Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Tue, 15 Sep 2020 17:25:02 +0300 Subject: [PATCH 06/41] Split tests for memory. One test one context (no, CPU, GPU). --- dppl/tests/dppl_tests/test_sycl_memory_manager.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dppl/tests/dppl_tests/test_sycl_memory_manager.py b/dppl/tests/dppl_tests/test_sycl_memory_manager.py index 06114984ed..95051310db 100644 --- a/dppl/tests/dppl_tests/test_sycl_memory_manager.py +++ b/dppl/tests/dppl_tests/test_sycl_memory_manager.py @@ -30,15 +30,29 @@ def test_memory_create (self): mobj = mem.Memory(nbytes) self.assertEqual(mobj.nbytes, nbytes) + def _create_memory (self): + nbytes = 1024 + mobj = mem.Memory(nbytes) + return mobj + + def test_memory_without_context (self): + mobj = self._create_memory() + # Without context self.assertEqual(mem.SyclQueue().get_pointer_type(mobj.pointer), 'shared') self.assertEqual(mobj._usm_type(), 'shared') + def test_memory_cpu_context (self): + mobj = self._create_memory() + # CPU context with dppl.device_context(dppl.device_type.cpu): self.assertEqual(mem.SyclQueue().get_pointer_type(mobj.pointer), 'unknown') self.assertEqual(mobj._usm_type(), 'shared') + def test_memory_gpu_context (self): + mobj = self._create_memory() + # GPU context with dppl.device_context(dppl.device_type.gpu): self.assertEqual(mem.SyclQueue().get_pointer_type(mobj.pointer), 'unknown') From 902bc8a54f74d8e9434a1348965fb4b208ff5904 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Tue, 15 Sep 2020 17:50:29 +0300 Subject: [PATCH 07/41] [opt] Rename getpyexts() to extensions(). --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 76a7070412..2a90338032 100644 --- a/setup.py +++ b/setup.py @@ -78,7 +78,7 @@ def get_other_cxxflags(): # what compiler we are using. return ['/Ox', '/std:c++17'] -def getpyexts(): +def extensions(): # Security flags eca = get_sdl_cflags() ela = get_sdl_ldflags() @@ -131,7 +131,7 @@ def getpyexts(): author="Intel Corporation", url='https://github.com/IntelPython/PyDPPL', packages=find_packages(include=["dppl", "dppl.*"]), - ext_modules = getpyexts(), + ext_modules = extensions(), setup_requires=requirements, cffi_modules=[ "./dppl/opencl_core.py:ffi" From 5d8187968ec30bf4263d3bce06617a179c9a3ea5 Mon Sep 17 00:00:00 2001 From: Diptorup Deb Date: Tue, 15 Sep 2020 17:46:17 -0500 Subject: [PATCH 08/41] Adds C and Cython API for portions of Sycl queue, device, context interfaces. - Separates out the queue manager from the sycl queue interface wrapper. - Added API to get context, device froma Sycl queue. - Added C-API wrappers for sycl device, queue, context interfaces exposing some of the API functionalities. More can be added as needed. - The dppl extension now defines extension types for sycl quque, device, context to mimic the C API. - Sycl queues are now returned to callers as a SyclQueue extension type rather than a Py_capsule. --- backends/CMakeLists.txt | 3 + .../include/dppl_sycl_context_interface.h | 52 +++ backends/include/dppl_sycl_device_interface.h | 178 ++++++++ backends/include/dppl_sycl_queue_interface.h | 155 +------ backends/include/dppl_sycl_queue_manager.h | 151 +++++++ backends/include/dppl_sycl_types.h | 27 +- backends/include/error_check_macros.h | 1 + .../source/dppl_sycl_context_interface.cpp | 58 +++ .../source/dppl_sycl_device_interface.cpp | 147 +++++++ backends/source/dppl_sycl_queue_interface.cpp | 387 +----------------- backends/source/dppl_sycl_queue_manager.cpp | 366 +++++++++++++++++ backends/tests/CMakeLists.txt | 2 +- backends/tests/test_sycl_queue_manager.cpp | 40 +- dppl/sycl_core.pyx | 161 ++++++-- .../dppl_tests/test_sycl_queue_manager.py | 5 +- dppl/tests/test_dump_functions.py | 6 +- 16 files changed, 1193 insertions(+), 546 deletions(-) create mode 100644 backends/include/dppl_sycl_context_interface.h create mode 100644 backends/include/dppl_sycl_device_interface.h create mode 100644 backends/include/dppl_sycl_queue_manager.h create mode 100644 backends/source/dppl_sycl_context_interface.cpp create mode 100644 backends/source/dppl_sycl_device_interface.cpp create mode 100644 backends/source/dppl_sycl_queue_manager.cpp diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index 3a9a0434d4..921bb1d3eb 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -96,7 +96,10 @@ message(STATUS "OpenCL_LIBRARY: ${OpenCL_LIBRARY}") add_library( DPPLSyclInterface SHARED + source/dppl_sycl_context_interface.cpp + source/dppl_sycl_device_interface.cpp source/dppl_sycl_queue_interface.cpp + source/dppl_sycl_queue_manager.cpp ) # Install DPPLOpenCLInterface diff --git a/backends/include/dppl_sycl_context_interface.h b/backends/include/dppl_sycl_context_interface.h new file mode 100644 index 0000000000..6cd3c271a2 --- /dev/null +++ b/backends/include/dppl_sycl_context_interface.h @@ -0,0 +1,52 @@ +//===--- dppl_sycl_context_interface.h - DPPL-SYCL interface --*--C++ --*--===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This header declares a C API to SYCL's sycl::context interface. +/// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "dppl_data_types.h" +#include "dppl_sycl_types.h" +#include "Support/DllExport.h" +#include "Support/ExternC.h" +#include "Support/MemOwnershipAttrs.h" +#include + +DPPL_C_EXTERN_C_BEGIN + +/*! + * @brief Returns true if this SYCL context is a host context. + * + * @param CtxtRef A opaque pointer to a sycl::context. + * @return True if the SYCL context is a host context, else False. + */ +bool DPPLIsHostContext (__dppl_keep const DPPLSyclContextRef CtxtRef); + +/*! + * @brief Delete the pointer after casting it to sycl::context + * + * @param CtxtRef The DPPLSyclContextRef pointer to be deleted. + */ +void DPPLDeleteSyclContext (__dppl_take DPPLSyclContextRef CtxtRef); + +DPPL_C_EXTERN_C_END diff --git a/backends/include/dppl_sycl_device_interface.h b/backends/include/dppl_sycl_device_interface.h new file mode 100644 index 0000000000..e379f7d733 --- /dev/null +++ b/backends/include/dppl_sycl_device_interface.h @@ -0,0 +1,178 @@ +//===--- dppl_sycl_device_interface.h - DPPL-SYCL interface ---*---C++ -*---===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This header declares a C interface to sycl::device. Not all of the device +/// API is exposed, only the bits needed in other places like context and queue +/// interfaces. +/// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "dppl_data_types.h" +#include "dppl_sycl_types.h" +#include "Support/DllExport.h" +#include "Support/ExternC.h" +#include "Support/MemOwnershipAttrs.h" + +DPPL_C_EXTERN_C_BEGIN + +/*! + * @brief Redefinition of Sycl's device_type so that we do not have to include + * sycl.hpp here and in the Python bindings. + * + */ +typedef enum +{ + DPPL_CPU, + DPPL_GPU, + DPPL_ACCELERATOR, + DPPL_CUSTOM, + DPPL_AUTOMATIC, + DPPL_HOST, + DPPL_ALL +} DPPLSyclDeviceType; + +/*! + * @brief Prints out some of the info::deivice attributes for the device. + * + * @param DRef A DPPLSyclDeviceRef pointer. + */ +DPPL_API +void DPPLDumpDeviceInfo (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Deletes a DPPLSyclDeviceRef pointer after casting to to sycl::device. + * + * @param DRef The DPPLSyclDeviceRef pointer to be freed. + */ +DPPL_API +void DPPLDeleteSyclDevice (__dppl_take DPPLSyclDeviceRef DRef); + +/*! + * @brief Returns true if this SYCL device is an OpenCL device and the device + * type is sycl::info::device_type::accelerator. + * + * @param DRef Opaque pointer to a sycl::device + * @return True if the device type is an accelerator, else False. + */ +DPPL_API +bool DPPLDeviceIsAccelerator (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Returns true if this SYCL device is an OpenCL device and the device + * type is sycl::info::device_type::cpu. + * + * @param DRef Opaque pointer to a sycl::device + * @return True if the device type is a cpu, else False. + */ +DPPL_API +bool DPPLDeviceIsCPU (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Returns true if this SYCL device is an OpenCL device and the device + * type is sycl::info::device_type::gpu. + * + * @param DRef Opaque pointer to a sycl::device + * @return True if the device type is a gpu, else False. + */ +DPPL_API +bool DPPLDeviceIsGPU (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Returns true if this SYCL device is a host device. + * + * @param DRef Opaque pointer to a sycl::device + * @return True if the device is a host device, else False. + */ +DPPL_API +bool DPPLDeviceIsHost (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Returns the OpenCL software driver version as a C string. + * + * @param DRef Opaque pointer to a sycl::device + * @return A C string in the form major_number.minor.number that corresponds + * to the OpenCL driver version if this is a OpenCL device. + */ +DPPL_API +__dppl_give const char* +DPPLGetDeviceDriverInfo (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Deletes a C string corresponding to the string returned by + * DPPLGetDeviceDriverInfo(). + * + * @param DriverInfo C String for the driver number. + */ +DPPL_API +void DPPLDeleteDeviceDriverInfo (__dppl_take const char* DriverInfo); + +/*! + * @brief Returns a C string for the device name. + * + * @param DRef Opaque pointer to a sycl::device + * @return A C string containing the OpenCL device name. + */ +DPPL_API +__dppl_give const char* +DPPLGetDeviceName (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Deletes a C string corresponding to the string returned by + * DPPLGetDeviceName(). + * + * @param DeviceName C String for the device name. + */ +DPPL_API +void DPPLDeleteDeviceName (__dppl_take const char* DeviceName); + +/*! + * @brief Returns a C string corresponding to the vendor name. + * + * @param DRef Opaque pointer to a sycl::device + * @return A C string containing the OpenCL device vendor name. + */ +DPPL_API +__dppl_give const char* +DPPLGetDeviceVendorName (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Deletes a C string corresponding to the string returned by + * DPPLGetDeviceVendorName(). + * + * @param char C String for the vendor name. + */ +DPPL_API +void DPPLDeleteDeviceVendorName (__dppl_take const char* VendorName); + +/*! + * @brief Returns True if the device and the host share a unified memory + * subsystem, else returns False. + * + * @param DRef Opaque pointer to a sycl::device + * @return Boolean indicating if the device shares a unified memory subsystem + * with the host. + */ +DPPL_API +bool DPPLGetDeviceHostUnifiedMemory (__dppl_keep const DPPLSyclDeviceRef DRef); + +DPPL_C_EXTERN_C_END diff --git a/backends/include/dppl_sycl_queue_interface.h b/backends/include/dppl_sycl_queue_interface.h index d85803b735..f2493b87f9 100644 --- a/backends/include/dppl_sycl_queue_interface.h +++ b/backends/include/dppl_sycl_queue_interface.h @@ -19,15 +19,9 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This header declares a C interface to DPPL's sycl::queue manager class that -/// maintains a thread local stack of sycl::queues objects for use inside -/// Python programs. The C interface is designed in a way to not have to -/// include the Sycl headers inside a Python extension module, since that would -/// require the extension to be compiled using dpc++ or another Sycl compiler. -/// Compiling the extension with a compiler different from what was used to -/// compile the Python interpreter can cause run-time problems especially on MS -/// Windows. Additionally, the C interface makes it easier to interoperate with -/// Numba without having to deal with C++ name mangling. +/// This header declares a C interface to sycl::queue member functions. Note +/// that sycl::queue constructors are not exposed in this interface. Instead, +/// users should use the functions in dppl_sycl_queue_manager.h. /// //===----------------------------------------------------------------------===// @@ -42,151 +36,38 @@ DPPL_C_EXTERN_C_BEGIN /*! - * @brief Redefinition of Sycl's device_type so that we do not have to include - * sycl.hpp here and in the Python bindings. - * - */ -typedef enum -{ - DPPL_CPU, - DPPL_GPU, - DPPL_ACCELERATOR, - DPPL_CUSTOM, - DPPL_AUTOMATIC, - DPPL_HOST, - DPPL_ALL -} DPPLSyclDeviceType; - - -/*! - * @brief Get the number of sycl::platform available on the system. - * - * @return The number of available sycl::platforms. - */ -DPPL_API -size_t DPPLGetNumPlatforms (); - -/*! - * @brief Get the sycl::queue object that is currently activated for this - * thread. - * - * @return A copy of the current (top of the stack) sycl::queue is returned - * wrapped inside an opaque DPPLSyclQueueRef pointer. - */ -DPPL_API -__dppl_give DPPLSyclQueueRef DPPLGetCurrentQueue (); - -/*! - * @brief Get a sycl::queue object of the specified type and device id. - * - * @param DeviceTy The type of Sycl device (sycl_device_type) - * @param DNum Device id for the device (defaults to 0) - * - * @return A copy of the sycl::queue corresponding to the device is returned - * wrapped inside a DPPLSyclDeviceType pointer. A runtime_error exception is - * raised if no such device exists. - */ -DPPL_API -__dppl_give DPPLSyclQueueRef DPPLGetQueue (DPPLSyclDeviceType DeviceTy, - size_t DNum); - -/*! - * @brief Get the number of activated queues not including the global or - * default queue. - * - * @return The number of activated queues. - */ -DPPL_API -size_t DPPLGetNumActivatedQueues (); - -/*! - * @brief Get the number of GPU queues available on the system. - * - * @return The number of available GPU queues. - */ -DPPL_API -size_t DPPLGetNumGPUQueues (); - -/*! - * @brief Get the number of CPU queues available on the system. - * - * @return The number of available CPU queues. - */ -DPPL_API -size_t DPPLGetNumCPUQueues (); - -/*! -* @brief Set the default DPPL queue to the sycl::queue for the given device. -* -* If no such device is found the a runtime_error exception is thrown. -* -* @param DeviceTy The type of Sycl device (sycl_device_type) -* @param DNum Device id for the device (defaults to 0) -*/ -DPPL_API -void DPPLSetAsDefaultQueue (DPPLSyclDeviceType DeviceTy, - size_t DNum); - -/*! - * @brief Pushes a new sycl::queue object to the top of DPPL's thread-local - * stack of a "activated" queues, and returns a copy of the queue to caller. - * - * DPPL maintains a thread-local stack of sycl::queue objects to facilitate - * nested parallelism. The sycl::queue at the top of the stack is termed as the - * currently activated queue, and is always the one returned by - * DPPLGetCurrentQueue(). DPPLPushSyclQueueToStack creates a new sycl::queue - * corresponding to the specified device and pushes it to the top of the stack. - * A copy of the sycl::queue is returned to the caller wrapped inside the - * opaque DPPLSyclQueueRef pointer. A runtime_error exception is thrown when - * a new sycl::queue could not be created for the specified device. - * - * @param DeviceTy The type of Sycl device (sycl_device_type) - * @param DNum Device id for the device (defaults to 0) - * - * @return A copy of the sycl::queue that was pushed to the top of DPPL's - * stack of sycl::queue objects. + * @brief Prints out information about the Sycl environment, such as + * number of available platforms, number of activated queues, etc. */ DPPL_API -__dppl_give DPPLSyclQueueRef DPPLPushSyclQueue (DPPLSyclDeviceType DeviceTy, - size_t DNum); +void DPPLDumpPlatformInfo (); /*! - * @brief Pops the top of stack element from DPPL's stack of activated - * sycl::queue objects. - * - * DPPLPopSyclQueue only removes the reference from the DPPL stack of - * sycl::queue objects. Any instance of the popped queue that were previously - * acquired by calling DPPLPushSyclQueue() or DPPLGetCurrentQueue() needs to be - * freed separately. In addition, a runtime_error is thrown when the stack - * contains only one sycl::queue, i.e., the default queue. + * @brief Returns the Sycl context for the queue. * + * @param QRef An opaque pointer to the sycl queue. + * @return A DPPLSyclContextRef pointer to the sycl context for the queue. */ DPPL_API -void DPPLPopSyclQueue (); - -/*! - * @brief Prints out information about the Sycl environment, such as - * number of available platforms, number of activated queues, etc. - */ -DPPL_API -void DPPLDumpPlatformInfo (); +__dppl_give DPPLSyclContextRef +DPPLGetContextFromQueue (__dppl_keep const DPPLSyclQueueRef QRef); /*! - * @brief Prints out information about the device corresponding to the - * sycl::queue argument. + * @brief returns the Sycl device for the queue. * - * @param QRef A DPPLSyclQueueRef pointer whose metadata will be - * printed out. + * @param QRef An opaque pointer to the sycl queue. + * @return A DPPLSyclDeviceRef pointer to the sycl device for the queue. */ DPPL_API -void DPPLDumpDeviceInfo (__dppl_keep const DPPLSyclQueueRef QRef); +__dppl_give DPPLSyclDeviceRef +DPPLGetDeviceFromQueue (__dppl_keep const DPPLSyclQueueRef QRef); /*! - * @brief Delete the pointer after static casting it to sycl::queue. + * @brief Delete the pointer after casting it to sycl::queue. * * @param QRef A DPPLSyclQueueRef pointer that gets deleted. */ DPPL_API -void DPPLDeleteQueue (__dppl_take DPPLSyclQueueRef QRef); +void DPPLDeleteSyclQueue (__dppl_take DPPLSyclQueueRef QRef); DPPL_C_EXTERN_C_END diff --git a/backends/include/dppl_sycl_queue_manager.h b/backends/include/dppl_sycl_queue_manager.h new file mode 100644 index 0000000000..741cb51ad2 --- /dev/null +++ b/backends/include/dppl_sycl_queue_manager.h @@ -0,0 +1,151 @@ +//===--- dppl_sycl_queue_manager.h - DPPL-SYCL interface ---*---C++ ---*---===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This header declares a C interface to DPPL's sycl::queue manager to +/// maintain a thread local stack of sycl::queues objects for use inside +/// Python programs. The C interface is designed in a way to not have to +/// include the Sycl headers inside a Python extension module, since that would +/// require the extension to be compiled using dpc++ or another Sycl compiler. +/// Compiling the extension with a compiler different from what was used to +/// compile the Python interpreter can cause run-time problems especially on MS +/// Windows. Additionally, the C interface makes it easier to interoperate with +/// Numba without having to deal with C++ name mangling. +/// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "dppl_data_types.h" +#include "dppl_sycl_types.h" +#include "dppl_sycl_device_interface.h" +#include "Support/DllExport.h" +#include "Support/ExternC.h" +#include "Support/MemOwnershipAttrs.h" + +DPPL_C_EXTERN_C_BEGIN + +/*! + * @brief Get the number of sycl::platform available on the system. + * + * @return The number of available sycl::platforms. + */ +DPPL_API +size_t DPPLGetNumPlatforms (); + +/*! + * @brief Get the sycl::queue object that is currently activated for this + * thread. + * + * @return A copy of the current (top of the stack) sycl::queue is returned + * wrapped inside an opaque DPPLSyclQueueRef pointer. + */ +DPPL_API +__dppl_give DPPLSyclQueueRef DPPLGetCurrentQueue (); + +/*! + * @brief Get a sycl::queue object of the specified type and device id. + * + * @param DeviceTy The type of Sycl device (sycl_device_type) + * @param DNum Device id for the device (defaults to 0) + * + * @return A copy of the sycl::queue corresponding to the device is returned + * wrapped inside a DPPLSyclDeviceType pointer. A runtime_error exception is + * raised if no such device exists. + */ +DPPL_API +__dppl_give DPPLSyclQueueRef DPPLGetQueue (DPPLSyclDeviceType DeviceTy, + size_t DNum); + +/*! + * @brief Get the number of activated queues not including the global or + * default queue. + * + * @return The number of activated queues. + */ +DPPL_API +size_t DPPLGetNumActivatedQueues (); + +/*! + * @brief Get the number of GPU queues available on the system. + * + * @return The number of available GPU queues. + */ +DPPL_API +size_t DPPLGetNumGPUQueues (); + +/*! + * @brief Get the number of CPU queues available on the system. + * + * @return The number of available CPU queues. + */ +DPPL_API +size_t DPPLGetNumCPUQueues (); + +/*! +* @brief Set the default DPPL queue to the sycl::queue for the given device. +* +* If no such device is found the a runtime_error exception is thrown. +* +* @param DeviceTy The type of Sycl device (sycl_device_type) +* @param DNum Device id for the device (defaults to 0) +*/ +DPPL_API +void DPPLSetAsDefaultQueue (DPPLSyclDeviceType DeviceTy, + size_t DNum); + +/*! + * @brief Pushes a new sycl::queue object to the top of DPPL's thread-local + * stack of a "activated" queues, and returns a copy of the queue to caller. + * + * DPPL maintains a thread-local stack of sycl::queue objects to facilitate + * nested parallelism. The sycl::queue at the top of the stack is termed as the + * currently activated queue, and is always the one returned by + * DPPLGetCurrentQueue(). DPPLPushSyclQueueToStack creates a new sycl::queue + * corresponding to the specified device and pushes it to the top of the stack. + * A copy of the sycl::queue is returned to the caller wrapped inside the + * opaque DPPLSyclQueueRef pointer. A runtime_error exception is thrown when + * a new sycl::queue could not be created for the specified device. + * + * @param DeviceTy The type of Sycl device (sycl_device_type) + * @param DNum Device id for the device (defaults to 0) + * + * @return A copy of the sycl::queue that was pushed to the top of DPPL's + * stack of sycl::queue objects. + */ +DPPL_API +__dppl_give DPPLSyclQueueRef DPPLPushSyclQueue (DPPLSyclDeviceType DeviceTy, + size_t DNum); + +/*! + * @brief Pops the top of stack element from DPPL's stack of activated + * sycl::queue objects. + * + * DPPLPopSyclQueue only removes the reference from the DPPL stack of + * sycl::queue objects. Any instance of the popped queue that were previously + * acquired by calling DPPLPushSyclQueue() or DPPLGetCurrentQueue() needs to be + * freed separately. In addition, a runtime_error is thrown when the stack + * contains only one sycl::queue, i.e., the default queue. + * + */ +DPPL_API +void DPPLPopSyclQueue (); + +DPPL_C_EXTERN_C_END diff --git a/backends/include/dppl_sycl_types.h b/backends/include/dppl_sycl_types.h index ea3d6b479b..d1777aae5d 100644 --- a/backends/include/dppl_sycl_types.h +++ b/backends/include/dppl_sycl_types.h @@ -23,10 +23,35 @@ /// //===----------------------------------------------------------------------===// +#pragma once + +/*! + * @brief + * + */ +typedef struct DPPLOpaqueSyclContext *DPPLSyclContextRef; + +/*! + * @brief + * + */ +typedef struct DPPLOpaqueSyclDevice *DPPLSyclDeviceRef; + +/*! + * @brief + * + */ +typedef struct DPPLOpaqueSyclPlatform *DPPLSyclPlatformRef; /*! - * Used to pass a sycl::queue opaquely through DPPL interfaces. + * @brief Used to pass a sycl::queue opaquely through DPPL interfaces. * * @see sycl::queue */ typedef struct DPPLOpaqueSyclQueue *DPPLSyclQueueRef; + +/*! + * @brief Used to pass a sycl::program opaquely through DPPL interfaces. + * + */ +typedef struct DPPLOpaqueSyclProgram *DPPLSyclProgramRef; diff --git a/backends/include/error_check_macros.h b/backends/include/error_check_macros.h index 201a0f071a..77bd462e5a 100644 --- a/backends/include/error_check_macros.h +++ b/backends/include/error_check_macros.h @@ -23,6 +23,7 @@ /// codes. /// //===----------------------------------------------------------------------===// + #pragma once #include diff --git a/backends/source/dppl_sycl_context_interface.cpp b/backends/source/dppl_sycl_context_interface.cpp new file mode 100644 index 0000000000..d27b150f74 --- /dev/null +++ b/backends/source/dppl_sycl_context_interface.cpp @@ -0,0 +1,58 @@ +//===--- dppl_sycl_context_interface.cpp - DPPL-SYCL interface --*- C++ -*-===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This file implements the data types and functions declared in +/// dppl_sycl_context_interface.h. +/// +//===----------------------------------------------------------------------===// + +#include "dppl_sycl_context_interface.h" +#include "Support/CBindingWrapping.h" +#include + +using namespace cl::sycl; + +namespace +{ + // Create wrappers for C Binding types (see CBindingWrapping.h). + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(context, DPPLSyclContextRef) +} /* end of anonymous namespace */ + +/*! + * @brief + * + * @param CtxtRef My Param doc + * @return {return} My Param doc + */ +bool DPPLIsHostContext (__dppl_keep const DPPLSyclContextRef CtxtRef) +{ + return unwrap(CtxtRef)->is_host(); +} + +/*! + * @brief + * + * @param CtxtRef My Param doc + */ +void DPPLDeleteSyclContext (__dppl_take DPPLSyclContextRef CtxtRef) +{ + delete unwrap(CtxtRef); +} diff --git a/backends/source/dppl_sycl_device_interface.cpp b/backends/source/dppl_sycl_device_interface.cpp new file mode 100644 index 0000000000..4efcf40580 --- /dev/null +++ b/backends/source/dppl_sycl_device_interface.cpp @@ -0,0 +1,147 @@ +//===--- dppl_sycl_device_interface.cpp - DPPL-SYCL interface --*- C++ -*--===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This file implements the data types and functions declared in +/// dppl_sycl_device_interface.h. +/// +//===----------------------------------------------------------------------===// + +#include "dppl_sycl_device_interface.h" +#include "Support/CBindingWrapping.h" +#include +#include +#include /* SYCL headers */ + +using namespace cl::sycl; + +namespace +{ +// Create wrappers for C Binding types (see CBindingWrapping.h). + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(device, DPPLSyclDeviceRef) + + /*! + * @brief + * + * @param Device My Param doc + */ +void dump_device_info (const device & Device) +{ + std::stringstream ss; + + ss << std::setw(4) << " " << std::left << std::setw(16) << "Name" + << Device.get_info() << '\n'; + ss << std::setw(4) << " " << std::left << std::setw(16) << "Driver version" + << Device.get_info() << '\n'; + ss << std::setw(4) << " " << std::left << std::setw(16) << "Vendor" + << Device.get_info() << '\n'; + ss << std::setw(4) << " " << std::left << std::setw(16) << "Profile" + << Device.get_info() << '\n'; + + std::cout << ss.str(); +} + +} /* end of anonymous namespace */ + +/*! + * Prints some of the device info metadata for the device corresponding to the + * specified sycl::queue. Currently, device name, driver version, device + * vendor, and device profile are printed out. More attributed may be added + * later. + */ +void DPPLDumpDeviceInfo (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + auto Device = unwrap(DRef); + dump_device_info(*Device); +} + + +void DPPLDeleteSyclDevice (__dppl_take DPPLSyclDeviceRef DRef) +{ + delete unwrap(DRef); +} + +bool DPPLDeviceIsAccelerator (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + return unwrap(DRef)->is_accelerator(); +} + +bool DPPLDeviceIsCPU (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + return unwrap(DRef)->is_cpu(); +} + +bool DPPLDeviceIsGPU (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + return unwrap(DRef)->is_gpu(); +} + + +bool DPPLDeviceIsHost (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + return unwrap(DRef)->is_host(); +} + +__dppl_give const char* +DPPLGetDeviceName (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + auto name = unwrap(DRef)->get_info(); + auto cstr_name = new char [name.length()+1]; + std::strcpy (cstr_name, name.c_str()); + return cstr_name; +} + +void DPPLDeleteDeviceName (__dppl_take const char *DeviceName) +{ + delete DeviceName; +} + +__dppl_give const char* +DPPLGetDeviceVendorName (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + auto vendor = unwrap(DRef)->get_info(); + auto cstr_vendor = new char [vendor.length()+1]; + std::strcpy (cstr_vendor, vendor.c_str()); + return cstr_vendor; +} + +void DPPLDeleteDeviceVendorName (__dppl_take const char *VendorName) +{ + delete VendorName; +} + +__dppl_give const char* +DPPLGetDeviceDriverInfo (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + auto driver = unwrap(DRef)->get_info(); + auto cstr_driver = new char [driver.length()+1]; + std::strcpy (cstr_driver, driver.c_str()); + return cstr_driver; +} + +void DPPLDeleteDeviceDriverInfo (__dppl_take const char *DriverInfo) +{ + delete DriverInfo; +} + +bool DPPLGetDeviceHostUnifiedMemory (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + return unwrap(DRef)->get_info(); +} diff --git a/backends/source/dppl_sycl_queue_interface.cpp b/backends/source/dppl_sycl_queue_interface.cpp index cf215c6795..2dad78b604 100644 --- a/backends/source/dppl_sycl_queue_interface.cpp +++ b/backends/source/dppl_sycl_queue_interface.cpp @@ -20,53 +20,25 @@ /// /// \file /// This file implements the data types and functions declared in -/// dppl_sycl_queue_interface.hpp. +/// dppl_sycl_queue_interface.h. /// //===----------------------------------------------------------------------===// + #include "dppl_sycl_queue_interface.h" #include "Support/CBindingWrapping.h" -#include -#include #include #include #include -#include -#include #include /* SYCL headers */ using namespace cl::sycl; -/*------------------------------- Private helpers ----------------------------*/ - -// Anonymous namespace for private helpers namespace { - - // Create wrappers for C Binding types (see CBindingWrapping.h). +// Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) -/*! - * @brief - * - * @param Device My Param doc - */ -void dump_device_info (const device & Device) -{ - std::stringstream ss; - - ss << std::setw(4) << " " << std::left << std::setw(16) << "Name" - << Device.get_info() << '\n'; - ss << std::setw(4) << " " << std::left << std::setw(16) << "Driver version" - << Device.get_info() << '\n'; - ss << std::setw(4) << " " << std::left << std::setw(16) << "Vendor" - << Device.get_info() << '\n'; - ss << std::setw(4) << " " << std::left << std::setw(16) << "Profile" - << Device.get_info() << '\n'; - - std::cout << ss.str(); -} - /*! * @brief * @@ -88,257 +60,8 @@ void dump_platform_info (const platform & Platform) std::cout << ss.str(); } -void error_reporter (const std::string & msg) -{ - throw std::runtime_error("Error: " + msg); -} - -/*! - * @brief A helper class to support the DPPLSyclQueuemanager. - * - * The QMgrHelper is needed so that sycl headers are not exposed at the - * top-level DPPL API. - * - */ -class QMgrHelper -{ -public: - static std::vector& - cpu_queues_ () - { - static std::vector* cpu_queues = - QMgrHelper::init_queues(info::device_type::cpu); - return *cpu_queues; - } - - static std::vector& - gpu_queues_ () - { - static std::vector* gpu_queues = - QMgrHelper::init_queues(info::device_type::gpu); - return *gpu_queues; - } - - static std::vector& - active_queues_ () - { - thread_local static std::vector* active_queues = - new std::vector({default_selector()}); - return *active_queues; - } - - static __dppl_give DPPLSyclQueueRef - getQueue (DPPLSyclDeviceType DeviceTy, size_t DNum); - - static __dppl_give DPPLSyclQueueRef - getCurrentQueue (); - - static void - setAsDefaultQueue (DPPLSyclDeviceType DeviceTy, size_t DNum); - - static __dppl_give DPPLSyclQueueRef - pushSyclQueue (DPPLSyclDeviceType DeviceTy, size_t DNum); - - static void - popSyclQueue (); - - static cl::sycl::vector_class* - init_queues (info::device_type device_ty) - { - auto queues = new std::vector(); - for(auto d : device::get_devices(device_ty)) - queues->emplace_back(d); - return queues; - } -}; - -// make function call like access to variable -// it is for minimizing code changes during replacing static vars with functions -// it could be refactored by replacing variable with function call -// scope of this variables is only this file -#define cpu_queues cpu_queues_() -#define gpu_queues gpu_queues_() -#define active_queues active_queues_() - -/*! - * Allocates a new copy of the present top of stack queue, which can be the - * default queue and returns to caller. The caller owns the pointer and is - * responsible for deallocating it. The helper function deleteQueue can be used - * is for that purpose. - */ -DPPLSyclQueueRef QMgrHelper::getCurrentQueue () -{ - if(active_queues.empty()) - error_reporter("No currently active queues."); - auto last = QMgrHelper::active_queues.size() - 1; - return wrap(new queue(QMgrHelper::active_queues[last])); -} - -/*! - * Allocates a sycl::queue by copying from the cached {cpu|gpu}_queues vector - * and returns it to the caller. The caller owns the pointer and is responsible - * for deallocating it. The helper function deleteQueue can be used is for that - * purpose. - */ -DPPLSyclQueueRef -QMgrHelper::getQueue (DPPLSyclDeviceType DeviceTy, - size_t DNum) -{ - queue *QRef = nullptr; - - switch (DeviceTy) - { - case DPPLSyclDeviceType::DPPL_CPU: - { - if (DNum >= cpu_queues.size()) { - std::stringstream ss; - ss << "SYCL CPU device " << DNum << " not found on system."; - error_reporter(ss.str()); - } - QRef = new queue(QMgrHelper::cpu_queues[DNum]); - break; - } - case DPPLSyclDeviceType::DPPL_GPU: - { - if (DNum >= gpu_queues.size()) { - std::stringstream ss; - ss << "SYCL GPU device " << DNum << " not found on system."; - error_reporter(ss.str()); - } - QRef = new queue(QMgrHelper::gpu_queues[DNum]); - break; - } - default: - error_reporter("Unsupported device type."); - } - - return wrap(QRef); -} - -/*! - * Changes the first entry into the stack, i.e., the default queue to a new - * sycl::queue corresponding to the device type and device number. - */ -void -QMgrHelper::setAsDefaultQueue (DPPLSyclDeviceType DeviceTy, size_t DNum) -{ - if(active_queues.empty()) - error_reporter("active queue vector is corrupted."); - - switch (DeviceTy) - { - case DPPLSyclDeviceType::DPPL_CPU: - { - if (DNum >= cpu_queues.size()) { - std::stringstream ss; - ss << "SYCL CPU device " << DNum << " not found on system."; - error_reporter(ss.str()); - } - active_queues[0] = cpu_queues[DNum]; - break; - } - case DPPLSyclDeviceType::DPPL_GPU: - { - if (DNum >= gpu_queues.size()) { - std::stringstream ss; - ss << "SYCL GPU device " << DNum << " not found on system."; - error_reporter(ss.str()); - } - active_queues[0] = gpu_queues[DNum]; - break; - } - default: - { - error_reporter("Unsupported device type."); - } - } -} - -/*! - * Allocates a new sycl::queue by copying from the cached {cpu|gpu}_queues - * vector. The pointer returned is now owned by the caller and must be properly - * cleaned up. The helper function DPPLDeleteQueue() can be used is for that - * purpose. - */ -DPPLSyclQueueRef -QMgrHelper::pushSyclQueue (DPPLSyclDeviceType DeviceTy, size_t DNum) -{ - queue *QRef = nullptr; - if(active_queues.empty()) - error_reporter("Why is there no previous global context?"); - - switch (DeviceTy) - { - case DPPLSyclDeviceType::DPPL_CPU: - { - if (DNum >= cpu_queues.size()) { - std::stringstream ss; - ss << "SYCL CPU device " << DNum << " not found on system."; - error_reporter(ss.str()); - } - active_queues.emplace_back(cpu_queues[DNum]); - QRef = new queue(active_queues[active_queues.size()-1]); - break; - } - case DPPLSyclDeviceType::DPPL_GPU: - { - if (DNum >= gpu_queues.size()) { - std::stringstream ss; - ss << "SYCL GPU device " << DNum << " not found on system."; - error_reporter(ss.str()); - } - active_queues.emplace_back(gpu_queues[DNum]); - QRef = new queue(active_queues[active_queues.size()-1]); - break; - } - default: - { - error_reporter("Unsupported device type."); - } - } - - return wrap(QRef); -} - -/*! - * If there were any sycl::queue that were activated and added to the stack of - * activated queues then the top of the stack entry is popped. Note that since - * the same std::vector is used to keep track of the activated queues and the - * global queue a popSyclQueue call can never make the stack empty. Even - * after all activated queues are popped, the global queue is still available as - * the first element added to the stack. - */ -void -QMgrHelper::popSyclQueue () -{ - // The first queue which is the "default" queue can not be removed. - if(active_queues.size() <= 1 ) - error_reporter("No active contexts"); - active_queues.pop_back(); -} - } /* end of anonymous namespace */ -/*! - * Delete the passed in pointer after verifying it points to a sycl::queue. - */ -void DPPLDeleteQueue (__dppl_take DPPLSyclQueueRef QRef) -{ - delete unwrap(QRef); -} - -/*! - * Prints some of the device info metadata for the device corresponding to the - * specified sycl::queue. Currently, device name, driver version, device - * vendor, and device profile are printed out. More attributed may be added - * later. - */ -void DPPLDumpDeviceInfo (__dppl_keep const DPPLSyclQueueRef QRef) -{ - auto Q = unwrap(QRef); - dump_device_info(Q->get_device()); -} - /*! * Prints out number of available SYCL platforms, number of CPU queues, number * of GPU queues, metadata about the current global queue, and how many queues @@ -359,106 +82,28 @@ void DPPLDumpPlatformInfo () dump_platform_info(p); ++i; } - - // Print out the info for CPU devices - if (QMgrHelper::cpu_queues.size()) - std::cout << "---Number of available SYCL CPU queues: " - << QMgrHelper::cpu_queues.size() << '\n'; - else - std::cout << "---No available SYCL CPU device\n"; - - // Print out the info for GPU devices - if (QMgrHelper::gpu_queues.size()) - std::cout << "---Number of available SYCL GPU queues: " - << QMgrHelper::gpu_queues.size() << '\n'; - else - std::cout << "---No available SYCL GPU device\n"; - - std::cout << "---Current queue :\n"; - DPPLDumpDeviceInfo(wrap(&QMgrHelper::active_queues[0])); - - std::cout << "---Number of active queues : " - << QMgrHelper::active_queues.size() - << '\n'; -} - -/*! - * Returns the number of sycl::platform on the system. - */ -size_t DPPLGetNumPlatforms () -{ - return platform::get_platforms().size(); } -/*! - * Returns inside the number of activated queues not including the global queue - * (QMgrHelper::active_queues[0]). - */ -size_t DPPLGetNumActivatedQueues () -{ - if (QMgrHelper::active_queues.empty()) - error_reporter("No active contexts"); - return QMgrHelper::active_queues.size() - 1; -} - -/*! - * Returns the number of CPU queues. - */ -size_t DPPLGetNumCPUQueues () -{ - return QMgrHelper::cpu_queues.size(); -} - -/*! - * Returns the number of GPU queues. - */ -size_t DPPLGetNumGPUQueues () -{ - return QMgrHelper::gpu_queues.size(); -} - -/*! - * \see QMgrHelper::getCurrentQueue() - */ -DPPLSyclQueueRef DPPLGetCurrentQueue () +__dppl_give DPPLSyclDeviceRef +DPPLGetDeviceFromQueue (__dppl_keep const DPPLSyclQueueRef QRef) { - return QMgrHelper::getCurrentQueue(); -} - -/*! - * Returns a copy of a sycl::queue corresponding to the specified device type - * and device number. A runtime_error gets thrown if no such device exists. - */ -DPPLSyclQueueRef DPPLGetQueue (DPPLSyclDeviceType DeviceTy, - size_t DNum) -{ - return QMgrHelper::getQueue(DeviceTy, DNum); -} - -/*! - * The function sets the global queue, i.e., the sycl::queue object at - * QMgrHelper::active_queues[0] vector to the sycl::queue corresponding to the - * specified device type and id. A runtime_error gets thrown if no such device - * exists. - */ -void DPPLSetAsDefaultQueue (DPPLSyclDeviceType DeviceTy, size_t DNum) -{ - QMgrHelper::setAsDefaultQueue(DeviceTy, DNum); + auto Q = unwrap(QRef); + auto Device = new device(Q->get_device()); + return reinterpret_cast(Device); } -/*! - * \see QMgrHelper::pushSyclQueue() - */ -__dppl_give DPPLSyclQueueRef DPPLPushSyclQueue (DPPLSyclDeviceType DeviceTy, - size_t DNum) +__dppl_give DPPLSyclContextRef +DPPLGetContextFromQueue (__dppl_keep const DPPLSyclQueueRef QRef) { - return QMgrHelper::pushSyclQueue(DeviceTy, DNum); + auto Q = unwrap(QRef); + auto Context = new context(Q->get_context()); + return reinterpret_cast(Context); } /*! - * \see QMgrHelper::popSyclQueue() + * Delete the passed in pointer after verifying it points to a sycl::queue. */ -void DPPLPopSyclQueue () +void DPPLDeleteSyclQueue (__dppl_take DPPLSyclQueueRef QRef) { - QMgrHelper::popSyclQueue(); + delete unwrap(QRef); } diff --git a/backends/source/dppl_sycl_queue_manager.cpp b/backends/source/dppl_sycl_queue_manager.cpp new file mode 100644 index 0000000000..e6e4485942 --- /dev/null +++ b/backends/source/dppl_sycl_queue_manager.cpp @@ -0,0 +1,366 @@ +//===--- dppl_sycl_queue_manager.cpp - DPPL-SYCL interface --*- C++ -*---===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This file implements the data types and functions declared in +/// dppl_sycl_queue_manager.h. +/// +//===----------------------------------------------------------------------===// +#include "dppl_sycl_queue_manager.h" +#include "Support/CBindingWrapping.h" +#include +#include +#include + +#include /* SYCL headers */ + +using namespace cl::sycl; + +/*------------------------------- Private helpers ----------------------------*/ + +// Anonymous namespace for private helpers +namespace +{ + + // Create wrappers for C Binding types (see CBindingWrapping.h). + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) + +void error_reporter (const std::string & msg) +{ + throw std::runtime_error("Error: " + msg); +} + +/*! + * @brief A helper class to support the DPPLSyclQueuemanager. + * + * The QMgrHelper is needed so that sycl headers are not exposed at the + * top-level DPPL API. + * + */ +class QMgrHelper +{ +public: + static std::vector& + cpu_queues_ () + { + static std::vector* cpu_queues = + QMgrHelper::init_queues(info::device_type::cpu); + return *cpu_queues; + } + + static std::vector& + gpu_queues_ () + { + static std::vector* gpu_queues = + QMgrHelper::init_queues(info::device_type::gpu); + return *gpu_queues; + } + + static std::vector& + active_queues_ () + { + thread_local static std::vector* active_queues = + new std::vector({default_selector()}); + return *active_queues; + } + + static __dppl_give DPPLSyclQueueRef + getQueue (DPPLSyclDeviceType DeviceTy, size_t DNum); + + static __dppl_give DPPLSyclQueueRef + getCurrentQueue (); + + static void + setAsDefaultQueue (DPPLSyclDeviceType DeviceTy, size_t DNum); + + static __dppl_give DPPLSyclQueueRef + pushSyclQueue (DPPLSyclDeviceType DeviceTy, size_t DNum); + + static void + popSyclQueue (); + + static cl::sycl::vector_class* + init_queues (info::device_type device_ty) + { + auto queues = new std::vector(); + for(auto d : device::get_devices(device_ty)) + queues->emplace_back(d); + return queues; + } +}; + +// make function call like access to variable +// it is for minimizing code changes during replacing static vars with functions +// it could be refactored by replacing variable with function call +// scope of this variables is only this file +#define cpu_queues cpu_queues_() +#define gpu_queues gpu_queues_() +#define active_queues active_queues_() + + +//----------------------------- Public API -----------------------------------// + +/*! + * Returns the number of sycl::platform on the system. + */ +size_t DPPLGetNumPlatforms () +{ + return platform::get_platforms().size(); +} + +/*! + * Allocates a new copy of the present top of stack queue, which can be the + * default queue and returns to caller. The caller owns the pointer and is + * responsible for deallocating it. The helper function deleteQueue can be used + * is for that purpose. + */ +DPPLSyclQueueRef QMgrHelper::getCurrentQueue () +{ + if(active_queues.empty()) + error_reporter("No currently active queues."); + auto last = QMgrHelper::active_queues.size() - 1; + return wrap(new queue(QMgrHelper::active_queues[last])); +} + +/*! + * Allocates a sycl::queue by copying from the cached {cpu|gpu}_queues vector + * and returns it to the caller. The caller owns the pointer and is responsible + * for deallocating it. The helper function deleteQueue can be used is for that + * purpose. + */ +DPPLSyclQueueRef +QMgrHelper::getQueue (DPPLSyclDeviceType DeviceTy, + size_t DNum) +{ + queue *QRef = nullptr; + + switch (DeviceTy) + { + case DPPLSyclDeviceType::DPPL_CPU: + { + if (DNum >= cpu_queues.size()) { + std::stringstream ss; + ss << "SYCL CPU device " << DNum << " not found on system."; + error_reporter(ss.str()); + } + QRef = new queue(QMgrHelper::cpu_queues[DNum]); + break; + } + case DPPLSyclDeviceType::DPPL_GPU: + { + if (DNum >= gpu_queues.size()) { + std::stringstream ss; + ss << "SYCL GPU device " << DNum << " not found on system."; + error_reporter(ss.str()); + } + QRef = new queue(QMgrHelper::gpu_queues[DNum]); + break; + } + default: + error_reporter("Unsupported device type."); + } + + return wrap(QRef); +} + +/*! + * Changes the first entry into the stack, i.e., the default queue to a new + * sycl::queue corresponding to the device type and device number. + */ +void +QMgrHelper::setAsDefaultQueue (DPPLSyclDeviceType DeviceTy, size_t DNum) +{ + if(active_queues.empty()) + error_reporter("active queue vector is corrupted."); + + switch (DeviceTy) + { + case DPPLSyclDeviceType::DPPL_CPU: + { + if (DNum >= cpu_queues.size()) { + std::stringstream ss; + ss << "SYCL CPU device " << DNum << " not found on system."; + error_reporter(ss.str()); + } + active_queues[0] = cpu_queues[DNum]; + break; + } + case DPPLSyclDeviceType::DPPL_GPU: + { + if (DNum >= gpu_queues.size()) { + std::stringstream ss; + ss << "SYCL GPU device " << DNum << " not found on system."; + error_reporter(ss.str()); + } + active_queues[0] = gpu_queues[DNum]; + break; + } + default: + { + error_reporter("Unsupported device type."); + } + } +} + +/*! + * Allocates a new sycl::queue by copying from the cached {cpu|gpu}_queues + * vector. The pointer returned is now owned by the caller and must be properly + * cleaned up. The helper function DPPLDeleteSyclQueue() can be used is for that + * purpose. + */ +DPPLSyclQueueRef +QMgrHelper::pushSyclQueue (DPPLSyclDeviceType DeviceTy, size_t DNum) +{ + queue *QRef = nullptr; + if(active_queues.empty()) + error_reporter("Why is there no previous global context?"); + + switch (DeviceTy) + { + case DPPLSyclDeviceType::DPPL_CPU: + { + if (DNum >= cpu_queues.size()) { + std::stringstream ss; + ss << "SYCL CPU device " << DNum << " not found on system."; + error_reporter(ss.str()); + } + active_queues.emplace_back(cpu_queues[DNum]); + QRef = new queue(active_queues[active_queues.size()-1]); + break; + } + case DPPLSyclDeviceType::DPPL_GPU: + { + if (DNum >= gpu_queues.size()) { + std::stringstream ss; + ss << "SYCL GPU device " << DNum << " not found on system."; + error_reporter(ss.str()); + } + active_queues.emplace_back(gpu_queues[DNum]); + QRef = new queue(active_queues[active_queues.size()-1]); + break; + } + default: + { + error_reporter("Unsupported device type."); + } + } + + return wrap(QRef); +} + +/*! + * If there were any sycl::queue that were activated and added to the stack of + * activated queues then the top of the stack entry is popped. Note that since + * the same std::vector is used to keep track of the activated queues and the + * global queue a popSyclQueue call can never make the stack empty. Even + * after all activated queues are popped, the global queue is still available as + * the first element added to the stack. + */ +void +QMgrHelper::popSyclQueue () +{ + // The first queue which is the "default" queue can not be removed. + if(active_queues.size() <= 1 ) + error_reporter("No active contexts"); + active_queues.pop_back(); +} + +} /* end of anonymous namespace */ + +/*! + * Returns the number of sycl::platform on the system. + */ +size_t DPPLGetNumPlatforms () +{ + return platform::get_platforms().size(); +} + +/*! + * Returns inside the number of activated queues not including the global queue + * (QMgrHelper::active_queues[0]). + */ +size_t DPPLGetNumActivatedQueues () +{ + if (QMgrHelper::active_queues.empty()) + error_reporter("No active contexts"); + return QMgrHelper::active_queues.size() - 1; +} + +/*! + * Returns the number of CPU queues. + */ +size_t DPPLGetNumCPUQueues () +{ + return QMgrHelper::cpu_queues.size(); +} + +/*! + * Returns the number of GPU queues. + */ +size_t DPPLGetNumGPUQueues () +{ + return QMgrHelper::gpu_queues.size(); +} + +/*! + * \see QMgrHelper::getCurrentQueue() + */ +DPPLSyclQueueRef DPPLGetCurrentQueue () +{ + return QMgrHelper::getCurrentQueue(); +} + +/*! + * Returns a copy of a sycl::queue corresponding to the specified device type + * and device number. A runtime_error gets thrown if no such device exists. + */ +DPPLSyclQueueRef DPPLGetQueue (DPPLSyclDeviceType DeviceTy, + size_t DNum) +{ + return QMgrHelper::getQueue(DeviceTy, DNum); +} + +/*! + * The function sets the global queue, i.e., the sycl::queue object at + * QMgrHelper::active_queues[0] vector to the sycl::queue corresponding to the + * specified device type and id. A runtime_error gets thrown if no such device + * exists. + */ +void DPPLSetAsDefaultQueue (DPPLSyclDeviceType DeviceTy, size_t DNum) +{ + QMgrHelper::setAsDefaultQueue(DeviceTy, DNum); +} + +/*! + * \see QMgrHelper::pushSyclQueue() + */ +__dppl_give DPPLSyclQueueRef DPPLPushSyclQueue (DPPLSyclDeviceType DeviceTy, + size_t DNum) +{ + return QMgrHelper::pushSyclQueue(DeviceTy, DNum); +} + +/*! + * \see QMgrHelper::popSyclQueue() + */ +void DPPLPopSyclQueue () +{ + QMgrHelper::popSyclQueue(); +} diff --git a/backends/tests/CMakeLists.txt b/backends/tests/CMakeLists.txt index b2558f4fab..e83f408f05 100644 --- a/backends/tests/CMakeLists.txt +++ b/backends/tests/CMakeLists.txt @@ -11,7 +11,7 @@ else() # We need thread support for gtest find_package(Threads REQUIRED) - set(CMAKE_CTEST_COMMAND ctest -V) + set(CMAKE_CTEST_COMMAND ctest -V) # Emulate autotools like make check target to build tests add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) diff --git a/backends/tests/test_sycl_queue_manager.cpp b/backends/tests/test_sycl_queue_manager.cpp index a64d06cdab..8ca98aa66a 100644 --- a/backends/tests/test_sycl_queue_manager.cpp +++ b/backends/tests/test_sycl_queue_manager.cpp @@ -1,6 +1,32 @@ +//===--- test_sycl_queue_manager.cpp - DPPL-SYCL interface --*- C++ ---*---===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This file has unit test cases for functions defined in +/// dppl_sycl_queue_interface.h. +/// +//===----------------------------------------------------------------------===// +#include "dppl_sycl_device_interface.h" +#include "dppl_sycl_queue_manager.h" #include "dppl_sycl_queue_interface.h" #include -#include #include using namespace std; @@ -15,8 +41,8 @@ namespace num = DPPLGetNumActivatedQueues(); DPPLPopSyclQueue(); DPPLPopSyclQueue(); - DPPLDeleteQueue(q1); - DPPLDeleteQueue(q2); + DPPLDeleteSyclQueue(q1); + DPPLDeleteSyclQueue(q2); } void bar (size_t & num) @@ -25,7 +51,7 @@ namespace // Capture the number of active queues in second num = DPPLGetNumActivatedQueues(); DPPLPopSyclQueue(); - DPPLDeleteQueue(q1); + DPPLDeleteSyclQueue(q1); } } @@ -102,7 +128,7 @@ TEST_F (TestDPPLSyclQueuemanager, CheckGetNumActivatedQueues) EXPECT_EQ(num2, 1); EXPECT_EQ(num4, 0); - DPPLDeleteQueue(q); + DPPLDeleteSyclQueue(q); } @@ -115,8 +141,8 @@ TEST_F (TestDPPLSyclQueuemanager, CheckDPPLDumpPlatformInfo) TEST_F (TestDPPLSyclQueuemanager, CheckDPPLDumpDeviceInfo) { auto q = DPPLGetCurrentQueue(); - EXPECT_NO_FATAL_FAILURE(DPPLDumpDeviceInfo(q)); - EXPECT_NO_FATAL_FAILURE(DPPLDeleteQueue(q)); + EXPECT_NO_FATAL_FAILURE(DPPLDumpDeviceInfo(DPPLGetDeviceFromQueue(q))); + EXPECT_NO_FATAL_FAILURE(DPPLDeleteSyclQueue(q)); } diff --git a/dppl/sycl_core.pyx b/dppl/sycl_core.pyx index 2a8a5cd840..f167cc3cdf 100644 --- a/dppl/sycl_core.pyx +++ b/dppl/sycl_core.pyx @@ -27,11 +27,9 @@ # cython: language_level=3 from __future__ import print_function -from cpython.pycapsule cimport (PyCapsule_New, - PyCapsule_IsValid, - PyCapsule_GetPointer) from enum import Enum, auto import logging +from libcpp cimport bool _logger = logging.getLogger(__name__) @@ -46,20 +44,56 @@ cdef class UnsupportedDeviceTypeError(Exception): ''' pass -cdef extern from "dppl_sycl_types.h": +cdef extern from "dppl_sycl_types.h": + cdef struct DPPLOpaqueSyclContext: + pass cdef struct DPPLOpaqueSyclQueue: pass + cdef struct DPPLOpaqueSyclDevice: + pass + + ctypedef DPPLOpaqueSyclContext* DPPLSyclContextRef ctypedef DPPLOpaqueSyclQueue* DPPLSyclQueueRef + ctypedef DPPLOpaqueSyclDevice* DPPLSyclDeviceRef + +cdef extern from "dppl_sycl_context_interface.h": + cdef void DPPLDeleteSyclContext (DPPLSyclContextRef CtxtRef) except + -cdef extern from "dppl_sycl_queue_interface.h": +cdef extern from "dppl_sycl_queue_interface.h": + cdef void DPPLDeleteSyclQueue (DPPLSyclQueueRef QRef) except + + cdef void DPPLDumpPlatformInfo () except + + cdef DPPLSyclContextRef DPPLGetContextFromQueue (const DPPLSyclQueueRef Q) \ + except+ + cdef DPPLSyclDeviceRef DPPLGetDeviceFromQueue (const DPPLSyclQueueRef Q) \ + except + + + +cdef extern from "dppl_sycl_device_interface.h": + cdef void DPPLDumpDeviceInfo (const DPPLSyclDeviceRef DRef) except + + cdef void DPPLDeleteSyclDevice (DPPLSyclDeviceRef DRef) except + + cdef void DPPLDumpDeviceInfo (const DPPLSyclDeviceRef DRef) except + + cdef bool DPPLDeviceIsAccelerator (const DPPLSyclDeviceRef DRef) except + + cdef bool DPPLDeviceIsCPU (const DPPLSyclDeviceRef DRef) except + + cdef bool DPPLDeviceIsGPU (const DPPLSyclDeviceRef DRef) except + + cdef bool DPPLDeviceIsHost (const DPPLSyclDeviceRef DRef) except + + cdef const char* DPPLGetDeviceDriverInfo (const DPPLSyclDeviceRef DRef) \ + except + + cdef const char* DPPLGetDeviceName (const DPPLSyclDeviceRef DRef) except + + cdef const char* DPPLGetDeviceVendorName (const DPPLSyclDeviceRef DRef) \ + except + + cdef bool DPPLGetDeviceHostUnifiedMemory (const DPPLSyclDeviceRef DRef) \ + except + + cdef void DPPLDeleteDeviceName (const char *DeviceName) except + + cdef void DPPLDeleteDeviceVendorName (const char *VendorName) except + + cdef void DPPLDeleteDeviceDriverInfo (const char *DriverInfo) except + + +cdef extern from "dppl_sycl_queue_manager.h": cdef enum _device_type 'DPPLSyclDeviceType': _GPU 'DPPL_GPU' _CPU 'DPPL_CPU' - cdef void DPPLDumpPlatformInfo () except + - cdef void DPPLDumpDeviceInfo (const DPPLSyclQueueRef Q) except + cdef DPPLSyclQueueRef DPPLGetCurrentQueue () except + cdef size_t DPPLGetNumCPUQueues () except + cdef size_t DPPLGetNumGPUQueues () except + @@ -72,15 +106,101 @@ cdef extern from "dppl_sycl_queue_interface.h": size_t device_num) except + cdef void DPPLSetAsDefaultQueue (_device_type DTy, size_t device_num) except + - cdef void DPPLDeleteQueue (DPPLSyclQueueRef Q) except + -# Destructor for a PyCapsule containing a SYCL queue -cdef void delete_queue (object cap): - DPPLDeleteQueue(PyCapsule_GetPointer(cap, NULL)) +cdef class SyclContext: + cdef DPPLSyclContextRef ctxt_ptr -cdef class _SyclQueueManager: + @staticmethod + cdef SyclContext _create (DPPLSyclContextRef ctxt): + cdef SyclContext ret = SyclContext.__new__(SyclContext) + ret.ctxt_ptr = ctxt + return ret + + def __dealloc__ (self): + DPPLDeleteSyclContext(self.ctxt_ptr) + + cdef DPPLSyclContextRef get_context_ref (self): + return self.ctxt_ptr + + +cdef class SyclDevice: + ''' Wrapper class for a Sycl Device + ''' + cdef DPPLSyclDeviceRef device_ptr + cdef const char *vendor_name + cdef const char *device_name + cdef const char *driver_version + + @staticmethod + cdef SyclDevice _create (DPPLSyclDeviceRef dref): + cdef SyclDevice ret = SyclDevice.__new__(SyclDevice) + ret.device_ptr = dref + ret.vendor_name = DPPLGetDeviceVendorName(dref) + ret.device_name = DPPLGetDeviceName(dref) + ret.driver_version = DPPLGetDeviceDriverInfo(dref) + return ret + + def __dealloc__ (self): + DPPLDeleteSyclDevice(self.device_ptr) + DPPLDeleteDeviceName(self.device_name) + DPPLDeleteDeviceVendorName(self.vendor_name) + DPPLDeleteDeviceDriverInfo(self.driver_version) + + def dump_device_info (self): + ''' Print information about the SYCL device. + ''' + DPPLDumpDeviceInfo(self.device_ptr) + def get_device_name (self): + ''' Returns the name of the device as a string + ''' + return self.device_name + + def get_vendor_name (self): + ''' Returns the device vendor name as a string + ''' + return self.vendor_name + + def get_driver_version (self): + ''' Returns the OpenCL software driver version as a string + in the form: major number.minor number, if this SYCL + device is an OpenCL device. Returns a string class + with the value "1.2" if this SYCL device is a host device. + ''' + return self.driver_version + + cdef DPPLSyclDeviceRef get_device_ptr (self): + ''' Returns the DPPLSyclDeviceRef pointer for this class. + ''' + return self.device_ptr + + +cdef class SyclQueue: + ''' Wrapper class for a Sycl queue. + ''' + cdef DPPLSyclQueueRef queue_ptr + + @staticmethod + cdef SyclQueue _create (DPPLSyclQueueRef qref): + cdef SyclQueue ret = SyclQueue.__new__(SyclQueue) + ret.queue_ptr = qref + return ret + + def __dealloc__ (self): + DPPLDeleteSyclQueue(self.queue_ptr) + + cpdef get_sycl_context (self): + return SyclContext._create(DPPLGetContextFromQueue(self.queue_ptr)) + + cpdef get_sycl_device (self): + return SyclDevice._create(DPPLGetDeviceFromQueue(self.queue_ptr)) + + cdef DPPLSyclQueueRef get_queue_ref (self): + return self.queue_ptr + + +cdef class _SyclQueueManager: def _set_as_current_queue (self, device_ty, device_id): cdef DPPLSyclQueueRef queue_ptr if device_ty == device_type.gpu: @@ -91,12 +211,11 @@ cdef class _SyclQueueManager: e = UnsupportedDeviceTypeError("Device can only be cpu or gpu") raise e - return PyCapsule_New(queue_ptr, NULL, &delete_queue) + return SyclQueue._create(queue_ptr) def _remove_current_queue (self): DPPLPopSyclQueue() - def has_sycl_platforms (self): cdef size_t num_platforms = DPPLGetNumPlatforms() if num_platforms: @@ -117,8 +236,7 @@ cdef class _SyclQueueManager: def get_current_queue (self): ''' Returns the activated SYCL queue as a PyCapsule. ''' - cdef DPPLSyclQueueRef queue_ptr = DPPLGetCurrentQueue() - return PyCapsule_New(queue_ptr, NULL, &delete_queue) + return SyclQueue._create(DPPLGetCurrentQueue()) def set_default_queue (self, device_ty, device_id): if device_ty == device_type.gpu: @@ -148,16 +266,6 @@ cdef class _SyclQueueManager: ''' DPPLDumpPlatformInfo() - def dump_device_info (self, queue_cap): - ''' Prints information about the SYCL queue object. - ''' - if PyCapsule_IsValid(queue_cap, NULL): - DPPLDumpDeviceInfo( - PyCapsule_GetPointer(queue_cap, NULL) - ) - else: - raise ValueError("Expected a PyCapsule encapsulating a SYCL queue") - def is_in_dppl_ctxt (self): cdef size_t num = DPPLGetNumActivatedQueues() if num: @@ -171,7 +279,6 @@ _qmgr = _SyclQueueManager() # Global bound functions dump = _qmgr.dump -dump_device_info = _qmgr.dump_device_info get_current_queue = _qmgr.get_current_queue get_num_platforms = _qmgr.get_num_platforms get_num_activated_queues = _qmgr.get_num_activated_queues diff --git a/dppl/tests/dppl_tests/test_sycl_queue_manager.py b/dppl/tests/dppl_tests/test_sycl_queue_manager.py index 9fb44730d4..6f83f0fdc9 100644 --- a/dppl/tests/dppl_tests/test_sycl_queue_manager.py +++ b/dppl/tests/dppl_tests/test_sycl_queue_manager.py @@ -43,7 +43,7 @@ def test_dppl_dump (self): def test_dppl_dump_device_info (self): q = dppl.get_current_queue() try: - dppl.dump_device_info(q) + q.get_sycl_device().dump_device_info() except Exception: self.fail("Encountered an exception inside dump_device_info().") @@ -92,3 +92,6 @@ def SessionThread (self): self.assertEqual(dppl.get_num_activated_queues(), 1) Session1.start() Session2.start() + +if __name__ == '__main__': + unittest.main() diff --git a/dppl/tests/test_dump_functions.py b/dppl/tests/test_dump_functions.py index 3b054548fb..2af4744b8e 100644 --- a/dppl/tests/test_dump_functions.py +++ b/dppl/tests/test_dump_functions.py @@ -31,6 +31,10 @@ def test_dppl_dump (self): def test_dppl_dump_device_info (self): q = dppl.get_current_queue() try: - dppl.dump_device_info(q) + q.get_sycl_device().dump_device_info() except Exception: self.fail("Encountered an exception inside dump_device_info().") + + +if __name__ == '__main__': + unittest.main() From 758aacca5058ac712058851da1a296e94a45ed61 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Wed, 16 Sep 2020 14:34:01 +0300 Subject: [PATCH 09/41] Add C-API stub library for sycl memory. --- backends/CMakeLists.txt | 1 + backends/include/dppl_sycl_usm_interface.h | 32 +++++++++++++++++++++ backends/source/dppl_sycl_usm_interface.cpp | 29 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 backends/include/dppl_sycl_usm_interface.h create mode 100644 backends/source/dppl_sycl_usm_interface.cpp diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index 3a9a0434d4..dfb664859e 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -97,6 +97,7 @@ add_library( DPPLSyclInterface SHARED source/dppl_sycl_queue_interface.cpp + source/dppl_sycl_usm_interface.cpp ) # Install DPPLOpenCLInterface diff --git a/backends/include/dppl_sycl_usm_interface.h b/backends/include/dppl_sycl_usm_interface.h new file mode 100644 index 0000000000..94d3ca46be --- /dev/null +++ b/backends/include/dppl_sycl_usm_interface.h @@ -0,0 +1,32 @@ +//===--- dppl_sycl_usm_interface.h - DPPL-SYCL interface ---*---C++ -*---===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// TODO +/// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "Support/ExternC.h" + +DPPL_C_EXTERN_C_BEGIN + +DPPL_C_EXTERN_C_END diff --git a/backends/source/dppl_sycl_usm_interface.cpp b/backends/source/dppl_sycl_usm_interface.cpp new file mode 100644 index 0000000000..974f8c0ad6 --- /dev/null +++ b/backends/source/dppl_sycl_usm_interface.cpp @@ -0,0 +1,29 @@ +//===--- dppl_sycl_usm_interface.cpp - DPPL-SYCL interface --*- C++ -*---===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// TODO +/// +//===----------------------------------------------------------------------===// +#include "dppl_sycl_usm_interface.h" + +#include /* SYCL headers */ + +using namespace cl::sycl; From 35a467419f8fa48fb649642ec269071cddd22992 Mon Sep 17 00:00:00 2001 From: Diptorup Deb Date: Wed, 16 Sep 2020 12:21:55 -0500 Subject: [PATCH 10/41] Add missing DPPL_API. --- backends/include/dppl_sycl_context_interface.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backends/include/dppl_sycl_context_interface.h b/backends/include/dppl_sycl_context_interface.h index 6cd3c271a2..1f3506930e 100644 --- a/backends/include/dppl_sycl_context_interface.h +++ b/backends/include/dppl_sycl_context_interface.h @@ -40,6 +40,7 @@ DPPL_C_EXTERN_C_BEGIN * @param CtxtRef A opaque pointer to a sycl::context. * @return True if the SYCL context is a host context, else False. */ +DPPL_API bool DPPLIsHostContext (__dppl_keep const DPPLSyclContextRef CtxtRef); /*! @@ -47,6 +48,7 @@ bool DPPLIsHostContext (__dppl_keep const DPPLSyclContextRef CtxtRef); * * @param CtxtRef The DPPLSyclContextRef pointer to be deleted. */ +DPPL_API void DPPLDeleteSyclContext (__dppl_take DPPLSyclContextRef CtxtRef); DPPL_C_EXTERN_C_END From 7bb5faf2cefe7ef507f3cb59985681d9d140d0c7 Mon Sep 17 00:00:00 2001 From: Diptorup Deb Date: Wed, 16 Sep 2020 15:08:11 -0500 Subject: [PATCH 11/41] Move platform specific functions into a separate file. --- backends/CMakeLists.txt | 1 + .../include/dppl_sycl_platform_interface.h | 49 ++++++++++++ backends/include/dppl_sycl_queue_interface.h | 7 -- backends/include/dppl_sycl_queue_manager.h | 8 -- .../source/dppl_sycl_platform_interface.cpp | 74 +++++++++++++++++++ backends/source/dppl_sycl_queue_interface.cpp | 46 ------------ backends/source/dppl_sycl_queue_manager.cpp | 16 ---- backends/tests/CMakeLists.txt | 1 + .../tests/test_sycl_platform_interface.cpp | 50 +++++++++++++ backends/tests/test_sycl_queue_manager.cpp | 18 +---- dppl/sycl_core.pyx | 28 +++---- 11 files changed, 191 insertions(+), 107 deletions(-) create mode 100644 backends/include/dppl_sycl_platform_interface.h create mode 100644 backends/source/dppl_sycl_platform_interface.cpp create mode 100644 backends/tests/test_sycl_platform_interface.cpp diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index 921bb1d3eb..d1a6dd8aa2 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -98,6 +98,7 @@ add_library( SHARED source/dppl_sycl_context_interface.cpp source/dppl_sycl_device_interface.cpp + source/dppl_sycl_platform_interface.cpp source/dppl_sycl_queue_interface.cpp source/dppl_sycl_queue_manager.cpp ) diff --git a/backends/include/dppl_sycl_platform_interface.h b/backends/include/dppl_sycl_platform_interface.h new file mode 100644 index 0000000000..459a39a1da --- /dev/null +++ b/backends/include/dppl_sycl_platform_interface.h @@ -0,0 +1,49 @@ +//===--- dppl_sycl_platform_interface.h - DPPL-SYCL interface ---*--C++ -*-===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This header declares a C interface to sycl::platform interface functions. +/// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "dppl_data_types.h" +#include "Support/DllExport.h" +#include "Support/ExternC.h" + +DPPL_C_EXTERN_C_BEGIN + +/*! + * @brief Get the number of sycl::platform available on the system. + * + * @return The number of available sycl::platforms. + */ +DPPL_API +size_t DPPLPlatform_GetNumPlatforms (); + +/*! + * @brief Prints out some selected info about all sycl::platform on the system. + * + */ +DPPL_API +void DPPLPlatform_DumpInfo (); + +DPPL_C_EXTERN_C_END diff --git a/backends/include/dppl_sycl_queue_interface.h b/backends/include/dppl_sycl_queue_interface.h index f2493b87f9..60d080e3f0 100644 --- a/backends/include/dppl_sycl_queue_interface.h +++ b/backends/include/dppl_sycl_queue_interface.h @@ -35,13 +35,6 @@ DPPL_C_EXTERN_C_BEGIN -/*! - * @brief Prints out information about the Sycl environment, such as - * number of available platforms, number of activated queues, etc. - */ -DPPL_API -void DPPLDumpPlatformInfo (); - /*! * @brief Returns the Sycl context for the queue. * diff --git a/backends/include/dppl_sycl_queue_manager.h b/backends/include/dppl_sycl_queue_manager.h index 741cb51ad2..8d550be6b9 100644 --- a/backends/include/dppl_sycl_queue_manager.h +++ b/backends/include/dppl_sycl_queue_manager.h @@ -42,14 +42,6 @@ DPPL_C_EXTERN_C_BEGIN -/*! - * @brief Get the number of sycl::platform available on the system. - * - * @return The number of available sycl::platforms. - */ -DPPL_API -size_t DPPLGetNumPlatforms (); - /*! * @brief Get the sycl::queue object that is currently activated for this * thread. diff --git a/backends/source/dppl_sycl_platform_interface.cpp b/backends/source/dppl_sycl_platform_interface.cpp new file mode 100644 index 0000000000..271a64b31a --- /dev/null +++ b/backends/source/dppl_sycl_platform_interface.cpp @@ -0,0 +1,74 @@ +//===--- dppl_sycl_platform_interface.cpp - DPPL-SYCL interface --*- C++ -*-===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This file implements the functions declared in +/// dppl_sycl_platform_interface.h. +/// +//===----------------------------------------------------------------------===// + +#include "dppl_sycl_platform_interface.h" +#include +#include +#include + +#include + +using namespace cl::sycl; + +/*! + * Prints out the following sycl::info::platform attributes for each platform + * found on the system: + * - info::platform::name + * - info::platform::version + * - info::platform::profile + * + */ +void DPPLPlatform_DumpInfo () +{ + size_t i = 0; + + // Print out the info for each platform + auto platforms = platform::get_platforms(); + for (auto &p : platforms) { + std::cout << "---Platform " << i << '\n'; + std::stringstream ss; + + ss << std::setw(4) << " " << std::left << std::setw(12) << "Name" + << p.get_info() << '\n'; + ss << std::setw(4) << " " << std::left << std::setw(12) << "Version" + << p.get_info() << '\n'; + ss << std::setw(4) << " " << std::left << std::setw(12) << "Vendor" + << p.get_info() << '\n'; + ss << std::setw(4) << " " << std::left << std::setw(12) << "Profile" + << p.get_info() << '\n'; + + std::cout << ss.str(); + ++i; + } +} + +/*! + * Returns the number of sycl::platform on the system. + */ +size_t DPPLPlatform_GetNumPlatforms () +{ + return platform::get_platforms().size(); +} diff --git a/backends/source/dppl_sycl_queue_interface.cpp b/backends/source/dppl_sycl_queue_interface.cpp index 2dad78b604..e02479d69d 100644 --- a/backends/source/dppl_sycl_queue_interface.cpp +++ b/backends/source/dppl_sycl_queue_interface.cpp @@ -26,9 +26,6 @@ #include "dppl_sycl_queue_interface.h" #include "Support/CBindingWrapping.h" -#include -#include -#include #include /* SYCL headers */ @@ -39,51 +36,8 @@ namespace // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) -/*! - * @brief - * - * @param Platform My Param doc - */ -void dump_platform_info (const platform & Platform) -{ - std::stringstream ss; - - ss << std::setw(4) << " " << std::left << std::setw(12) << "Name" - << Platform.get_info() << '\n'; - ss << std::setw(4) << " " << std::left << std::setw(12) << "Version" - << Platform.get_info() << '\n'; - ss << std::setw(4) << " " << std::left << std::setw(12) << "Vendor" - << Platform.get_info() << '\n'; - ss << std::setw(4) << " " << std::left << std::setw(12) << "Profile" - << Platform.get_info() << '\n'; - - std::cout << ss.str(); -} - } /* end of anonymous namespace */ -/*! - * Prints out number of available SYCL platforms, number of CPU queues, number - * of GPU queues, metadata about the current global queue, and how many queues - * are currently activated. More information can be added in future, and - * functions to extract these information using SYCL API (e.g. device_info) - * may also be added. For now, this function can be used as a basic canary test - * to check if the queue manager was properly initialized. - * - */ -void DPPLDumpPlatformInfo () -{ - size_t i = 0; - - // Print out the info for each platform - auto platforms = platform::get_platforms(); - for (auto &p : platforms) { - std::cout << "---Platform " << i << '\n'; - dump_platform_info(p); - ++i; - } -} - __dppl_give DPPLSyclDeviceRef DPPLGetDeviceFromQueue (__dppl_keep const DPPLSyclQueueRef QRef) { diff --git a/backends/source/dppl_sycl_queue_manager.cpp b/backends/source/dppl_sycl_queue_manager.cpp index e6e4485942..17776fda11 100644 --- a/backends/source/dppl_sycl_queue_manager.cpp +++ b/backends/source/dppl_sycl_queue_manager.cpp @@ -117,14 +117,6 @@ class QMgrHelper //----------------------------- Public API -----------------------------------// -/*! - * Returns the number of sycl::platform on the system. - */ -size_t DPPLGetNumPlatforms () -{ - return platform::get_platforms().size(); -} - /*! * Allocates a new copy of the present top of stack queue, which can be the * default queue and returns to caller. The caller owns the pointer and is @@ -284,14 +276,6 @@ QMgrHelper::popSyclQueue () } /* end of anonymous namespace */ -/*! - * Returns the number of sycl::platform on the system. - */ -size_t DPPLGetNumPlatforms () -{ - return platform::get_platforms().size(); -} - /*! * Returns inside the number of activated queues not including the global queue * (QMgrHelper::active_queues[0]). diff --git a/backends/tests/CMakeLists.txt b/backends/tests/CMakeLists.txt index e83f408f05..c3add176ba 100644 --- a/backends/tests/CMakeLists.txt +++ b/backends/tests/CMakeLists.txt @@ -24,6 +24,7 @@ else() set(PYDPPL_BACKEND_TEST_CASES test_sycl_queue_manager + test_sycl_platform_interface ) foreach(TEST_CASE ${PYDPPL_BACKEND_TEST_CASES}) diff --git a/backends/tests/test_sycl_platform_interface.cpp b/backends/tests/test_sycl_platform_interface.cpp new file mode 100644 index 0000000000..3de7029b40 --- /dev/null +++ b/backends/tests/test_sycl_platform_interface.cpp @@ -0,0 +1,50 @@ +//===--- test_sycl_platform_interface.cpp - DPPL-SYCL interface -*- C++ -*-===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This file has unit test cases for functions defined in +/// dppl_sycl_platform_interface.h. +/// +//===----------------------------------------------------------------------===// +#include "dppl_sycl_platform_interface.h" +#include + +struct TestDPPLSyclPlatformInterface : public ::testing::Test +{ }; + + +TEST_F (TestDPPLSyclPlatformInterface, CheckGetNumPlatforms) +{ + auto nplatforms = DPPLPlatform_GetNumPlatforms(); + EXPECT_GE(nplatforms, 0); +} + +TEST_F (TestDPPLSyclPlatformInterface, CheckDPPLPlatformDumpInfo) +{ + EXPECT_NO_FATAL_FAILURE(DPPLPlatform_DumpInfo()); +} + +int +main (int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + return ret; +} diff --git a/backends/tests/test_sycl_queue_manager.cpp b/backends/tests/test_sycl_queue_manager.cpp index 8ca98aa66a..d38ddb2a8a 100644 --- a/backends/tests/test_sycl_queue_manager.cpp +++ b/backends/tests/test_sycl_queue_manager.cpp @@ -20,7 +20,7 @@ /// /// \file /// This file has unit test cases for functions defined in -/// dppl_sycl_queue_interface.h. +/// dppl_sycl_queue_interface.h and dppl_sycl_queue_manager.h. /// //===----------------------------------------------------------------------===// #include "dppl_sycl_device_interface.h" @@ -56,15 +56,7 @@ namespace } struct TestDPPLSyclQueuemanager : public ::testing::Test -{ - -}; - -TEST_F (TestDPPLSyclQueuemanager, CheckGetNumPlatforms) -{ - auto nplatforms = DPPLGetNumPlatforms(); - EXPECT_GE(nplatforms, 0); -} +{ }; TEST_F (TestDPPLSyclQueuemanager, CheckDPPLGetCurrentQueue) @@ -132,12 +124,6 @@ TEST_F (TestDPPLSyclQueuemanager, CheckGetNumActivatedQueues) } -TEST_F (TestDPPLSyclQueuemanager, CheckDPPLDumpPlatformInfo) -{ - EXPECT_NO_FATAL_FAILURE(DPPLDumpPlatformInfo()); -} - - TEST_F (TestDPPLSyclQueuemanager, CheckDPPLDumpDeviceInfo) { auto q = DPPLGetCurrentQueue(); diff --git a/dppl/sycl_core.pyx b/dppl/sycl_core.pyx index f167cc3cdf..4018b3b734 100644 --- a/dppl/sycl_core.pyx +++ b/dppl/sycl_core.pyx @@ -60,16 +60,6 @@ cdef extern from "dppl_sycl_types.h": cdef extern from "dppl_sycl_context_interface.h": cdef void DPPLDeleteSyclContext (DPPLSyclContextRef CtxtRef) except + - -cdef extern from "dppl_sycl_queue_interface.h": - cdef void DPPLDeleteSyclQueue (DPPLSyclQueueRef QRef) except + - cdef void DPPLDumpPlatformInfo () except + - cdef DPPLSyclContextRef DPPLGetContextFromQueue (const DPPLSyclQueueRef Q) \ - except+ - cdef DPPLSyclDeviceRef DPPLGetDeviceFromQueue (const DPPLSyclQueueRef Q) \ - except + - - cdef extern from "dppl_sycl_device_interface.h": cdef void DPPLDumpDeviceInfo (const DPPLSyclDeviceRef DRef) except + cdef void DPPLDeleteSyclDevice (DPPLSyclDeviceRef DRef) except + @@ -89,6 +79,17 @@ cdef extern from "dppl_sycl_device_interface.h": cdef void DPPLDeleteDeviceVendorName (const char *VendorName) except + cdef void DPPLDeleteDeviceDriverInfo (const char *DriverInfo) except + +cdef extern from "dppl_sycl_platform_interface.h": + cdef size_t DPPLPlatform_GetNumPlatforms () + cdef void DPPLPlatform_DumpInfo () + +cdef extern from "dppl_sycl_queue_interface.h": + cdef void DPPLDeleteSyclQueue (DPPLSyclQueueRef QRef) except + + cdef DPPLSyclContextRef DPPLGetContextFromQueue (const DPPLSyclQueueRef Q) \ + except+ + cdef DPPLSyclDeviceRef DPPLGetDeviceFromQueue (const DPPLSyclQueueRef Q) \ + except + + cdef extern from "dppl_sycl_queue_manager.h": cdef enum _device_type 'DPPLSyclDeviceType': _GPU 'DPPL_GPU' @@ -98,7 +99,6 @@ cdef extern from "dppl_sycl_queue_manager.h": cdef size_t DPPLGetNumCPUQueues () except + cdef size_t DPPLGetNumGPUQueues () except + cdef size_t DPPLGetNumActivatedQueues () except + - cdef size_t DPPLGetNumPlatforms () except + cdef DPPLSyclQueueRef DPPLGetQueue (_device_type DTy, size_t device_num) except + cdef void DPPLPopSyclQueue () except + @@ -217,7 +217,7 @@ cdef class _SyclQueueManager: DPPLPopSyclQueue() def has_sycl_platforms (self): - cdef size_t num_platforms = DPPLGetNumPlatforms() + cdef size_t num_platforms = DPPLPlatform_GetNumPlatforms() if num_platforms: return True else: @@ -226,7 +226,7 @@ cdef class _SyclQueueManager: def get_num_platforms (self): ''' Returns the number of available SYCL/OpenCL platforms. ''' - return DPPLGetNumPlatforms() + return DPPLPlatform_GetNumPlatforms() def get_num_activated_queues (self): ''' Return the number of currently activated queues for this thread. @@ -264,7 +264,7 @@ cdef class _SyclQueueManager: def dump (self): ''' Prints information about the Runtime object. ''' - DPPLDumpPlatformInfo() + DPPLPlatform_DumpInfo() def is_in_dppl_ctxt (self): cdef size_t num = DPPLGetNumActivatedQueues() From 4a114909cffa612e302dd26c8c14ea2775ebc2a2 Mon Sep 17 00:00:00 2001 From: Diptorup Deb Date: Wed, 16 Sep 2020 15:38:09 -0500 Subject: [PATCH 12/41] Create a single utility function to delete C strings. --- backends/CMakeLists.txt | 1 + backends/include/dppl_sycl_device_interface.h | 27 ------------ backends/include/dppl_utils.h | 41 +++++++++++++++++++ .../source/dppl_sycl_device_interface.cpp | 17 +------- backends/source/dppl_utils.cpp | 31 ++++++++++++++ dppl/sycl_core.pyx | 11 +++-- 6 files changed, 79 insertions(+), 49 deletions(-) create mode 100644 backends/include/dppl_utils.h create mode 100644 backends/source/dppl_utils.cpp diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index d1a6dd8aa2..b812978ed0 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -101,6 +101,7 @@ add_library( source/dppl_sycl_platform_interface.cpp source/dppl_sycl_queue_interface.cpp source/dppl_sycl_queue_manager.cpp + source/dppl_utils.cpp ) # Install DPPLOpenCLInterface diff --git a/backends/include/dppl_sycl_device_interface.h b/backends/include/dppl_sycl_device_interface.h index e379f7d733..adbc216662 100644 --- a/backends/include/dppl_sycl_device_interface.h +++ b/backends/include/dppl_sycl_device_interface.h @@ -117,15 +117,6 @@ DPPL_API __dppl_give const char* DPPLGetDeviceDriverInfo (__dppl_keep const DPPLSyclDeviceRef DRef); -/*! - * @brief Deletes a C string corresponding to the string returned by - * DPPLGetDeviceDriverInfo(). - * - * @param DriverInfo C String for the driver number. - */ -DPPL_API -void DPPLDeleteDeviceDriverInfo (__dppl_take const char* DriverInfo); - /*! * @brief Returns a C string for the device name. * @@ -136,15 +127,6 @@ DPPL_API __dppl_give const char* DPPLGetDeviceName (__dppl_keep const DPPLSyclDeviceRef DRef); -/*! - * @brief Deletes a C string corresponding to the string returned by - * DPPLGetDeviceName(). - * - * @param DeviceName C String for the device name. - */ -DPPL_API -void DPPLDeleteDeviceName (__dppl_take const char* DeviceName); - /*! * @brief Returns a C string corresponding to the vendor name. * @@ -155,15 +137,6 @@ DPPL_API __dppl_give const char* DPPLGetDeviceVendorName (__dppl_keep const DPPLSyclDeviceRef DRef); -/*! - * @brief Deletes a C string corresponding to the string returned by - * DPPLGetDeviceVendorName(). - * - * @param char C String for the vendor name. - */ -DPPL_API -void DPPLDeleteDeviceVendorName (__dppl_take const char* VendorName); - /*! * @brief Returns True if the device and the host share a unified memory * subsystem, else returns False. diff --git a/backends/include/dppl_utils.h b/backends/include/dppl_utils.h new file mode 100644 index 0000000000..89071f19f9 --- /dev/null +++ b/backends/include/dppl_utils.h @@ -0,0 +1,41 @@ +//===------------- dppl_utils.h - DPPL-SYCL interface --*-- C++ -----*-----===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This file defines common helper functions used in other places in DPPL. +//===----------------------------------------------------------------------===// + +#pragma once + +#include "Support/DllExport.h" +#include "Support/ExternC.h" +#include "Support/MemOwnershipAttrs.h" + +DPPL_C_EXTERN_C_BEGIN + +/*! + * @brief Deletes the C String argument + * + * @param str C string to be deleted + */ +DPPL_API +void DPPLDeleteCString (__dppl_take const char* str); + +DPPL_C_EXTERN_C_END diff --git a/backends/source/dppl_sycl_device_interface.cpp b/backends/source/dppl_sycl_device_interface.cpp index 4efcf40580..f70f34be1e 100644 --- a/backends/source/dppl_sycl_device_interface.cpp +++ b/backends/source/dppl_sycl_device_interface.cpp @@ -38,7 +38,7 @@ namespace DEFINE_SIMPLE_CONVERSION_FUNCTIONS(device, DPPLSyclDeviceRef) /*! - * @brief + * @brief Helper function to print the metadata for a sycl::device. * * @param Device My Param doc */ @@ -108,11 +108,6 @@ DPPLGetDeviceName (__dppl_keep const DPPLSyclDeviceRef DRef) return cstr_name; } -void DPPLDeleteDeviceName (__dppl_take const char *DeviceName) -{ - delete DeviceName; -} - __dppl_give const char* DPPLGetDeviceVendorName (__dppl_keep const DPPLSyclDeviceRef DRef) { @@ -122,11 +117,6 @@ DPPLGetDeviceVendorName (__dppl_keep const DPPLSyclDeviceRef DRef) return cstr_vendor; } -void DPPLDeleteDeviceVendorName (__dppl_take const char *VendorName) -{ - delete VendorName; -} - __dppl_give const char* DPPLGetDeviceDriverInfo (__dppl_keep const DPPLSyclDeviceRef DRef) { @@ -136,11 +126,6 @@ DPPLGetDeviceDriverInfo (__dppl_keep const DPPLSyclDeviceRef DRef) return cstr_driver; } -void DPPLDeleteDeviceDriverInfo (__dppl_take const char *DriverInfo) -{ - delete DriverInfo; -} - bool DPPLGetDeviceHostUnifiedMemory (__dppl_keep const DPPLSyclDeviceRef DRef) { return unwrap(DRef)->get_info(); diff --git a/backends/source/dppl_utils.cpp b/backends/source/dppl_utils.cpp new file mode 100644 index 0000000000..f9c7460f73 --- /dev/null +++ b/backends/source/dppl_utils.cpp @@ -0,0 +1,31 @@ +//===--------- dppl_utils.cpp - DPPL-SYCL interface ----*---- C++ ----*----===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This file implements the helper functions defined in dppl_utils.h. +/// +//===----------------------------------------------------------------------===// + +#include "dppl_utils.h" + +void DPPLDeleteCString (__dppl_take const char* str) +{ + delete str; +} \ No newline at end of file diff --git a/dppl/sycl_core.pyx b/dppl/sycl_core.pyx index 4018b3b734..1ed47334df 100644 --- a/dppl/sycl_core.pyx +++ b/dppl/sycl_core.pyx @@ -44,6 +44,8 @@ cdef class UnsupportedDeviceTypeError(Exception): ''' pass +cdef extern from "dppl_utils.h": + cdef void DPPLDeleteCString (const char *str) cdef extern from "dppl_sycl_types.h": cdef struct DPPLOpaqueSyclContext: @@ -75,9 +77,6 @@ cdef extern from "dppl_sycl_device_interface.h": except + cdef bool DPPLGetDeviceHostUnifiedMemory (const DPPLSyclDeviceRef DRef) \ except + - cdef void DPPLDeleteDeviceName (const char *DeviceName) except + - cdef void DPPLDeleteDeviceVendorName (const char *VendorName) except + - cdef void DPPLDeleteDeviceDriverInfo (const char *DriverInfo) except + cdef extern from "dppl_sycl_platform_interface.h": cdef size_t DPPLPlatform_GetNumPlatforms () @@ -143,9 +142,9 @@ cdef class SyclDevice: def __dealloc__ (self): DPPLDeleteSyclDevice(self.device_ptr) - DPPLDeleteDeviceName(self.device_name) - DPPLDeleteDeviceVendorName(self.vendor_name) - DPPLDeleteDeviceDriverInfo(self.driver_version) + DPPLDeleteCString(self.device_name) + DPPLDeleteCString(self.vendor_name) + DPPLDeleteCString(self.driver_version) def dump_device_info (self): ''' Print information about the SYCL device. From 456bdf23ea88543dca9d7a05ae09d7c13e6089cc Mon Sep 17 00:00:00 2001 From: Diptorup Deb Date: Wed, 16 Sep 2020 22:39:48 -0500 Subject: [PATCH 13/41] Change the wrap/unwrap functions to also include the type. --- backends/include/Support/CBindingWrapping.h | 4 ++-- .../source/dppl_sycl_context_interface.cpp | 8 +++---- .../source/dppl_sycl_device_interface.cpp | 22 +++++++++---------- backends/source/dppl_sycl_queue_interface.cpp | 15 +++++++------ backends/source/dppl_sycl_queue_manager.cpp | 10 ++++----- 5 files changed, 30 insertions(+), 29 deletions(-) diff --git a/backends/include/Support/CBindingWrapping.h b/backends/include/Support/CBindingWrapping.h index 40ef4027b2..2a98f59512 100644 --- a/backends/include/Support/CBindingWrapping.h +++ b/backends/include/Support/CBindingWrapping.h @@ -26,11 +26,11 @@ #pragma once #define DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref) \ - inline ty *unwrap(ref P) { \ + inline ty *unwrap_##ty(ref P) { \ return reinterpret_cast(P); \ } \ \ - inline ref wrap(const ty *P) { \ + inline ref wrap_##ty(const ty *P) { \ return reinterpret_cast(const_cast(P)); \ } diff --git a/backends/source/dppl_sycl_context_interface.cpp b/backends/source/dppl_sycl_context_interface.cpp index d27b150f74..0a83f16d58 100644 --- a/backends/source/dppl_sycl_context_interface.cpp +++ b/backends/source/dppl_sycl_context_interface.cpp @@ -32,8 +32,8 @@ using namespace cl::sycl; namespace { - // Create wrappers for C Binding types (see CBindingWrapping.h). - DEFINE_SIMPLE_CONVERSION_FUNCTIONS(context, DPPLSyclContextRef) +// Create wrappers for C Binding types (see CBindingWrapping.h). +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(context, DPPLSyclContextRef) } /* end of anonymous namespace */ /*! @@ -44,7 +44,7 @@ namespace */ bool DPPLIsHostContext (__dppl_keep const DPPLSyclContextRef CtxtRef) { - return unwrap(CtxtRef)->is_host(); + return unwrap_context(CtxtRef)->is_host(); } /*! @@ -54,5 +54,5 @@ bool DPPLIsHostContext (__dppl_keep const DPPLSyclContextRef CtxtRef) */ void DPPLDeleteSyclContext (__dppl_take DPPLSyclContextRef CtxtRef) { - delete unwrap(CtxtRef); + delete unwrap_context(CtxtRef); } diff --git a/backends/source/dppl_sycl_device_interface.cpp b/backends/source/dppl_sycl_device_interface.cpp index f70f34be1e..7fa9c8d54f 100644 --- a/backends/source/dppl_sycl_device_interface.cpp +++ b/backends/source/dppl_sycl_device_interface.cpp @@ -35,7 +35,7 @@ using namespace cl::sycl; namespace { // Create wrappers for C Binding types (see CBindingWrapping.h). - DEFINE_SIMPLE_CONVERSION_FUNCTIONS(device, DPPLSyclDeviceRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(device, DPPLSyclDeviceRef) /*! * @brief Helper function to print the metadata for a sycl::device. @@ -68,41 +68,41 @@ void dump_device_info (const device & Device) */ void DPPLDumpDeviceInfo (__dppl_keep const DPPLSyclDeviceRef DRef) { - auto Device = unwrap(DRef); + auto Device = unwrap_device(DRef); dump_device_info(*Device); } void DPPLDeleteSyclDevice (__dppl_take DPPLSyclDeviceRef DRef) { - delete unwrap(DRef); + delete unwrap_device(DRef); } bool DPPLDeviceIsAccelerator (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->is_accelerator(); + return unwrap_device(DRef)->is_accelerator(); } bool DPPLDeviceIsCPU (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->is_cpu(); + return unwrap_device(DRef)->is_cpu(); } bool DPPLDeviceIsGPU (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->is_gpu(); + return unwrap_device(DRef)->is_gpu(); } bool DPPLDeviceIsHost (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->is_host(); + return unwrap_device(DRef)->is_host(); } __dppl_give const char* DPPLGetDeviceName (__dppl_keep const DPPLSyclDeviceRef DRef) { - auto name = unwrap(DRef)->get_info(); + auto name = unwrap_device(DRef)->get_info(); auto cstr_name = new char [name.length()+1]; std::strcpy (cstr_name, name.c_str()); return cstr_name; @@ -111,7 +111,7 @@ DPPLGetDeviceName (__dppl_keep const DPPLSyclDeviceRef DRef) __dppl_give const char* DPPLGetDeviceVendorName (__dppl_keep const DPPLSyclDeviceRef DRef) { - auto vendor = unwrap(DRef)->get_info(); + auto vendor = unwrap_device(DRef)->get_info(); auto cstr_vendor = new char [vendor.length()+1]; std::strcpy (cstr_vendor, vendor.c_str()); return cstr_vendor; @@ -120,7 +120,7 @@ DPPLGetDeviceVendorName (__dppl_keep const DPPLSyclDeviceRef DRef) __dppl_give const char* DPPLGetDeviceDriverInfo (__dppl_keep const DPPLSyclDeviceRef DRef) { - auto driver = unwrap(DRef)->get_info(); + auto driver = unwrap_device(DRef)->get_info(); auto cstr_driver = new char [driver.length()+1]; std::strcpy (cstr_driver, driver.c_str()); return cstr_driver; @@ -128,5 +128,5 @@ DPPLGetDeviceDriverInfo (__dppl_keep const DPPLSyclDeviceRef DRef) bool DPPLGetDeviceHostUnifiedMemory (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->get_info(); + return unwrap_device(DRef)->get_info(); } diff --git a/backends/source/dppl_sycl_queue_interface.cpp b/backends/source/dppl_sycl_queue_interface.cpp index e02479d69d..efb23554d5 100644 --- a/backends/source/dppl_sycl_queue_interface.cpp +++ b/backends/source/dppl_sycl_queue_interface.cpp @@ -34,24 +34,25 @@ using namespace cl::sycl; namespace { // Create wrappers for C Binding types (see CBindingWrapping.h). - DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) - +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(device, DPPLSyclDeviceRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(context, DPPLSyclContextRef) } /* end of anonymous namespace */ __dppl_give DPPLSyclDeviceRef DPPLGetDeviceFromQueue (__dppl_keep const DPPLSyclQueueRef QRef) { - auto Q = unwrap(QRef); + auto Q = unwrap_queue(QRef); auto Device = new device(Q->get_device()); - return reinterpret_cast(Device); + return wrap_device(Device); } __dppl_give DPPLSyclContextRef DPPLGetContextFromQueue (__dppl_keep const DPPLSyclQueueRef QRef) { - auto Q = unwrap(QRef); + auto Q = unwrap_queue(QRef); auto Context = new context(Q->get_context()); - return reinterpret_cast(Context); + return wrap_context(Context); } /*! @@ -59,5 +60,5 @@ DPPLGetContextFromQueue (__dppl_keep const DPPLSyclQueueRef QRef) */ void DPPLDeleteSyclQueue (__dppl_take DPPLSyclQueueRef QRef) { - delete unwrap(QRef); + delete unwrap_queue(QRef); } diff --git a/backends/source/dppl_sycl_queue_manager.cpp b/backends/source/dppl_sycl_queue_manager.cpp index 17776fda11..c299269e5d 100644 --- a/backends/source/dppl_sycl_queue_manager.cpp +++ b/backends/source/dppl_sycl_queue_manager.cpp @@ -39,8 +39,8 @@ using namespace cl::sycl; namespace { - // Create wrappers for C Binding types (see CBindingWrapping.h). - DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) +// Create wrappers for C Binding types (see CBindingWrapping.h). +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) void error_reporter (const std::string & msg) { @@ -128,7 +128,7 @@ DPPLSyclQueueRef QMgrHelper::getCurrentQueue () if(active_queues.empty()) error_reporter("No currently active queues."); auto last = QMgrHelper::active_queues.size() - 1; - return wrap(new queue(QMgrHelper::active_queues[last])); + return wrap_queue(new queue(QMgrHelper::active_queues[last])); } /*! @@ -169,7 +169,7 @@ QMgrHelper::getQueue (DPPLSyclDeviceType DeviceTy, error_reporter("Unsupported device type."); } - return wrap(QRef); + return wrap_queue(QRef); } /*! @@ -254,7 +254,7 @@ QMgrHelper::pushSyclQueue (DPPLSyclDeviceType DeviceTy, size_t DNum) } } - return wrap(QRef); + return wrap_queue(QRef); } /*! From dd8d8460bc3be3468587b176744d94a8bc14ede7 Mon Sep 17 00:00:00 2001 From: Diptorup Deb Date: Wed, 16 Sep 2020 22:41:54 -0500 Subject: [PATCH 14/41] Add an interoperability function to create Sycl kernels from SPIR-V. --- backends/CMakeLists.txt | 1 + backends/include/dppl_sycl_kernel_interface.h | 99 ++++++++++++++++ backends/include/dppl_sycl_types.h | 34 ++++-- .../source/dppl_sycl_kernel_interface.cpp | 110 ++++++++++++++++++ 4 files changed, 233 insertions(+), 11 deletions(-) create mode 100644 backends/include/dppl_sycl_kernel_interface.h create mode 100644 backends/source/dppl_sycl_kernel_interface.cpp diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index b812978ed0..b909b9b15d 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -98,6 +98,7 @@ add_library( SHARED source/dppl_sycl_context_interface.cpp source/dppl_sycl_device_interface.cpp + source/dppl_sycl_kernel_interface.cpp source/dppl_sycl_platform_interface.cpp source/dppl_sycl_queue_interface.cpp source/dppl_sycl_queue_manager.cpp diff --git a/backends/include/dppl_sycl_kernel_interface.h b/backends/include/dppl_sycl_kernel_interface.h new file mode 100644 index 0000000000..3131f9fe0d --- /dev/null +++ b/backends/include/dppl_sycl_kernel_interface.h @@ -0,0 +1,99 @@ +//===---- dppl_sycl_kernel_interface.h - DPPL-SYCL interface --*--C++ --*--===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This header declares a C API to create Sycl kernels from OpenCL kernels. In +/// future, API to create interoperability kernels from other languages such as +/// Level-0 driver API may be added here. +/// +/// \todo Investigate what we should do when we add support for Level-0 API. +/// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "dppl_data_types.h" +#include "dppl_sycl_types.h" +#include "Support/DllExport.h" +#include "Support/ExternC.h" +#include "Support/MemOwnershipAttrs.h" + +DPPL_C_EXTERN_C_BEGIN + +/*! + * @brief Create a Sycl Kernel from an OpenCL SPIR-V binary + * + * Sycl 1.2 does expose any method to create a sycl::program from a SPIR-V IL + * file. To get around this limitation, we need to use the Sycl feature to + * create an interoperability kernel from an OpenCL kernel. This function first + * creates an OpenCL program and kernel from the SPIR-V binary and then using + * the Sycl-OpenCL interoperability feature creates a Sycl kernel from the + * OpenCL kernel. + * + * The feature to create a Sycl kernel from a SPIR-V IL binary will be available + * in Sycl 2.0. + * + * @param Ctx An opaque pointer to a sycl::context + * @param IL SPIR-V binary + * @return A new SyclProgramRef pointer if the program creation succeeded, + * else returns NULL. + */ +DPPL_API +__dppl_give DPPLSyclKernelRef +DPPLKernel_CreateKernelFromSpirv (__dppl_keep const DPPLSyclContextRef Ctx, + __dppl_keep const void *IL, + size_t length, + const char *KernelName = nullptr); + +/*! + * @brief Returns a C string for the kernel name. + * + * @param Kernel DPPLSyclKernelRef pointer to an OpenCL + * interoperability kernel. + * @return If a kernel name exists then returns it as a C string, else + * returns a nullptr. + */ +DPPL_API +__dppl_give const char* +DPPLKernel_GetFunctionName (__dppl_keep const DPPLSyclKernelRef Kernel); + +/*! + * @brief Returns the number of arguments for the OpenCL kernel. + * + * @param Kernel DPPLSyclKernelRef pointer to an OpenCL + * interoperability kernel. + * @return Returns the number of arguments for the OpenCL interoperability + * kernel. + */ +DPPL_API +size_t +DPPLKernel_GetNumArgs (__dppl_keep const DPPLSyclKernelRef Kernel); + +/*! + * @brief Deletes the DPPLSyclKernelRef after casting it to a sycl::kernel. + * + * @param Kernel DPPLSyclKernelRef pointer to an OpenCL + * interoperability kernel. + */ +DPPL_API +void +DPPLKernel_DeleteKernelRef (__dppl_take DPPLSyclKernelRef Kernel); + +DPPL_C_EXTERN_C_END diff --git a/backends/include/dppl_sycl_types.h b/backends/include/dppl_sycl_types.h index d1777aae5d..1bba3de1fb 100644 --- a/backends/include/dppl_sycl_types.h +++ b/backends/include/dppl_sycl_types.h @@ -19,39 +19,51 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file defines types used by DPPL's C interface to SYCL. +/// This file defines opaque pointer types wrapping Sycl object that get used +/// by DPPL's C API. /// //===----------------------------------------------------------------------===// #pragma once /*! - * @brief + * @brief Opaque pointer used to represent references to sycl::context* * + * @see sycl::context */ typedef struct DPPLOpaqueSyclContext *DPPLSyclContextRef; /*! - * @brief + * @brief Opaque pointer used to represent references to sycl::device* * + * @see sycl::device */ typedef struct DPPLOpaqueSyclDevice *DPPLSyclDeviceRef; /*! - * @brief + * @brief Opaque pointer used to represent references to sycl::kernel* * + * @see sycl::kernel + */ +typedef struct DPPLOpaqueSyclProgram *DPPLSyclKernelRef; + +/*! + * @brief Opaque pointer used to represent references to sycl::platform* + * + * @see sycl::platform */ typedef struct DPPLOpaqueSyclPlatform *DPPLSyclPlatformRef; +/*! + * @brief Opaque pointer used to represent references to sycl::program* + * + * @see sycl::program + */ +typedef struct DPPLOpaqueSyclProgram *DPPLSyclProgramRef; + /*! - * @brief Used to pass a sycl::queue opaquely through DPPL interfaces. + * @brief Opaque pointer used to represent references to sycl::queue* * * @see sycl::queue */ typedef struct DPPLOpaqueSyclQueue *DPPLSyclQueueRef; - -/*! - * @brief Used to pass a sycl::program opaquely through DPPL interfaces. - * - */ -typedef struct DPPLOpaqueSyclProgram *DPPLSyclProgramRef; diff --git a/backends/source/dppl_sycl_kernel_interface.cpp b/backends/source/dppl_sycl_kernel_interface.cpp new file mode 100644 index 0000000000..479d501520 --- /dev/null +++ b/backends/source/dppl_sycl_kernel_interface.cpp @@ -0,0 +1,110 @@ +//===--- dppl_sycl_kernel_interface.cpp - DPPL-SYCL interface --*-- C++ -*-===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This file implements the functions declared in +/// dppl_sycl_kernel_interface.h. +/// +//===----------------------------------------------------------------------===// + +#include "dppl_sycl_kernel_interface.h" +#include "Support/CBindingWrapping.h" + +#include /* Sycl headers */ +#include /* OpenCL headers */ + +using namespace cl::sycl; + +namespace +{ +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(kernel, DPPLSyclKernelRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(context, DPPLSyclContextRef) +} + +__dppl_give DPPLSyclKernelRef +DPPLKernel_CreateKernelFromSpirv (__dppl_keep const DPPLSyclContextRef Ctx, + __dppl_keep const void *IL, + size_t length, + const char *KernelName) +{ + cl_int err; + + auto SyclCtx = unwrap_context(Ctx); + auto CLCtx = SyclCtx->get(); + auto CLProgram = clCreateProgramWithIL(CLCtx, IL, length, &err); + if (err) { + // \todo: record the error string and any other information. + return nullptr; + } + auto SyclDevices = SyclCtx->get_devices(); + + // Get a list of CL Devices from the Sycl devices + auto CLDevices = new cl_device_id[SyclDevices.size()]; + for (auto i = 0ul; i < SyclDevices.size(); ++i) + CLDevices[i] = SyclDevices[i].get(); + + // Create the OpenCL interoperability program + err = clBuildProgram(CLProgram, (cl_uint)(SyclDevices.size()), CLDevices, + nullptr, nullptr, nullptr); + // free the CLDevices array + delete[] CLDevices; + + if (err) { + // \todo: record the error string and any other information. + return nullptr; + } + + // Create the OpenCL interoperability kernel + auto CLKernel = clCreateKernel(CLProgram, KernelName, &err); + if (err) { + // \todo: record the error string and any other information. + return nullptr; + } + auto SyclKernel = new kernel(CLKernel, *SyclCtx); + return wrap_kernel(SyclKernel); +} + +__dppl_give const char* +DPPLKernel_GetFunctionName (__dppl_keep const DPPLSyclKernelRef Kernel) +{ + auto SyclKernel = unwrap_kernel(Kernel); + auto kernel_name = SyclKernel->get_info(); + if(kernel_name.empty()) + return nullptr; + auto cstr_name = new char [kernel_name.length()+1]; + std::strcpy (cstr_name, kernel_name.c_str()); + return cstr_name; +} + +size_t +DPPLKernel_GetNumArgs (__dppl_keep const DPPLSyclKernelRef Kernel) +{ + auto SyclKernel = unwrap_kernel(Kernel); + auto num_args = SyclKernel->get_info(); + return (size_t)num_args; +} + +void +DPPLKernel_DeleteKernelRef (__dppl_take DPPLSyclKernelRef Kernel) +{ + delete unwrap_kernel(Kernel); +} + + From 6e246fb11723fef219a585571604a1b510a5ac6e Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Thu, 17 Sep 2020 10:30:21 +0300 Subject: [PATCH 15/41] Update backends/source/dppl_utils.cpp New line at EOF. --- backends/source/dppl_utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/source/dppl_utils.cpp b/backends/source/dppl_utils.cpp index f9c7460f73..39006153ae 100644 --- a/backends/source/dppl_utils.cpp +++ b/backends/source/dppl_utils.cpp @@ -28,4 +28,4 @@ void DPPLDeleteCString (__dppl_take const char* str) { delete str; -} \ No newline at end of file +} From abcf6f3f4bba0add91ed46030d24fa8265a660fe Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Thu, 17 Sep 2020 13:25:54 +0300 Subject: [PATCH 16/41] Add _sycl_core.pxd file. --- dppl/_memory.pyx | 3 ++- dppl/_sycl_core.pxd | 43 +++++++++++++++++++++++++++++++++++++++++++ dppl/sycl_core.pyx | 1 - 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 dppl/_sycl_core.pxd diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index 4d6639a0c4..052bf44d37 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -1,4 +1,5 @@ import dppl +cimport dppl._sycl_core from cython.operator cimport dereference as deref @@ -66,7 +67,7 @@ cdef class Memory: cdef object queue_cap def __cinit__(self, Py_ssize_t nbytes): - cdef object q_cap + cdef dppl._sycl_core.SyclQueue q_cap cdef void* queue_ptr cdef void* p diff --git a/dppl/_sycl_core.pxd b/dppl/_sycl_core.pxd new file mode 100644 index 0000000000..9f62a13124 --- /dev/null +++ b/dppl/_sycl_core.pxd @@ -0,0 +1,43 @@ +##===------------- sycl_core.pxd - DPPL interface ------*- Cython -*-------===## +## +## Python Data Parallel Processing Library (PyDPPL) +## +## 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 +## This file defines the Cython interface for the Sycl API of PyDPPL. +## +##===----------------------------------------------------------------------===## + +cdef extern from "dppl_sycl_types.h": + cdef struct DPPLOpaqueSyclQueue + + ctypedef DPPLOpaqueSyclQueue* DPPLSyclQueueRef + + +cdef class SyclQueue: + ''' Wrapper class for a Sycl queue. + ''' + + cdef DPPLSyclQueueRef queue_ptr + + @staticmethod + cdef SyclQueue _create (DPPLSyclQueueRef qref) + cpdef get_sycl_context (self) + cpdef get_sycl_device (self) + cdef DPPLSyclQueueRef get_queue_ref (self) + diff --git a/dppl/sycl_core.pyx b/dppl/sycl_core.pyx index 1ed47334df..96993eea05 100644 --- a/dppl/sycl_core.pyx +++ b/dppl/sycl_core.pyx @@ -178,7 +178,6 @@ cdef class SyclDevice: cdef class SyclQueue: ''' Wrapper class for a Sycl queue. ''' - cdef DPPLSyclQueueRef queue_ptr @staticmethod cdef SyclQueue _create (DPPLSyclQueueRef qref): From 039b79453df85f8fe878fffaf3951f94c7ff8ddb Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Thu, 17 Sep 2020 13:39:06 +0300 Subject: [PATCH 17/41] Remove using of PyCapsule in _memory.pyx. --- dppl/_memory.pyx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index 052bf44d37..66b3303293 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -3,7 +3,6 @@ cimport dppl._sycl_core from cython.operator cimport dereference as deref -from cpython.pycapsule cimport PyCapsule_GetPointer from cpython cimport Py_buffer cdef extern from "CL/sycl.hpp" namespace "cl::sycl::usm": @@ -27,13 +26,13 @@ cdef extern from "CL/sycl.hpp" namespace "cl::sycl": cdef class SyclQueue: - cdef object queue_cap + cdef dppl._sycl_core.SyclQueue queue_cap cdef queue q def __cinit__(self): cdef void* q_ptr self.queue_cap = dppl.get_current_queue() - q_ptr = PyCapsule_GetPointer(self.queue_cap, NULL) + q_ptr = self.queue_cap.get_queue_ref() if (q_ptr): self.q = deref(q_ptr) else: @@ -64,7 +63,7 @@ cdef class SyclQueue: cdef class Memory: cdef void* _ptr cdef Py_ssize_t nbytes - cdef object queue_cap + cdef dppl._sycl_core.SyclQueue queue_cap def __cinit__(self, Py_ssize_t nbytes): cdef dppl._sycl_core.SyclQueue q_cap @@ -77,7 +76,7 @@ cdef class Memory: if (nbytes > 0): q_cap = dppl.get_current_queue() - queue_ptr = PyCapsule_GetPointer(q_cap, NULL) + queue_ptr = q_cap.get_queue_ref() p = malloc_shared(nbytes, deref(queue_ptr)) if (p): self._ptr = p @@ -92,7 +91,7 @@ cdef class Memory: cdef void* queue_ptr if (self._ptr): - queue_ptr = PyCapsule_GetPointer(self.queue_cap, NULL) + queue_ptr = self.queue_cap.get_queue_ref() free(self._ptr, deref(queue_ptr)) self._ptr = NULL self.nbytes = 0 @@ -129,9 +128,10 @@ cdef class Memory: def _usm_type(self, qcaps=None): cdef void *q_ptr cdef alloc ptr_type + cdef dppl._sycl_core.SyclQueue _cap _cap = qcaps if (qcaps) else self.queue_cap - q_ptr = PyCapsule_GetPointer(_cap, NULL) + q_ptr = _cap.get_queue_ref() ptr_type = get_pointer_type(self._ptr, deref(q_ptr).get_context()) if (ptr_type == alloc.shared): return "shared" From dc72b03666601c8076bc63f8ddc0fc8a7867d1b2 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Thu, 17 Sep 2020 13:40:40 +0300 Subject: [PATCH 18/41] Small style fixes in _memory.pyx. --- dppl/_memory.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index 66b3303293..70f0e0b491 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -73,7 +73,7 @@ cdef class Memory: self._ptr = NULL self.queue_cap = None self.nbytes = 0 - + if (nbytes > 0): q_cap = dppl.get_current_queue() queue_ptr = q_cap.get_queue_ref() @@ -96,7 +96,7 @@ cdef class Memory: self._ptr = NULL self.nbytes = 0 self.queue_cap = None - + def __getbuffer__(self, Py_buffer *buffer, int flags): buffer.buf = self._ptr buffer.format = 'B' # byte From b5ab5d600ee150bb5630381f1097c3dceaa3944a Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Thu, 17 Sep 2020 17:54:01 +0300 Subject: [PATCH 19/41] Moved functions from _memory.pyx to C-API interface library. --- backends/include/dppl_sycl_types.h | 6 ++ backends/include/dppl_sycl_usm_interface.h | 22 ++++++- backends/source/dppl_sycl_usm_interface.cpp | 26 ++++++++ dppl/_memory.pyx | 70 +++++++++++---------- 4 files changed, 91 insertions(+), 33 deletions(-) diff --git a/backends/include/dppl_sycl_types.h b/backends/include/dppl_sycl_types.h index d1777aae5d..db61bfb677 100644 --- a/backends/include/dppl_sycl_types.h +++ b/backends/include/dppl_sycl_types.h @@ -55,3 +55,9 @@ typedef struct DPPLOpaqueSyclQueue *DPPLSyclQueueRef; * */ typedef struct DPPLOpaqueSyclProgram *DPPLSyclProgramRef; + +/*! + * @brief + * + */ +typedef struct DPPLOpaqueMemoryUSMShared *DPPLMemoryUSMSharedRef; diff --git a/backends/include/dppl_sycl_usm_interface.h b/backends/include/dppl_sycl_usm_interface.h index 94d3ca46be..10783f8a89 100644 --- a/backends/include/dppl_sycl_usm_interface.h +++ b/backends/include/dppl_sycl_usm_interface.h @@ -19,14 +19,34 @@ //===----------------------------------------------------------------------===// /// /// \file -/// TODO +/// This header declares a C interface to sycl::usm interface functions. /// //===----------------------------------------------------------------------===// #pragma once +#include "dppl_data_types.h" +#include "dppl_sycl_types.h" +#include "Support/DllExport.h" #include "Support/ExternC.h" +#include "Support/MemOwnershipAttrs.h" DPPL_C_EXTERN_C_BEGIN +/*! + * @brief Crete USM shared memory. + * + * @return The pointer to USM shared memory. + */ +DPPL_API +__dppl_give DPPLMemoryUSMSharedRef +DPPLmalloc_shared (size_t size, __dppl_keep const DPPLSyclQueueRef QRef); + +/*! + * @brief Free USM memory. + * + */ +DPPL_API +void DPPLfree (__dppl_take DPPLMemoryUSMSharedRef MRef, __dppl_keep const DPPLSyclQueueRef QRef); + DPPL_C_EXTERN_C_END diff --git a/backends/source/dppl_sycl_usm_interface.cpp b/backends/source/dppl_sycl_usm_interface.cpp index 974f8c0ad6..06f0d71b3e 100644 --- a/backends/source/dppl_sycl_usm_interface.cpp +++ b/backends/source/dppl_sycl_usm_interface.cpp @@ -22,8 +22,34 @@ /// TODO /// //===----------------------------------------------------------------------===// + #include "dppl_sycl_usm_interface.h" +#include "Support/CBindingWrapping.h" #include /* SYCL headers */ using namespace cl::sycl; + +// TODO: move it to one header for not duplicate in many cpp files +namespace +{ +// Create wrappers for C Binding types (see CBindingWrapping.h). + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(void, DPPLMemoryUSMSharedRef) + +} /* end of anonymous namespace */ + +__dppl_give DPPLMemoryUSMSharedRef +DPPLmalloc_shared (size_t size, __dppl_keep const DPPLSyclQueueRef QRef) +{ + auto Q = unwrap(QRef); + auto Ptr = malloc_shared(size, *Q); + return reinterpret_cast(Ptr); +} + +void DPPLfree (DPPLMemoryUSMSharedRef MRef, __dppl_keep const DPPLSyclQueueRef QRef) +{ + auto Ptr = unwrap(MRef); + auto Q = unwrap(QRef); + free(Ptr, *Q); +} diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index 70f0e0b491..93267fe290 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -20,19 +20,30 @@ cdef extern from "CL/sycl.hpp" namespace "cl::sycl": context get_context() nogil pass - cdef void* malloc_shared(Py_ssize_t, queue&) nogil - cdef void free(void *, queue&) nogil cdef alloc get_pointer_type(void *, context&) nogil +cdef extern from "dppl_sycl_types.h": + cdef struct DPPLOpaqueSyclQueue + cdef struct DPPLOpaqueMemoryUSMShared + + ctypedef DPPLOpaqueSyclQueue* DPPLSyclQueueRef + ctypedef DPPLOpaqueMemoryUSMShared* DPPLMemoryUSMSharedRef + + +cdef extern from "dppl_sycl_usm_interface.h": + cdef DPPLMemoryUSMSharedRef DPPLmalloc_shared (size_t size, DPPLSyclQueueRef QRef) except + + cdef void DPPLfree (DPPLMemoryUSMSharedRef MRef, DPPLSyclQueueRef QRef) except + + + cdef class SyclQueue: - cdef dppl._sycl_core.SyclQueue queue_cap + cdef dppl._sycl_core.SyclQueue queue cdef queue q def __cinit__(self): cdef void* q_ptr - self.queue_cap = dppl.get_current_queue() - q_ptr = self.queue_cap.get_queue_ref() + self.queue = dppl.get_current_queue() + q_ptr = self.queue.get_queue_ref() if (q_ptr): self.q = deref(q_ptr) else: @@ -54,48 +65,43 @@ cdef class SyclQueue: property get_capsule: def __get__(self): - return self.queue_cap + return self.queue cdef queue get_queue(self): return self.q cdef class Memory: - cdef void* _ptr + cdef DPPLMemoryUSMSharedRef _ptr cdef Py_ssize_t nbytes - cdef dppl._sycl_core.SyclQueue queue_cap + cdef dppl._sycl_core.SyclQueue queue def __cinit__(self, Py_ssize_t nbytes): - cdef dppl._sycl_core.SyclQueue q_cap - cdef void* queue_ptr - cdef void* p + cdef dppl._sycl_core.SyclQueue q + cdef DPPLMemoryUSMSharedRef p self._ptr = NULL - self.queue_cap = None + self.queue = None self.nbytes = 0 if (nbytes > 0): - q_cap = dppl.get_current_queue() - queue_ptr = q_cap.get_queue_ref() - p = malloc_shared(nbytes, deref(queue_ptr)) + q = dppl.get_current_queue() + p = DPPLmalloc_shared(nbytes, q.get_queue_ref()) if (p): self._ptr = p self.nbytes = nbytes - self.queue_cap = q_cap + self.queue = q else: raise RuntimeError("Null memory pointer returned") else: raise ValueError("Non-positive number of bytes found.") def __dealloc__(self): - cdef void* queue_ptr - if (self._ptr): - queue_ptr = self.queue_cap.get_queue_ref() - free(self._ptr, deref(queue_ptr)) + DPPLfree(self._ptr, self.queue.get_queue_ref()) self._ptr = NULL self.nbytes = 0 - self.queue_cap = None + self.queue = None def __getbuffer__(self, Py_buffer *buffer, int flags): buffer.buf = self._ptr @@ -120,7 +126,7 @@ cdef class Memory: property _queue: def __get__(self): - return self.queue_cap + return self.queue def __repr__(self): return "".format(self.nbytes, hex((self._ptr))) @@ -130,7 +136,7 @@ cdef class Memory: cdef alloc ptr_type cdef dppl._sycl_core.SyclQueue _cap - _cap = qcaps if (qcaps) else self.queue_cap + _cap = qcaps if (qcaps) else self.queue q_ptr = _cap.get_queue_ref() ptr_type = get_pointer_type(self._ptr, deref(q_ptr).get_context()) if (ptr_type == alloc.shared): @@ -144,12 +150,12 @@ cdef class Memory: # cdef void* _ptr # cdef Py_ssize_t nbytes -# cdef object queue_cap - - @staticmethod - cdef Memory create(void *p, Py_ssize_t nbytes, object queue_cap): - cdef Memory ret = Memory.__new__() - ret._ptr = p - ret.nbytes = nbytes - ret.q_cap = queue_cap - return ret +# cdef object queue + + # @staticmethod + # cdef Memory create(void *p, Py_ssize_t nbytes, object queue): + # cdef Memory ret = Memory.__new__() + # ret._ptr = p + # ret.nbytes = nbytes + # ret.q_cap = queue + # return ret From c57c05c07dc26158210601334fa9e6f5e9d21e74 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Thu, 17 Sep 2020 22:53:48 +0300 Subject: [PATCH 20/41] Move Cython definitions for backend to single pxd file. --- dppl/_memory.pyx | 14 +------ dppl/_sycl_core.pxd | 32 +++++++++++---- dppl/backend.pxd | 99 +++++++++++++++++++++++++++++++++++++++++++++ dppl/sycl_core.pyx | 75 +++------------------------------- 4 files changed, 130 insertions(+), 90 deletions(-) create mode 100644 dppl/backend.pxd diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index 93267fe290..4b1a3f9ef6 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -1,4 +1,5 @@ import dppl +from dppl.backend cimport * cimport dppl._sycl_core from cython.operator cimport dereference as deref @@ -23,19 +24,6 @@ cdef extern from "CL/sycl.hpp" namespace "cl::sycl": cdef alloc get_pointer_type(void *, context&) nogil -cdef extern from "dppl_sycl_types.h": - cdef struct DPPLOpaqueSyclQueue - cdef struct DPPLOpaqueMemoryUSMShared - - ctypedef DPPLOpaqueSyclQueue* DPPLSyclQueueRef - ctypedef DPPLOpaqueMemoryUSMShared* DPPLMemoryUSMSharedRef - - -cdef extern from "dppl_sycl_usm_interface.h": - cdef DPPLMemoryUSMSharedRef DPPLmalloc_shared (size_t size, DPPLSyclQueueRef QRef) except + - cdef void DPPLfree (DPPLMemoryUSMSharedRef MRef, DPPLSyclQueueRef QRef) except + - - cdef class SyclQueue: cdef dppl._sycl_core.SyclQueue queue cdef queue q diff --git a/dppl/_sycl_core.pxd b/dppl/_sycl_core.pxd index 9f62a13124..c4b8dd2ab1 100644 --- a/dppl/_sycl_core.pxd +++ b/dppl/_sycl_core.pxd @@ -23,21 +23,39 @@ ## ##===----------------------------------------------------------------------===## -cdef extern from "dppl_sycl_types.h": - cdef struct DPPLOpaqueSyclQueue +from .backend cimport * - ctypedef DPPLOpaqueSyclQueue* DPPLSyclQueueRef + +cdef class SyclContext: + ''' Wrapper class for a Sycl Context + ''' + cdef DPPLSyclContextRef ctxt_ptr + + @staticmethod + cdef SyclContext _create (DPPLSyclContextRef ctxt) + cdef DPPLSyclContextRef get_context_ref (self) + + +cdef class SyclDevice: + ''' Wrapper class for a Sycl Device + ''' + cdef DPPLSyclDeviceRef device_ptr + cdef const char *vendor_name + cdef const char *device_name + cdef const char *driver_version + + @staticmethod + cdef SyclDevice _create (DPPLSyclDeviceRef dref) + cdef DPPLSyclDeviceRef get_device_ptr (self) cdef class SyclQueue: ''' Wrapper class for a Sycl queue. ''' - cdef DPPLSyclQueueRef queue_ptr @staticmethod cdef SyclQueue _create (DPPLSyclQueueRef qref) - cpdef get_sycl_context (self) - cpdef get_sycl_device (self) + cpdef SyclContext get_sycl_context (self) + cpdef SyclDevice get_sycl_device (self) cdef DPPLSyclQueueRef get_queue_ref (self) - diff --git a/dppl/backend.pxd b/dppl/backend.pxd new file mode 100644 index 0000000000..23165c44fa --- /dev/null +++ b/dppl/backend.pxd @@ -0,0 +1,99 @@ +##===------------- backend.pyx - DPPL interface ------*- Cython -*-------===## +## +## Python Data Parallel Processing Library (PyDPPL) +## +## 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 +## This file defines the Cython interface for the backend API of PyDPPL. +## +##===----------------------------------------------------------------------===## + +from libcpp cimport bool + + +cdef extern from "dppl_utils.h": + cdef void DPPLDeleteCString (const char *str) + + +cdef extern from "dppl_sycl_types.h": + cdef struct DPPLOpaqueSyclContext + cdef struct DPPLOpaqueSyclQueue + cdef struct DPPLOpaqueSyclDevice + cdef struct DPPLOpaqueMemoryUSMShared + + ctypedef DPPLOpaqueSyclContext* DPPLSyclContextRef + ctypedef DPPLOpaqueSyclQueue* DPPLSyclQueueRef + ctypedef DPPLOpaqueSyclDevice* DPPLSyclDeviceRef + ctypedef DPPLOpaqueMemoryUSMShared* DPPLMemoryUSMSharedRef + + +cdef extern from "dppl_sycl_context_interface.h": + cdef void DPPLDeleteSyclContext (DPPLSyclContextRef CtxtRef) except + + + +cdef extern from "dppl_sycl_device_interface.h": + cdef void DPPLDumpDeviceInfo (const DPPLSyclDeviceRef DRef) except + + cdef void DPPLDeleteSyclDevice (DPPLSyclDeviceRef DRef) except + + cdef void DPPLDumpDeviceInfo (const DPPLSyclDeviceRef DRef) except + + cdef bool DPPLDeviceIsAccelerator (const DPPLSyclDeviceRef DRef) except + + cdef bool DPPLDeviceIsCPU (const DPPLSyclDeviceRef DRef) except + + cdef bool DPPLDeviceIsGPU (const DPPLSyclDeviceRef DRef) except + + cdef bool DPPLDeviceIsHost (const DPPLSyclDeviceRef DRef) except + + cdef const char* DPPLGetDeviceDriverInfo (const DPPLSyclDeviceRef DRef) \ + except + + cdef const char* DPPLGetDeviceName (const DPPLSyclDeviceRef DRef) except + + cdef const char* DPPLGetDeviceVendorName (const DPPLSyclDeviceRef DRef) \ + except + + cdef bool DPPLGetDeviceHostUnifiedMemory (const DPPLSyclDeviceRef DRef) \ + except + + + +cdef extern from "dppl_sycl_platform_interface.h": + cdef size_t DPPLPlatform_GetNumPlatforms () + cdef void DPPLPlatform_DumpInfo () + + +cdef extern from "dppl_sycl_queue_interface.h": + cdef void DPPLDeleteSyclQueue (DPPLSyclQueueRef QRef) except + + cdef DPPLSyclContextRef DPPLGetContextFromQueue (const DPPLSyclQueueRef Q) \ + except+ + cdef DPPLSyclDeviceRef DPPLGetDeviceFromQueue (const DPPLSyclQueueRef Q) \ + except + + + +cdef extern from "dppl_sycl_queue_manager.h": + cdef enum _device_type 'DPPLSyclDeviceType': + _GPU 'DPPL_GPU' + _CPU 'DPPL_CPU' + + cdef DPPLSyclQueueRef DPPLGetCurrentQueue () except + + cdef size_t DPPLGetNumCPUQueues () except + + cdef size_t DPPLGetNumGPUQueues () except + + cdef size_t DPPLGetNumActivatedQueues () except + + cdef DPPLSyclQueueRef DPPLGetQueue (_device_type DTy, + size_t device_num) except + + cdef void DPPLPopSyclQueue () except + + cdef DPPLSyclQueueRef DPPLPushSyclQueue (_device_type DTy, + size_t device_num) except + + cdef void DPPLSetAsDefaultQueue (_device_type DTy, + size_t device_num) except + + + +cdef extern from "dppl_sycl_usm_interface.h": + cdef DPPLMemoryUSMSharedRef DPPLmalloc_shared (size_t size, DPPLSyclQueueRef QRef) except + + cdef void DPPLfree (DPPLMemoryUSMSharedRef MRef, DPPLSyclQueueRef QRef) except + diff --git a/dppl/sycl_core.pyx b/dppl/sycl_core.pyx index 96993eea05..5df3af4367 100644 --- a/dppl/sycl_core.pyx +++ b/dppl/sycl_core.pyx @@ -29,10 +29,12 @@ from __future__ import print_function from enum import Enum, auto import logging -from libcpp cimport bool +from dppl.backend cimport * + _logger = logging.getLogger(__name__) + class device_type(Enum): gpu = auto() cpu = auto() @@ -44,71 +46,8 @@ cdef class UnsupportedDeviceTypeError(Exception): ''' pass -cdef extern from "dppl_utils.h": - cdef void DPPLDeleteCString (const char *str) - -cdef extern from "dppl_sycl_types.h": - cdef struct DPPLOpaqueSyclContext: - pass - cdef struct DPPLOpaqueSyclQueue: - pass - cdef struct DPPLOpaqueSyclDevice: - pass - - ctypedef DPPLOpaqueSyclContext* DPPLSyclContextRef - ctypedef DPPLOpaqueSyclQueue* DPPLSyclQueueRef - ctypedef DPPLOpaqueSyclDevice* DPPLSyclDeviceRef - -cdef extern from "dppl_sycl_context_interface.h": - cdef void DPPLDeleteSyclContext (DPPLSyclContextRef CtxtRef) except + - -cdef extern from "dppl_sycl_device_interface.h": - cdef void DPPLDumpDeviceInfo (const DPPLSyclDeviceRef DRef) except + - cdef void DPPLDeleteSyclDevice (DPPLSyclDeviceRef DRef) except + - cdef void DPPLDumpDeviceInfo (const DPPLSyclDeviceRef DRef) except + - cdef bool DPPLDeviceIsAccelerator (const DPPLSyclDeviceRef DRef) except + - cdef bool DPPLDeviceIsCPU (const DPPLSyclDeviceRef DRef) except + - cdef bool DPPLDeviceIsGPU (const DPPLSyclDeviceRef DRef) except + - cdef bool DPPLDeviceIsHost (const DPPLSyclDeviceRef DRef) except + - cdef const char* DPPLGetDeviceDriverInfo (const DPPLSyclDeviceRef DRef) \ - except + - cdef const char* DPPLGetDeviceName (const DPPLSyclDeviceRef DRef) except + - cdef const char* DPPLGetDeviceVendorName (const DPPLSyclDeviceRef DRef) \ - except + - cdef bool DPPLGetDeviceHostUnifiedMemory (const DPPLSyclDeviceRef DRef) \ - except + - -cdef extern from "dppl_sycl_platform_interface.h": - cdef size_t DPPLPlatform_GetNumPlatforms () - cdef void DPPLPlatform_DumpInfo () - -cdef extern from "dppl_sycl_queue_interface.h": - cdef void DPPLDeleteSyclQueue (DPPLSyclQueueRef QRef) except + - cdef DPPLSyclContextRef DPPLGetContextFromQueue (const DPPLSyclQueueRef Q) \ - except+ - cdef DPPLSyclDeviceRef DPPLGetDeviceFromQueue (const DPPLSyclQueueRef Q) \ - except + - -cdef extern from "dppl_sycl_queue_manager.h": - cdef enum _device_type 'DPPLSyclDeviceType': - _GPU 'DPPL_GPU' - _CPU 'DPPL_CPU' - - cdef DPPLSyclQueueRef DPPLGetCurrentQueue () except + - cdef size_t DPPLGetNumCPUQueues () except + - cdef size_t DPPLGetNumGPUQueues () except + - cdef size_t DPPLGetNumActivatedQueues () except + - cdef DPPLSyclQueueRef DPPLGetQueue (_device_type DTy, - size_t device_num) except + - cdef void DPPLPopSyclQueue () except + - cdef DPPLSyclQueueRef DPPLPushSyclQueue (_device_type DTy, - size_t device_num) except + - cdef void DPPLSetAsDefaultQueue (_device_type DTy, - size_t device_num) except + - cdef class SyclContext: - cdef DPPLSyclContextRef ctxt_ptr @staticmethod cdef SyclContext _create (DPPLSyclContextRef ctxt): @@ -126,10 +65,6 @@ cdef class SyclContext: cdef class SyclDevice: ''' Wrapper class for a Sycl Device ''' - cdef DPPLSyclDeviceRef device_ptr - cdef const char *vendor_name - cdef const char *device_name - cdef const char *driver_version @staticmethod cdef SyclDevice _create (DPPLSyclDeviceRef dref): @@ -188,10 +123,10 @@ cdef class SyclQueue: def __dealloc__ (self): DPPLDeleteSyclQueue(self.queue_ptr) - cpdef get_sycl_context (self): + cpdef SyclContext get_sycl_context (self): return SyclContext._create(DPPLGetContextFromQueue(self.queue_ptr)) - cpdef get_sycl_device (self): + cpdef SyclDevice get_sycl_device (self): return SyclDevice._create(DPPLGetDeviceFromQueue(self.queue_ptr)) cdef DPPLSyclQueueRef get_queue_ref (self): From c075f0c9dbae1ae3030cc00b47bd68d03232856a Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Thu, 17 Sep 2020 23:06:23 +0300 Subject: [PATCH 21/41] Remove SyclQueue from _memory.pyx --- dppl/_memory.pyx | 35 ------------------- .../dppl_tests/test_sycl_memory_manager.py | 3 -- 2 files changed, 38 deletions(-) diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index 4b1a3f9ef6..464dcb25e0 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -24,41 +24,6 @@ cdef extern from "CL/sycl.hpp" namespace "cl::sycl": cdef alloc get_pointer_type(void *, context&) nogil -cdef class SyclQueue: - cdef dppl._sycl_core.SyclQueue queue - cdef queue q - - def __cinit__(self): - cdef void* q_ptr - self.queue = dppl.get_current_queue() - q_ptr = self.queue.get_queue_ref() - if (q_ptr): - self.q = deref(q_ptr) - else: - raise ValueError("NULL pointer returned by the Capsule") - - def get_pointer_type(self, Py_ssize_t p): - cdef context ctx = self.q.get_context() - cdef void * p_ptr = p - - ptr_type = get_pointer_type(p_ptr, ctx) - if (ptr_type == alloc.shared): - return "shared" - elif (ptr_type == alloc.host): - return "host" - elif (ptr_type == alloc.device): - return "device" - else: - return "unknown" - - property get_capsule: - def __get__(self): - return self.queue - - cdef queue get_queue(self): - return self.q - - cdef class Memory: cdef DPPLMemoryUSMSharedRef _ptr cdef Py_ssize_t nbytes diff --git a/dppl/tests/dppl_tests/test_sycl_memory_manager.py b/dppl/tests/dppl_tests/test_sycl_memory_manager.py index 95051310db..7d0ea24aaa 100644 --- a/dppl/tests/dppl_tests/test_sycl_memory_manager.py +++ b/dppl/tests/dppl_tests/test_sycl_memory_manager.py @@ -39,7 +39,6 @@ def test_memory_without_context (self): mobj = self._create_memory() # Without context - self.assertEqual(mem.SyclQueue().get_pointer_type(mobj.pointer), 'shared') self.assertEqual(mobj._usm_type(), 'shared') def test_memory_cpu_context (self): @@ -47,7 +46,6 @@ def test_memory_cpu_context (self): # CPU context with dppl.device_context(dppl.device_type.cpu): - self.assertEqual(mem.SyclQueue().get_pointer_type(mobj.pointer), 'unknown') self.assertEqual(mobj._usm_type(), 'shared') def test_memory_gpu_context (self): @@ -55,5 +53,4 @@ def test_memory_gpu_context (self): # GPU context with dppl.device_context(dppl.device_type.gpu): - self.assertEqual(mem.SyclQueue().get_pointer_type(mobj.pointer), 'unknown') self.assertEqual(mobj._usm_type(), 'shared') From 708fd1f4679cac6040431554a128be938ff1dcf5 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Thu, 17 Sep 2020 23:10:59 +0300 Subject: [PATCH 22/41] Use SyclQueue from --- dppl/_memory.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index 464dcb25e0..0e9cf72475 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -1,6 +1,6 @@ import dppl from dppl.backend cimport * -cimport dppl._sycl_core +from ._sycl_core cimport SyclQueue from cython.operator cimport dereference as deref @@ -27,10 +27,10 @@ cdef extern from "CL/sycl.hpp" namespace "cl::sycl": cdef class Memory: cdef DPPLMemoryUSMSharedRef _ptr cdef Py_ssize_t nbytes - cdef dppl._sycl_core.SyclQueue queue + cdef SyclQueue queue def __cinit__(self, Py_ssize_t nbytes): - cdef dppl._sycl_core.SyclQueue q + cdef SyclQueue q cdef DPPLMemoryUSMSharedRef p self._ptr = NULL @@ -87,7 +87,7 @@ cdef class Memory: def _usm_type(self, qcaps=None): cdef void *q_ptr cdef alloc ptr_type - cdef dppl._sycl_core.SyclQueue _cap + cdef SyclQueue _cap _cap = qcaps if (qcaps) else self.queue q_ptr = _cap.get_queue_ref() From 5d3db207cf981dfcc75fb134b32b3651229266d8 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Thu, 17 Sep 2020 23:43:18 +0300 Subject: [PATCH 23/41] Remove cl::sycl::queue from _memory.pyx --- dppl/_memory.pyx | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index 0e9cf72475..a9ec79405e 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -14,18 +14,13 @@ cdef extern from "CL/sycl.hpp" namespace "cl::sycl::usm": unknown 'cl::sycl::usm::alloc::unknown' cdef extern from "CL/sycl.hpp" namespace "cl::sycl": - cdef cppclass context nogil: - pass - - cdef cppclass queue nogil: - context get_context() nogil - pass + cdef cppclass context nogil cdef alloc get_pointer_type(void *, context&) nogil cdef class Memory: - cdef DPPLMemoryUSMSharedRef _ptr + cdef DPPLMemoryUSMSharedRef memory_ptr cdef Py_ssize_t nbytes cdef SyclQueue queue @@ -33,7 +28,7 @@ cdef class Memory: cdef SyclQueue q cdef DPPLMemoryUSMSharedRef p - self._ptr = NULL + self.memory_ptr = NULL self.queue = None self.nbytes = 0 @@ -41,7 +36,7 @@ cdef class Memory: q = dppl.get_current_queue() p = DPPLmalloc_shared(nbytes, q.get_queue_ref()) if (p): - self._ptr = p + self.memory_ptr = p self.nbytes = nbytes self.queue = q else: @@ -50,14 +45,14 @@ cdef class Memory: raise ValueError("Non-positive number of bytes found.") def __dealloc__(self): - if (self._ptr): - DPPLfree(self._ptr, self.queue.get_queue_ref()) - self._ptr = NULL + if (self.memory_ptr): + DPPLfree(self.memory_ptr, self.queue.get_queue_ref()) + self.memory_ptr = NULL self.nbytes = 0 self.queue = None def __getbuffer__(self, Py_buffer *buffer, int flags): - buffer.buf = self._ptr + buffer.buf = self.memory_ptr buffer.format = 'B' # byte buffer.internal = NULL # see References buffer.itemsize = 1 @@ -71,7 +66,7 @@ cdef class Memory: property pointer: def __get__(self): - return (self._ptr) + return (self.memory_ptr) property nbytes: def __get__(self): @@ -82,16 +77,14 @@ cdef class Memory: return self.queue def __repr__(self): - return "".format(self.nbytes, hex((self._ptr))) + return "".format(self.nbytes, hex((self.memory_ptr))) - def _usm_type(self, qcaps=None): - cdef void *q_ptr + def _usm_type(self): + cdef DPPLSyclContextRef ctx_ptr cdef alloc ptr_type - cdef SyclQueue _cap - _cap = qcaps if (qcaps) else self.queue - q_ptr = _cap.get_queue_ref() - ptr_type = get_pointer_type(self._ptr, deref(q_ptr).get_context()) + ctx_ptr = self.queue.get_sycl_context().get_context_ref() + ptr_type = get_pointer_type(self.memory_ptr, deref(ctx_ptr)) if (ptr_type == alloc.shared): return "shared" elif (ptr_type == alloc.host): @@ -101,14 +94,10 @@ cdef class Memory: else: return "unknown" -# cdef void* _ptr -# cdef Py_ssize_t nbytes -# cdef object queue - # @staticmethod # cdef Memory create(void *p, Py_ssize_t nbytes, object queue): # cdef Memory ret = Memory.__new__() - # ret._ptr = p + # ret.memory_ptr = p # ret.nbytes = nbytes # ret.q_cap = queue # return ret From 6747080044a62e6d2a3747e585525cdb88c878fd Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Thu, 17 Sep 2020 23:46:36 +0300 Subject: [PATCH 24/41] Removed commented code from _memory.pyx --- dppl/_memory.pyx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index a9ec79405e..28b5738008 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -93,11 +93,3 @@ cdef class Memory: return "device" else: return "unknown" - - # @staticmethod - # cdef Memory create(void *p, Py_ssize_t nbytes, object queue): - # cdef Memory ret = Memory.__new__() - # ret.memory_ptr = p - # ret.nbytes = nbytes - # ret.q_cap = queue - # return ret From 56241ef88e352b3347bdcee6c0827a313ec46052 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Fri, 18 Sep 2020 00:03:29 +0300 Subject: [PATCH 25/41] Eliminate temporary context object. --- dppl/_memory.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index 28b5738008..fb5b3c9c42 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -1,6 +1,6 @@ import dppl from dppl.backend cimport * -from ._sycl_core cimport SyclQueue +from ._sycl_core cimport SyclContext, SyclQueue from cython.operator cimport dereference as deref @@ -80,11 +80,11 @@ cdef class Memory: return "".format(self.nbytes, hex((self.memory_ptr))) def _usm_type(self): - cdef DPPLSyclContextRef ctx_ptr + cdef SyclContext ctxt cdef alloc ptr_type - ctx_ptr = self.queue.get_sycl_context().get_context_ref() - ptr_type = get_pointer_type(self.memory_ptr, deref(ctx_ptr)) + ctxt = self.queue.get_sycl_context() + ptr_type = get_pointer_type(self.memory_ptr, deref(ctxt.get_context_ref())) if (ptr_type == alloc.shared): return "shared" elif (ptr_type == alloc.host): From 7fabbe4a972ed83a2b7cfb9d9db8a93f163c075d Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Fri, 18 Sep 2020 00:06:00 +0300 Subject: [PATCH 26/41] Fix style. --- backends/include/dppl_sycl_usm_interface.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backends/include/dppl_sycl_usm_interface.h b/backends/include/dppl_sycl_usm_interface.h index 10783f8a89..26a609e546 100644 --- a/backends/include/dppl_sycl_usm_interface.h +++ b/backends/include/dppl_sycl_usm_interface.h @@ -47,6 +47,7 @@ DPPLmalloc_shared (size_t size, __dppl_keep const DPPLSyclQueueRef QRef); * */ DPPL_API -void DPPLfree (__dppl_take DPPLMemoryUSMSharedRef MRef, __dppl_keep const DPPLSyclQueueRef QRef); +void DPPLfree (__dppl_take DPPLMemoryUSMSharedRef MRef, + __dppl_keep const DPPLSyclQueueRef QRef); DPPL_C_EXTERN_C_END From 7899c0735ef319cf3714314567fc6a12adc6fc86 Mon Sep 17 00:00:00 2001 From: Diptorup Deb Date: Thu, 17 Sep 2020 22:15:30 -0500 Subject: [PATCH 27/41] Add a kernel submission interface. --- backends/include/dppl_sycl_kernel_interface.h | 132 ++++++++++++++- backends/include/dppl_sycl_types.h | 7 + .../source/dppl_sycl_kernel_interface.cpp | 150 +++++++++++++++++- 3 files changed, 282 insertions(+), 7 deletions(-) diff --git a/backends/include/dppl_sycl_kernel_interface.h b/backends/include/dppl_sycl_kernel_interface.h index 3131f9fe0d..0c0ae453c9 100644 --- a/backends/include/dppl_sycl_kernel_interface.h +++ b/backends/include/dppl_sycl_kernel_interface.h @@ -37,6 +37,92 @@ DPPL_C_EXTERN_C_BEGIN +/*! + * @brief Enum of currently support types for kernel arguments. + * + * \todo Add support for sycl::buffer + * + */ +enum DPPLArgTypes +{ + CHAR, + SIGNED_CHAR, + UNSIGNED_CHAR, + SHORT, + INT, + UNSIGNED_INT, + LONG, + UNSIGNED_LONG, + LONG_LONG, + UNSIGNED_LONG_LONG, + SIZE_T, + FLOAT, + DOUBLE, + LONG_DOUBLE, + CHAR_P, + SIGNED_CHAR_P, + UNSIGNED_CHAR_P, + SHORT_P, + INT_P, + UNSIGNED_INT_P, + LONG_P, + UNSIGNED_LONG_P, + LONG_LONG_P, + UNSIGNED_LONG_LONG_P, + SIZE_T_P, + FLOAT_P, + DOUBLE_P, + LONG_DOUBLE_P +}; + +/*! + * @brief A union representing an OpenCL kernel argument that is either a basic + * C type of a pointer of the type. + * + */ +union DPPLArgValue +{ + char char_arg; + signed char schar_arg; + unsigned char uchar_arg; + short short_arg; + int int_arg; + unsigned int uint_arg; + long long_arg; + unsigned long ulong_arg; + long long longlong_arg; + unsigned long long ulonglong_arg; + size_t size_t_arg; + float float_arg; + double double_arg; + long double longdouble_arg; + char *char_p_arg; + signed char *schar_p_arg; + unsigned char *uchar_p_arg; + short *short_p_arg; + int *int_p_arg; + unsigned int *uint_p_arg; + long *long_p_arg; + unsigned long *ulong_p_arg; + long long *longlong_p_arg; + unsigned long long *ulonglong_p_arg; + size_t *size_t_p_arg; + float *float_p_arg; + double *double_p_arg; + long double *longdouble_p_arg; +}; + +/*! + * @brief The tagged union is used to pass through OpenCL kernel arguments to + * Sycl. + * + */ +struct DPPLKernelArg +{ + enum DPPLArgTypes argType; + union DPPLArgValue argVal; +}; + /*! * @brief Create a Sycl Kernel from an OpenCL SPIR-V binary * @@ -65,35 +151,69 @@ DPPLKernel_CreateKernelFromSpirv (__dppl_keep const DPPLSyclContextRef Ctx, /*! * @brief Returns a C string for the kernel name. * - * @param Kernel DPPLSyclKernelRef pointer to an OpenCL + * @param KRef DPPLSyclKernelRef pointer to an OpenCL * interoperability kernel. * @return If a kernel name exists then returns it as a C string, else * returns a nullptr. */ DPPL_API __dppl_give const char* -DPPLKernel_GetFunctionName (__dppl_keep const DPPLSyclKernelRef Kernel); +DPPLKernel_GetFunctionName (__dppl_keep const DPPLSyclKernelRef KRef); /*! * @brief Returns the number of arguments for the OpenCL kernel. * - * @param Kernel DPPLSyclKernelRef pointer to an OpenCL + * @param KRef DPPLSyclKernelRef pointer to an OpenCL * interoperability kernel. * @return Returns the number of arguments for the OpenCL interoperability * kernel. */ DPPL_API size_t -DPPLKernel_GetNumArgs (__dppl_keep const DPPLSyclKernelRef Kernel); +DPPLKernel_GetNumArgs (__dppl_keep const DPPLSyclKernelRef KRef); /*! * @brief Deletes the DPPLSyclKernelRef after casting it to a sycl::kernel. * - * @param Kernel DPPLSyclKernelRef pointer to an OpenCL + * @param KRef DPPLSyclKernelRef pointer to an OpenCL * interoperability kernel. */ DPPL_API void -DPPLKernel_DeleteKernelRef (__dppl_take DPPLSyclKernelRef Kernel); +DPPLKernel_DeleteKernelRef (__dppl_take DPPLSyclKernelRef KRef); + + +/*! + * @brief Submits the kernel to the specified queue using give arguments. + * + * A wrapper over sycl::queue.submit(). The function takes an OpenCL + * interoperability kernel, the kernel arguments, and a sycl queue as input + * arguments. The kernel arguments are passed in as an array of the + * DPPLKernelArg tagged union. + * + * \todo sycl::buffer arguments are not supported yet. + * + * @param KRef Opaque pointer to a OpenCL interoperability kernel + * wrapped inside a sycl::kernel. + * @param QRef Opaque pointer to the sycl::queue where the kernel + * will be enqueued. + * @param Args An array of the DPPLKernelArg tagged union type that + * represents the kernel arguments for the kernel. + * @param NArgs The number of kernel arguments (size of Args array). + * @param Range Array storing the range dimensions that can have a + * maximum size of three. Note the number of values + * in the array depends on the number of dimensions. + * @param NDims Number of dimensions in the range (size of Range). + * @return A opaque pointer to the sycl::event returned by the + * sycl::queue.submit() function. + */ +DPPL_API +DPPLSyclEventRef +DPPLKernel_Submit (__dppl_keep DPPLSyclKernelRef KRef, + __dppl_keep DPPLSyclQueueRef QRef, + __dppl_keep DPPLKernelArg *Args, + size_t NArgs, + size_t Range[3], + size_t NDims); DPPL_C_EXTERN_C_END diff --git a/backends/include/dppl_sycl_types.h b/backends/include/dppl_sycl_types.h index 1bba3de1fb..ef96be64e0 100644 --- a/backends/include/dppl_sycl_types.h +++ b/backends/include/dppl_sycl_types.h @@ -40,6 +40,13 @@ typedef struct DPPLOpaqueSyclContext *DPPLSyclContextRef; */ typedef struct DPPLOpaqueSyclDevice *DPPLSyclDeviceRef; +/*! + * @brief Opaque pointer used to represent references to sycl::event* + * + * @see sycl::event + */ +typedef struct DPPLOpaqueSyclEvent *DPPLSyclEventRef; + /*! * @brief Opaque pointer used to represent references to sycl::kernel* * diff --git a/backends/source/dppl_sycl_kernel_interface.cpp b/backends/source/dppl_sycl_kernel_interface.cpp index 479d501520..33f4c45999 100644 --- a/backends/source/dppl_sycl_kernel_interface.cpp +++ b/backends/source/dppl_sycl_kernel_interface.cpp @@ -34,10 +34,118 @@ using namespace cl::sycl; namespace { -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(kernel, DPPLSyclKernelRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(context, DPPLSyclContextRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(event, DPPLSyclEventRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(kernel, DPPLSyclKernelRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) + +/*! + * @brief Set the kernel arg object + * + * @param cgh My Param doc + * @param Arg My Param doc + */ +bool set_kernel_arg (handler &cgh, __dppl_keep DPPLKernelArg Arg, size_t idx) +{ + bool arg_set = true; + + switch (Arg.argType) + { + case CHAR: + cgh.set_arg(idx, Arg.argVal.char_arg); + break; + case SIGNED_CHAR: + cgh.set_arg(idx, Arg.argVal.schar_arg); + break; + case UNSIGNED_CHAR: + cgh.set_arg(idx, Arg.argVal.uchar_arg); + break; + case SHORT: + cgh.set_arg(idx, Arg.argVal.short_arg); + break; + case INT: + cgh.set_arg(idx, Arg.argVal.int_arg); + break; + case UNSIGNED_INT: + cgh.set_arg(idx, Arg.argVal.uint_arg); + break; + case LONG: + cgh.set_arg(idx, Arg.argVal.long_arg); + break; + case UNSIGNED_LONG: + cgh.set_arg(idx, Arg.argVal.ulong_arg); + break; + case LONG_LONG: + cgh.set_arg(idx, Arg.argVal.longlong_arg); + break; + case UNSIGNED_LONG_LONG: + cgh.set_arg(idx, Arg.argVal.ulonglong_arg); + break; + case SIZE_T: + cgh.set_arg(idx, Arg.argVal.size_t_arg); + break; + case FLOAT: + cgh.set_arg(idx, Arg.argVal.float_arg); + break; + case DOUBLE: + cgh.set_arg(idx, Arg.argVal.double_arg); + break; + case LONG_DOUBLE: + cgh.set_arg(idx, Arg.argVal.longdouble_arg); + break; + case CHAR_P: + cgh.set_arg(idx, Arg.argVal.char_p_arg); + break; + case SIGNED_CHAR_P: + cgh.set_arg(idx, Arg.argVal.schar_p_arg); + break; + case UNSIGNED_CHAR_P: + cgh.set_arg(idx, Arg.argVal.uchar_p_arg); + break; + case SHORT_P: + cgh.set_arg(idx, Arg.argVal.short_p_arg); + break; + case INT_P: + cgh.set_arg(idx, Arg.argVal.int_p_arg); + break; + case UNSIGNED_INT_P: + cgh.set_arg(idx, Arg.argVal.uint_p_arg); + break; + case LONG_P: + cgh.set_arg(idx, Arg.argVal.long_p_arg); + break; + case UNSIGNED_LONG_P: + cgh.set_arg(idx, Arg.argVal.ulong_p_arg); + break; + case LONG_LONG_P: + cgh.set_arg(idx, Arg.argVal.longlong_p_arg); + break; + case UNSIGNED_LONG_LONG_P: + cgh.set_arg(idx, Arg.argVal.ulonglong_p_arg); + break; + case SIZE_T_P: + cgh.set_arg(idx, Arg.argVal.size_t_p_arg); + break; + case FLOAT_P: + cgh.set_arg(idx, Arg.argVal.float_p_arg); + break; + case DOUBLE_P: + cgh.set_arg(idx, Arg.argVal.double_p_arg); + break; + case LONG_DOUBLE_P: + cgh.set_arg(idx, Arg.argVal.longdouble_p_arg); + break; + default: + // \todo handle errors + arg_set = false; + std::cerr << "Kernel argument could not be created.\n"; + break; + } + return arg_set; } +} /* end of anonymous namespace */ + __dppl_give DPPLSyclKernelRef DPPLKernel_CreateKernelFromSpirv (__dppl_keep const DPPLSyclContextRef Ctx, __dppl_keep const void *IL, @@ -108,3 +216,43 @@ DPPLKernel_DeleteKernelRef (__dppl_take DPPLSyclKernelRef Kernel) } +DPPL_API +DPPLSyclEventRef +DPPLKernel_Submit (__dppl_keep DPPLSyclKernelRef KRef, + __dppl_keep DPPLSyclQueueRef QRef, + __dppl_keep DPPLKernelArg *Args, + size_t NArgs, + size_t Range[3], + size_t NDims) +{ + auto Kernel = unwrap_kernel(KRef); + auto Queue = unwrap_queue(QRef); + event e; + + e = Queue->submit([&](handler& cgh) { + for (auto i = 0ul; i < 4; ++i) { + // \todo add support for Sycl buffers + // \todo handle errors properly + if(!set_kernel_arg(cgh, Args[i], i)) + exit(1); + } + switch(NDims) + { + case 1: + cgh.parallel_for(range<1>{Range[0]}, *Kernel); + break; + case 2: + cgh.parallel_for(range<2>{Range[0], Range[1]}, *Kernel); + break; + case 3: + cgh.parallel_for(range<3>{Range[0], Range[1], Range[2]}, *Kernel); + break; + default: + // \todo handle the error + std::cerr << "Range cannot be greater than three dimensions.\n"; + exit(1); + } + }); + + return wrap_event(new event(e)); +} From abd373bf3b3e3cd389f91dcad289c91ef5d392a4 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Fri, 18 Sep 2020 13:02:01 +0300 Subject: [PATCH 28/41] Add MemoryUSM* classes. --- backends/include/dppl_sycl_usm_interface.h | 18 +++++++++++ backends/source/dppl_sycl_usm_interface.cpp | 16 ++++++++++ dppl/_memory.pyx | 29 +++++++++++++++-- dppl/backend.pxd | 2 ++ .../dppl_tests/test_sycl_memory_manager.py | 32 +++++++++++++++++-- 5 files changed, 93 insertions(+), 4 deletions(-) diff --git a/backends/include/dppl_sycl_usm_interface.h b/backends/include/dppl_sycl_usm_interface.h index 26a609e546..4e5004dd6b 100644 --- a/backends/include/dppl_sycl_usm_interface.h +++ b/backends/include/dppl_sycl_usm_interface.h @@ -42,6 +42,24 @@ DPPL_API __dppl_give DPPLMemoryUSMSharedRef DPPLmalloc_shared (size_t size, __dppl_keep const DPPLSyclQueueRef QRef); +/*! + * @brief Crete USM host memory. + * + * @return The pointer to USM host memory. + */ +DPPL_API +__dppl_give DPPLMemoryUSMSharedRef +DPPLmalloc_host (size_t size, __dppl_keep const DPPLSyclQueueRef QRef); + +/*! + * @brief Crete USM device memory. + * + * @return The pointer to USM device memory. + */ +DPPL_API +__dppl_give DPPLMemoryUSMSharedRef +DPPLmalloc_device (size_t size, __dppl_keep const DPPLSyclQueueRef QRef); + /*! * @brief Free USM memory. * diff --git a/backends/source/dppl_sycl_usm_interface.cpp b/backends/source/dppl_sycl_usm_interface.cpp index 06f0d71b3e..74e4707978 100644 --- a/backends/source/dppl_sycl_usm_interface.cpp +++ b/backends/source/dppl_sycl_usm_interface.cpp @@ -47,6 +47,22 @@ DPPLmalloc_shared (size_t size, __dppl_keep const DPPLSyclQueueRef QRef) return reinterpret_cast(Ptr); } +__dppl_give DPPLMemoryUSMSharedRef +DPPLmalloc_host (size_t size, __dppl_keep const DPPLSyclQueueRef QRef) +{ + auto Q = unwrap(QRef); + auto Ptr = malloc_host(size, *Q); + return reinterpret_cast(Ptr); +} + +__dppl_give DPPLMemoryUSMSharedRef +DPPLmalloc_device (size_t size, __dppl_keep const DPPLSyclQueueRef QRef) +{ + auto Q = unwrap(QRef); + auto Ptr = malloc_device(size, *Q); + return reinterpret_cast(Ptr); +} + void DPPLfree (DPPLMemoryUSMSharedRef MRef, __dppl_keep const DPPLSyclQueueRef QRef) { auto Ptr = unwrap(MRef); diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index fb5b3c9c42..a944ee4f1c 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -24,7 +24,7 @@ cdef class Memory: cdef Py_ssize_t nbytes cdef SyclQueue queue - def __cinit__(self, Py_ssize_t nbytes): + cdef _cinit(self, Py_ssize_t nbytes, alloc ptr_type): cdef SyclQueue q cdef DPPLMemoryUSMSharedRef p @@ -34,7 +34,14 @@ cdef class Memory: if (nbytes > 0): q = dppl.get_current_queue() - p = DPPLmalloc_shared(nbytes, q.get_queue_ref()) + + if (ptr_type == alloc.shared): + p = DPPLmalloc_shared(nbytes, q.get_queue_ref()) + if (ptr_type == alloc.host): + p = DPPLmalloc_host(nbytes, q.get_queue_ref()) + if (ptr_type == alloc.device): + p = DPPLmalloc_device(nbytes, q.get_queue_ref()) + if (p): self.memory_ptr = p self.nbytes = nbytes @@ -93,3 +100,21 @@ cdef class Memory: return "device" else: return "unknown" + + +cdef class MemoryUSMShared(Memory): + + def __cinit__(self, Py_ssize_t nbytes): + self._cinit(nbytes, alloc.shared) + + +cdef class MemoryUSMHost(Memory): + + def __cinit__(self, Py_ssize_t nbytes): + self._cinit(nbytes, alloc.host) + + +cdef class MemoryUSMDevice(Memory): + + def __cinit__(self, Py_ssize_t nbytes): + self._cinit(nbytes, alloc.device) diff --git a/dppl/backend.pxd b/dppl/backend.pxd index 23165c44fa..e3d75c6f6f 100644 --- a/dppl/backend.pxd +++ b/dppl/backend.pxd @@ -96,4 +96,6 @@ cdef extern from "dppl_sycl_queue_manager.h": cdef extern from "dppl_sycl_usm_interface.h": cdef DPPLMemoryUSMSharedRef DPPLmalloc_shared (size_t size, DPPLSyclQueueRef QRef) except + + cdef DPPLMemoryUSMSharedRef DPPLmalloc_host (size_t size, DPPLSyclQueueRef QRef) except + + cdef DPPLMemoryUSMSharedRef DPPLmalloc_device (size_t size, DPPLSyclQueueRef QRef) except + cdef void DPPLfree (DPPLMemoryUSMSharedRef MRef, DPPLSyclQueueRef QRef) except + diff --git a/dppl/tests/dppl_tests/test_sycl_memory_manager.py b/dppl/tests/dppl_tests/test_sycl_memory_manager.py index 7d0ea24aaa..3476b30d5b 100644 --- a/dppl/tests/dppl_tests/test_sycl_memory_manager.py +++ b/dppl/tests/dppl_tests/test_sycl_memory_manager.py @@ -21,18 +21,19 @@ import unittest import dppl import dppl._memory as mem +from dppl._memory import MemoryUSMShared, MemoryUSMHost, MemoryUSMDevice class TestMemory (unittest.TestCase): # @unittest.skipIf(not dppl.has_sycl_platforms, "No SYCL platforms available") def test_memory_create (self): nbytes = 1024 - mobj = mem.Memory(nbytes) + mobj = MemoryUSMShared(nbytes) self.assertEqual(mobj.nbytes, nbytes) def _create_memory (self): nbytes = 1024 - mobj = mem.Memory(nbytes) + mobj = MemoryUSMShared(nbytes) return mobj def test_memory_without_context (self): @@ -54,3 +55,30 @@ def test_memory_gpu_context (self): # GPU context with dppl.device_context(dppl.device_type.gpu): self.assertEqual(mobj._usm_type(), 'shared') + + +class TestMemoryUSMShared(unittest.TestCase): + """Tests for MemoryUSMShared + """ + + def test_create (self): + m = MemoryUSMShared(1024) + self.assertEqual(m._usm_type(), 'shared') + + +class TestMemoryUSMHost(unittest.TestCase): + """Tests for MemoryUSMHost + """ + + def test_create (self): + m = MemoryUSMHost(1024) + self.assertEqual(m._usm_type(), 'host') + + +class TestMemoryUSMDevice(unittest.TestCase): + """Tests for MemoryUSMDevice + """ + + def test_create (self): + m = MemoryUSMDevice(1024) + self.assertEqual(m._usm_type(), 'device') From ba3e497268fe3ec69441b455800cbf499500beb3 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Fri, 18 Sep 2020 13:09:32 +0300 Subject: [PATCH 29/41] Add __getbuffer__ to Shared and Host MemoryUSM classes. --- dppl/_memory.pyx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index a944ee4f1c..381240213d 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -58,7 +58,7 @@ cdef class Memory: self.nbytes = 0 self.queue = None - def __getbuffer__(self, Py_buffer *buffer, int flags): + cdef _getbuffer(self, Py_buffer *buffer, int flags): buffer.buf = self.memory_ptr buffer.format = 'B' # byte buffer.internal = NULL # see References @@ -107,12 +107,18 @@ cdef class MemoryUSMShared(Memory): def __cinit__(self, Py_ssize_t nbytes): self._cinit(nbytes, alloc.shared) + def __getbuffer__(self, Py_buffer *buffer, int flags): + self._getbuffer(buffer, flags) + cdef class MemoryUSMHost(Memory): def __cinit__(self, Py_ssize_t nbytes): self._cinit(nbytes, alloc.host) + def __getbuffer__(self, Py_buffer *buffer, int flags): + self._getbuffer(buffer, flags) + cdef class MemoryUSMDevice(Memory): From 00d63b05d75897ecb24edcae5f27e5b77d419f08 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Fri, 18 Sep 2020 15:47:10 +0300 Subject: [PATCH 30/41] Rename C-API types for USM. --- backends/include/dppl_sycl_types.h | 5 +++-- backends/include/dppl_sycl_usm_interface.h | 8 ++++---- backends/source/dppl_sycl_usm_interface.cpp | 16 ++++++++-------- dppl/_memory.pyx | 4 ++-- dppl/backend.pxd | 12 ++++++------ 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/backends/include/dppl_sycl_types.h b/backends/include/dppl_sycl_types.h index db61bfb677..7d265805bd 100644 --- a/backends/include/dppl_sycl_types.h +++ b/backends/include/dppl_sycl_types.h @@ -57,7 +57,8 @@ typedef struct DPPLOpaqueSyclQueue *DPPLSyclQueueRef; typedef struct DPPLOpaqueSyclProgram *DPPLSyclProgramRef; /*! - * @brief + * @brief Used to pass a sycl::usm memory opaquely through DPPL interfaces. * + * @see sycl::usm */ -typedef struct DPPLOpaqueMemoryUSMShared *DPPLMemoryUSMSharedRef; +typedef struct DPPLOpaqueSyclUSM *DPPLSyclUSMRef; diff --git a/backends/include/dppl_sycl_usm_interface.h b/backends/include/dppl_sycl_usm_interface.h index 4e5004dd6b..117d1ecfcf 100644 --- a/backends/include/dppl_sycl_usm_interface.h +++ b/backends/include/dppl_sycl_usm_interface.h @@ -39,7 +39,7 @@ DPPL_C_EXTERN_C_BEGIN * @return The pointer to USM shared memory. */ DPPL_API -__dppl_give DPPLMemoryUSMSharedRef +__dppl_give DPPLSyclUSMRef DPPLmalloc_shared (size_t size, __dppl_keep const DPPLSyclQueueRef QRef); /*! @@ -48,7 +48,7 @@ DPPLmalloc_shared (size_t size, __dppl_keep const DPPLSyclQueueRef QRef); * @return The pointer to USM host memory. */ DPPL_API -__dppl_give DPPLMemoryUSMSharedRef +__dppl_give DPPLSyclUSMRef DPPLmalloc_host (size_t size, __dppl_keep const DPPLSyclQueueRef QRef); /*! @@ -57,7 +57,7 @@ DPPLmalloc_host (size_t size, __dppl_keep const DPPLSyclQueueRef QRef); * @return The pointer to USM device memory. */ DPPL_API -__dppl_give DPPLMemoryUSMSharedRef +__dppl_give DPPLSyclUSMRef DPPLmalloc_device (size_t size, __dppl_keep const DPPLSyclQueueRef QRef); /*! @@ -65,7 +65,7 @@ DPPLmalloc_device (size_t size, __dppl_keep const DPPLSyclQueueRef QRef); * */ DPPL_API -void DPPLfree (__dppl_take DPPLMemoryUSMSharedRef MRef, +void DPPLfree (__dppl_take DPPLSyclUSMRef MRef, __dppl_keep const DPPLSyclQueueRef QRef); DPPL_C_EXTERN_C_END diff --git a/backends/source/dppl_sycl_usm_interface.cpp b/backends/source/dppl_sycl_usm_interface.cpp index 74e4707978..8e4351a3c0 100644 --- a/backends/source/dppl_sycl_usm_interface.cpp +++ b/backends/source/dppl_sycl_usm_interface.cpp @@ -35,35 +35,35 @@ namespace { // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) - DEFINE_SIMPLE_CONVERSION_FUNCTIONS(void, DPPLMemoryUSMSharedRef) + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(void, DPPLSyclUSMRef) } /* end of anonymous namespace */ -__dppl_give DPPLMemoryUSMSharedRef +__dppl_give DPPLSyclUSMRef DPPLmalloc_shared (size_t size, __dppl_keep const DPPLSyclQueueRef QRef) { auto Q = unwrap(QRef); auto Ptr = malloc_shared(size, *Q); - return reinterpret_cast(Ptr); + return reinterpret_cast(Ptr); } -__dppl_give DPPLMemoryUSMSharedRef +__dppl_give DPPLSyclUSMRef DPPLmalloc_host (size_t size, __dppl_keep const DPPLSyclQueueRef QRef) { auto Q = unwrap(QRef); auto Ptr = malloc_host(size, *Q); - return reinterpret_cast(Ptr); + return reinterpret_cast(Ptr); } -__dppl_give DPPLMemoryUSMSharedRef +__dppl_give DPPLSyclUSMRef DPPLmalloc_device (size_t size, __dppl_keep const DPPLSyclQueueRef QRef) { auto Q = unwrap(QRef); auto Ptr = malloc_device(size, *Q); - return reinterpret_cast(Ptr); + return reinterpret_cast(Ptr); } -void DPPLfree (DPPLMemoryUSMSharedRef MRef, __dppl_keep const DPPLSyclQueueRef QRef) +void DPPLfree (DPPLSyclUSMRef MRef, __dppl_keep const DPPLSyclQueueRef QRef) { auto Ptr = unwrap(MRef); auto Q = unwrap(QRef); diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index 381240213d..34c195cc51 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -20,13 +20,13 @@ cdef extern from "CL/sycl.hpp" namespace "cl::sycl": cdef class Memory: - cdef DPPLMemoryUSMSharedRef memory_ptr + cdef DPPLSyclUSMRef memory_ptr cdef Py_ssize_t nbytes cdef SyclQueue queue cdef _cinit(self, Py_ssize_t nbytes, alloc ptr_type): cdef SyclQueue q - cdef DPPLMemoryUSMSharedRef p + cdef DPPLSyclUSMRef p self.memory_ptr = NULL self.queue = None diff --git a/dppl/backend.pxd b/dppl/backend.pxd index e3d75c6f6f..b44af8a9a8 100644 --- a/dppl/backend.pxd +++ b/dppl/backend.pxd @@ -34,12 +34,12 @@ cdef extern from "dppl_sycl_types.h": cdef struct DPPLOpaqueSyclContext cdef struct DPPLOpaqueSyclQueue cdef struct DPPLOpaqueSyclDevice - cdef struct DPPLOpaqueMemoryUSMShared + cdef struct DPPLOpaqueSyclUSM ctypedef DPPLOpaqueSyclContext* DPPLSyclContextRef ctypedef DPPLOpaqueSyclQueue* DPPLSyclQueueRef ctypedef DPPLOpaqueSyclDevice* DPPLSyclDeviceRef - ctypedef DPPLOpaqueMemoryUSMShared* DPPLMemoryUSMSharedRef + ctypedef DPPLOpaqueSyclUSM* DPPLSyclUSMRef cdef extern from "dppl_sycl_context_interface.h": @@ -95,7 +95,7 @@ cdef extern from "dppl_sycl_queue_manager.h": cdef extern from "dppl_sycl_usm_interface.h": - cdef DPPLMemoryUSMSharedRef DPPLmalloc_shared (size_t size, DPPLSyclQueueRef QRef) except + - cdef DPPLMemoryUSMSharedRef DPPLmalloc_host (size_t size, DPPLSyclQueueRef QRef) except + - cdef DPPLMemoryUSMSharedRef DPPLmalloc_device (size_t size, DPPLSyclQueueRef QRef) except + - cdef void DPPLfree (DPPLMemoryUSMSharedRef MRef, DPPLSyclQueueRef QRef) except + + cdef DPPLSyclUSMRef DPPLmalloc_shared (size_t size, DPPLSyclQueueRef QRef) except + + cdef DPPLSyclUSMRef DPPLmalloc_host (size_t size, DPPLSyclQueueRef QRef) except + + cdef DPPLSyclUSMRef DPPLmalloc_device (size_t size, DPPLSyclQueueRef QRef) except + + cdef void DPPLfree (DPPLSyclUSMRef MRef, DPPLSyclQueueRef QRef) except + From 28f0496c21e0c277ac416cf73ffc159110c02ae5 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Fri, 18 Sep 2020 16:42:28 +0300 Subject: [PATCH 31/41] Add DPPLUSM_GetPointerType and remove types from CL/sycl.hpp from _memory.pyx --- backends/include/dppl_sycl_usm_interface.h | 11 ++++++ backends/source/dppl_sycl_usm_interface.cpp | 23 ++++++++++- dppl/_memory.pyx | 44 ++++++--------------- dppl/backend.pxd | 1 + 4 files changed, 46 insertions(+), 33 deletions(-) diff --git a/backends/include/dppl_sycl_usm_interface.h b/backends/include/dppl_sycl_usm_interface.h index 117d1ecfcf..40e7ca4fd3 100644 --- a/backends/include/dppl_sycl_usm_interface.h +++ b/backends/include/dppl_sycl_usm_interface.h @@ -68,4 +68,15 @@ DPPL_API void DPPLfree (__dppl_take DPPLSyclUSMRef MRef, __dppl_keep const DPPLSyclQueueRef QRef); + +/*! + * @brief Get pointer type. + * + * @return "host", "device", "shared" or "unknown" + */ +DPPL_API +const char * +DPPLUSM_GetPointerType (__dppl_keep DPPLSyclUSMRef MRef, + __dppl_keep const DPPLSyclQueueRef QRef); + DPPL_C_EXTERN_C_END diff --git a/backends/source/dppl_sycl_usm_interface.cpp b/backends/source/dppl_sycl_usm_interface.cpp index 8e4351a3c0..ff7dcf0324 100644 --- a/backends/source/dppl_sycl_usm_interface.cpp +++ b/backends/source/dppl_sycl_usm_interface.cpp @@ -63,9 +63,30 @@ DPPLmalloc_device (size_t size, __dppl_keep const DPPLSyclQueueRef QRef) return reinterpret_cast(Ptr); } -void DPPLfree (DPPLSyclUSMRef MRef, __dppl_keep const DPPLSyclQueueRef QRef) +void DPPLfree (__dppl_take DPPLSyclUSMRef MRef, + __dppl_keep const DPPLSyclQueueRef QRef) { auto Ptr = unwrap(MRef); auto Q = unwrap(QRef); free(Ptr, *Q); } + +const char * +DPPLUSM_GetPointerType (__dppl_keep DPPLSyclUSMRef MRef, + __dppl_keep const DPPLSyclQueueRef QRef) +{ + auto Ptr = unwrap(MRef); + auto Q = unwrap(QRef); + + auto kind = get_pointer_type(Ptr, Q->get_context()); + switch(kind) { + case usm::alloc::host: + return "host"; + case usm::alloc::device: + return "device"; + case usm::alloc::shared: + return "shared"; + default: + return "unknown"; + } +} diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index 34c195cc51..f0ac9fcf62 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -6,25 +6,13 @@ from cython.operator cimport dereference as deref from cpython cimport Py_buffer -cdef extern from "CL/sycl.hpp" namespace "cl::sycl::usm": - cdef enum alloc: - host 'cl::sycl::usm::alloc::host' - device 'cl::sycl::usm::alloc::device' - shared 'cl::sycl::usm::alloc::shared' - unknown 'cl::sycl::usm::alloc::unknown' - -cdef extern from "CL/sycl.hpp" namespace "cl::sycl": - cdef cppclass context nogil - - cdef alloc get_pointer_type(void *, context&) nogil - cdef class Memory: cdef DPPLSyclUSMRef memory_ptr cdef Py_ssize_t nbytes cdef SyclQueue queue - cdef _cinit(self, Py_ssize_t nbytes, alloc ptr_type): + cdef _cinit(self, Py_ssize_t nbytes, ptr_type): cdef SyclQueue q cdef DPPLSyclUSMRef p @@ -35,12 +23,14 @@ cdef class Memory: if (nbytes > 0): q = dppl.get_current_queue() - if (ptr_type == alloc.shared): + if (ptr_type == "shared"): p = DPPLmalloc_shared(nbytes, q.get_queue_ref()) - if (ptr_type == alloc.host): + elif (ptr_type == "host"): p = DPPLmalloc_host(nbytes, q.get_queue_ref()) - if (ptr_type == alloc.device): + elif (ptr_type == "device"): p = DPPLmalloc_device(nbytes, q.get_queue_ref()) + else: + raise RuntimeError("Pointer type is unknown: {}".format(ptr_type)) if (p): self.memory_ptr = p @@ -87,25 +77,15 @@ cdef class Memory: return "".format(self.nbytes, hex((self.memory_ptr))) def _usm_type(self): - cdef SyclContext ctxt - cdef alloc ptr_type - - ctxt = self.queue.get_sycl_context() - ptr_type = get_pointer_type(self.memory_ptr, deref(ctxt.get_context_ref())) - if (ptr_type == alloc.shared): - return "shared" - elif (ptr_type == alloc.host): - return "host" - elif (ptr_type == alloc.device): - return "device" - else: - return "unknown" + cdef const char* kind + kind = DPPLUSM_GetPointerType(self.memory_ptr, self.queue.get_queue_ref()) + return kind.decode('UTF-8') cdef class MemoryUSMShared(Memory): def __cinit__(self, Py_ssize_t nbytes): - self._cinit(nbytes, alloc.shared) + self._cinit(nbytes, "shared") def __getbuffer__(self, Py_buffer *buffer, int flags): self._getbuffer(buffer, flags) @@ -114,7 +94,7 @@ cdef class MemoryUSMShared(Memory): cdef class MemoryUSMHost(Memory): def __cinit__(self, Py_ssize_t nbytes): - self._cinit(nbytes, alloc.host) + self._cinit(nbytes, "host") def __getbuffer__(self, Py_buffer *buffer, int flags): self._getbuffer(buffer, flags) @@ -123,4 +103,4 @@ cdef class MemoryUSMHost(Memory): cdef class MemoryUSMDevice(Memory): def __cinit__(self, Py_ssize_t nbytes): - self._cinit(nbytes, alloc.device) + self._cinit(nbytes, "device") diff --git a/dppl/backend.pxd b/dppl/backend.pxd index b44af8a9a8..e810ff97ba 100644 --- a/dppl/backend.pxd +++ b/dppl/backend.pxd @@ -99,3 +99,4 @@ cdef extern from "dppl_sycl_usm_interface.h": cdef DPPLSyclUSMRef DPPLmalloc_host (size_t size, DPPLSyclQueueRef QRef) except + cdef DPPLSyclUSMRef DPPLmalloc_device (size_t size, DPPLSyclQueueRef QRef) except + cdef void DPPLfree (DPPLSyclUSMRef MRef, DPPLSyclQueueRef QRef) except + + cdef const char* DPPLUSM_GetPointerType (DPPLSyclUSMRef MRef, DPPLSyclQueueRef QRef) except + From 80cec2ad07a5ea269d4a669b3372074ab7a32ff7 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Fri, 18 Sep 2020 16:47:50 +0300 Subject: [PATCH 32/41] Clean unused code from _memory_.pyx --- dppl/_memory.pyx | 2 -- 1 file changed, 2 deletions(-) diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index f0ac9fcf62..cc082d82d3 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -2,8 +2,6 @@ import dppl from dppl.backend cimport * from ._sycl_core cimport SyclContext, SyclQueue -from cython.operator cimport dereference as deref - from cpython cimport Py_buffer From bc68d17376474727725b39ee13625914315fcd54 Mon Sep 17 00:00:00 2001 From: Diptorup Deb Date: Fri, 18 Sep 2020 13:06:42 -0500 Subject: [PATCH 33/41] Add a change to ChameLists.txt to localte the libDPPLSyclInterface when running tests. --- backends/tests/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backends/tests/CMakeLists.txt b/backends/tests/CMakeLists.txt index c3add176ba..75bce82ac5 100644 --- a/backends/tests/CMakeLists.txt +++ b/backends/tests/CMakeLists.txt @@ -3,9 +3,9 @@ string(COMPARE EQUAL "${GTEST_LIB_DIR}" "" no_gtest_lib_dir) if(${no_gtest_incl_dir} OR ${no_gtest_lib_dir}) message(WARNING - "GTest is needed to test PyDPPL's backend test cases. Pass in \ - -DGTEST_INCLUDE_DIR and -DGTEST_LIB_DIR when you configure Cmake if\ - you wish to run PyDPPL backend tests." + "GTest is needed to test PyDPPL's backend test cases. Pass in \ + -DGTEST_INCLUDE_DIR and -DGTEST_LIB_DIR when you configure Cmake \ + if you wish to run PyDPPL backend tests." ) else() # We need thread support for gtest @@ -21,6 +21,7 @@ else() include_directories(../include) link_directories(${GTEST_LIB_DIR}) + link_directories(${CMAKE_BINARY_DIR}) set(PYDPPL_BACKEND_TEST_CASES test_sycl_queue_manager From 8ef95df11b3a23f88e3bd670603922e9039c84e4 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Fri, 18 Sep 2020 21:55:15 +0300 Subject: [PATCH 34/41] Small fixes. --- backends/include/dppl_sycl_usm_interface.h | 1 - backends/source/dppl_sycl_usm_interface.cpp | 3 ++- dppl/tests/dppl_tests/test_sycl_memory_manager.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backends/include/dppl_sycl_usm_interface.h b/backends/include/dppl_sycl_usm_interface.h index 40e7ca4fd3..e85d124c12 100644 --- a/backends/include/dppl_sycl_usm_interface.h +++ b/backends/include/dppl_sycl_usm_interface.h @@ -68,7 +68,6 @@ DPPL_API void DPPLfree (__dppl_take DPPLSyclUSMRef MRef, __dppl_keep const DPPLSyclQueueRef QRef); - /*! * @brief Get pointer type. * diff --git a/backends/source/dppl_sycl_usm_interface.cpp b/backends/source/dppl_sycl_usm_interface.cpp index ff7dcf0324..428231aad9 100644 --- a/backends/source/dppl_sycl_usm_interface.cpp +++ b/backends/source/dppl_sycl_usm_interface.cpp @@ -19,7 +19,8 @@ //===----------------------------------------------------------------------===// /// /// \file -/// TODO +/// This file implements the data types and functions declared in +/// dppl_sycl_usm_interface.h. /// //===----------------------------------------------------------------------===// diff --git a/dppl/tests/dppl_tests/test_sycl_memory_manager.py b/dppl/tests/dppl_tests/test_sycl_memory_manager.py index 3476b30d5b..9cab6d2de6 100644 --- a/dppl/tests/dppl_tests/test_sycl_memory_manager.py +++ b/dppl/tests/dppl_tests/test_sycl_memory_manager.py @@ -25,7 +25,7 @@ class TestMemory (unittest.TestCase): - # @unittest.skipIf(not dppl.has_sycl_platforms, "No SYCL platforms available") + def test_memory_create (self): nbytes = 1024 mobj = MemoryUSMShared(nbytes) From fa585dab023d80959dc96069ba97b0d77388a64c Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Fri, 18 Sep 2020 21:55:59 +0300 Subject: [PATCH 35/41] Remove unused code. --- dppl/tests/dppl_tests/test_sycl_memory_manager.py | 1 - 1 file changed, 1 deletion(-) diff --git a/dppl/tests/dppl_tests/test_sycl_memory_manager.py b/dppl/tests/dppl_tests/test_sycl_memory_manager.py index 9cab6d2de6..fc6cf16aea 100644 --- a/dppl/tests/dppl_tests/test_sycl_memory_manager.py +++ b/dppl/tests/dppl_tests/test_sycl_memory_manager.py @@ -20,7 +20,6 @@ import unittest import dppl -import dppl._memory as mem from dppl._memory import MemoryUSMShared, MemoryUSMHost, MemoryUSMDevice From 533e74b0637f802a27d8f16e95422fca22fb84a0 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Fri, 18 Sep 2020 22:04:55 +0300 Subject: [PATCH 36/41] Fix style. --- backends/source/dppl_sycl_usm_interface.cpp | 1 - dppl/_memory.pyx | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backends/source/dppl_sycl_usm_interface.cpp b/backends/source/dppl_sycl_usm_interface.cpp index 428231aad9..eaebbca107 100644 --- a/backends/source/dppl_sycl_usm_interface.cpp +++ b/backends/source/dppl_sycl_usm_interface.cpp @@ -31,7 +31,6 @@ using namespace cl::sycl; -// TODO: move it to one header for not duplicate in many cpp files namespace { // Create wrappers for C Binding types (see CBindingWrapping.h). diff --git a/dppl/_memory.pyx b/dppl/_memory.pyx index cc082d82d3..c20e211ed3 100644 --- a/dppl/_memory.pyx +++ b/dppl/_memory.pyx @@ -28,7 +28,8 @@ cdef class Memory: elif (ptr_type == "device"): p = DPPLmalloc_device(nbytes, q.get_queue_ref()) else: - raise RuntimeError("Pointer type is unknown: {}".format(ptr_type)) + raise RuntimeError("Pointer type is unknown: {}" \ + .format(ptr_type)) if (p): self.memory_ptr = p @@ -72,11 +73,13 @@ cdef class Memory: return self.queue def __repr__(self): - return "".format(self.nbytes, hex((self.memory_ptr))) + return "" \ + .format(self.nbytes, hex((self.memory_ptr))) def _usm_type(self): cdef const char* kind - kind = DPPLUSM_GetPointerType(self.memory_ptr, self.queue.get_queue_ref()) + kind = DPPLUSM_GetPointerType(self.memory_ptr, + self.queue.get_queue_ref()) return kind.decode('UTF-8') From ab7a9ba60cea9a434c18fe493768fb3af9a28d0b Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Fri, 18 Sep 2020 23:09:23 +0300 Subject: [PATCH 37/41] Fix style --- dppl/backend.pxd | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dppl/backend.pxd b/dppl/backend.pxd index e810ff97ba..d19cf02e2a 100644 --- a/dppl/backend.pxd +++ b/dppl/backend.pxd @@ -95,8 +95,12 @@ cdef extern from "dppl_sycl_queue_manager.h": cdef extern from "dppl_sycl_usm_interface.h": - cdef DPPLSyclUSMRef DPPLmalloc_shared (size_t size, DPPLSyclQueueRef QRef) except + - cdef DPPLSyclUSMRef DPPLmalloc_host (size_t size, DPPLSyclQueueRef QRef) except + - cdef DPPLSyclUSMRef DPPLmalloc_device (size_t size, DPPLSyclQueueRef QRef) except + + cdef DPPLSyclUSMRef DPPLmalloc_shared (size_t size, DPPLSyclQueueRef QRef) \ + except + + cdef DPPLSyclUSMRef DPPLmalloc_host (size_t size, DPPLSyclQueueRef QRef) \ + except + + cdef DPPLSyclUSMRef DPPLmalloc_device (size_t size, DPPLSyclQueueRef QRef) \ + except + cdef void DPPLfree (DPPLSyclUSMRef MRef, DPPLSyclQueueRef QRef) except + - cdef const char* DPPLUSM_GetPointerType (DPPLSyclUSMRef MRef, DPPLSyclQueueRef QRef) except + + cdef const char* DPPLUSM_GetPointerType (DPPLSyclUSMRef MRef, + DPPLSyclQueueRef QRef) except + From b73fbdd9b51c3f9df17b74b1f9331e0f1dd2cfa3 Mon Sep 17 00:00:00 2001 From: Diptorup Deb Date: Wed, 16 Sep 2020 22:39:48 -0500 Subject: [PATCH 38/41] Change the wrap/unwrap functions to also include the type. --- backends/include/Support/CBindingWrapping.h | 4 ++-- .../source/dppl_sycl_context_interface.cpp | 8 +++---- .../source/dppl_sycl_device_interface.cpp | 22 +++++++++---------- backends/source/dppl_sycl_queue_interface.cpp | 15 +++++++------ backends/source/dppl_sycl_queue_manager.cpp | 10 ++++----- 5 files changed, 30 insertions(+), 29 deletions(-) diff --git a/backends/include/Support/CBindingWrapping.h b/backends/include/Support/CBindingWrapping.h index 40ef4027b2..2a98f59512 100644 --- a/backends/include/Support/CBindingWrapping.h +++ b/backends/include/Support/CBindingWrapping.h @@ -26,11 +26,11 @@ #pragma once #define DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref) \ - inline ty *unwrap(ref P) { \ + inline ty *unwrap_##ty(ref P) { \ return reinterpret_cast(P); \ } \ \ - inline ref wrap(const ty *P) { \ + inline ref wrap_##ty(const ty *P) { \ return reinterpret_cast(const_cast(P)); \ } diff --git a/backends/source/dppl_sycl_context_interface.cpp b/backends/source/dppl_sycl_context_interface.cpp index d27b150f74..0a83f16d58 100644 --- a/backends/source/dppl_sycl_context_interface.cpp +++ b/backends/source/dppl_sycl_context_interface.cpp @@ -32,8 +32,8 @@ using namespace cl::sycl; namespace { - // Create wrappers for C Binding types (see CBindingWrapping.h). - DEFINE_SIMPLE_CONVERSION_FUNCTIONS(context, DPPLSyclContextRef) +// Create wrappers for C Binding types (see CBindingWrapping.h). +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(context, DPPLSyclContextRef) } /* end of anonymous namespace */ /*! @@ -44,7 +44,7 @@ namespace */ bool DPPLIsHostContext (__dppl_keep const DPPLSyclContextRef CtxtRef) { - return unwrap(CtxtRef)->is_host(); + return unwrap_context(CtxtRef)->is_host(); } /*! @@ -54,5 +54,5 @@ bool DPPLIsHostContext (__dppl_keep const DPPLSyclContextRef CtxtRef) */ void DPPLDeleteSyclContext (__dppl_take DPPLSyclContextRef CtxtRef) { - delete unwrap(CtxtRef); + delete unwrap_context(CtxtRef); } diff --git a/backends/source/dppl_sycl_device_interface.cpp b/backends/source/dppl_sycl_device_interface.cpp index f70f34be1e..7fa9c8d54f 100644 --- a/backends/source/dppl_sycl_device_interface.cpp +++ b/backends/source/dppl_sycl_device_interface.cpp @@ -35,7 +35,7 @@ using namespace cl::sycl; namespace { // Create wrappers for C Binding types (see CBindingWrapping.h). - DEFINE_SIMPLE_CONVERSION_FUNCTIONS(device, DPPLSyclDeviceRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(device, DPPLSyclDeviceRef) /*! * @brief Helper function to print the metadata for a sycl::device. @@ -68,41 +68,41 @@ void dump_device_info (const device & Device) */ void DPPLDumpDeviceInfo (__dppl_keep const DPPLSyclDeviceRef DRef) { - auto Device = unwrap(DRef); + auto Device = unwrap_device(DRef); dump_device_info(*Device); } void DPPLDeleteSyclDevice (__dppl_take DPPLSyclDeviceRef DRef) { - delete unwrap(DRef); + delete unwrap_device(DRef); } bool DPPLDeviceIsAccelerator (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->is_accelerator(); + return unwrap_device(DRef)->is_accelerator(); } bool DPPLDeviceIsCPU (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->is_cpu(); + return unwrap_device(DRef)->is_cpu(); } bool DPPLDeviceIsGPU (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->is_gpu(); + return unwrap_device(DRef)->is_gpu(); } bool DPPLDeviceIsHost (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->is_host(); + return unwrap_device(DRef)->is_host(); } __dppl_give const char* DPPLGetDeviceName (__dppl_keep const DPPLSyclDeviceRef DRef) { - auto name = unwrap(DRef)->get_info(); + auto name = unwrap_device(DRef)->get_info(); auto cstr_name = new char [name.length()+1]; std::strcpy (cstr_name, name.c_str()); return cstr_name; @@ -111,7 +111,7 @@ DPPLGetDeviceName (__dppl_keep const DPPLSyclDeviceRef DRef) __dppl_give const char* DPPLGetDeviceVendorName (__dppl_keep const DPPLSyclDeviceRef DRef) { - auto vendor = unwrap(DRef)->get_info(); + auto vendor = unwrap_device(DRef)->get_info(); auto cstr_vendor = new char [vendor.length()+1]; std::strcpy (cstr_vendor, vendor.c_str()); return cstr_vendor; @@ -120,7 +120,7 @@ DPPLGetDeviceVendorName (__dppl_keep const DPPLSyclDeviceRef DRef) __dppl_give const char* DPPLGetDeviceDriverInfo (__dppl_keep const DPPLSyclDeviceRef DRef) { - auto driver = unwrap(DRef)->get_info(); + auto driver = unwrap_device(DRef)->get_info(); auto cstr_driver = new char [driver.length()+1]; std::strcpy (cstr_driver, driver.c_str()); return cstr_driver; @@ -128,5 +128,5 @@ DPPLGetDeviceDriverInfo (__dppl_keep const DPPLSyclDeviceRef DRef) bool DPPLGetDeviceHostUnifiedMemory (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->get_info(); + return unwrap_device(DRef)->get_info(); } diff --git a/backends/source/dppl_sycl_queue_interface.cpp b/backends/source/dppl_sycl_queue_interface.cpp index e02479d69d..efb23554d5 100644 --- a/backends/source/dppl_sycl_queue_interface.cpp +++ b/backends/source/dppl_sycl_queue_interface.cpp @@ -34,24 +34,25 @@ using namespace cl::sycl; namespace { // Create wrappers for C Binding types (see CBindingWrapping.h). - DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) - +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(device, DPPLSyclDeviceRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(context, DPPLSyclContextRef) } /* end of anonymous namespace */ __dppl_give DPPLSyclDeviceRef DPPLGetDeviceFromQueue (__dppl_keep const DPPLSyclQueueRef QRef) { - auto Q = unwrap(QRef); + auto Q = unwrap_queue(QRef); auto Device = new device(Q->get_device()); - return reinterpret_cast(Device); + return wrap_device(Device); } __dppl_give DPPLSyclContextRef DPPLGetContextFromQueue (__dppl_keep const DPPLSyclQueueRef QRef) { - auto Q = unwrap(QRef); + auto Q = unwrap_queue(QRef); auto Context = new context(Q->get_context()); - return reinterpret_cast(Context); + return wrap_context(Context); } /*! @@ -59,5 +60,5 @@ DPPLGetContextFromQueue (__dppl_keep const DPPLSyclQueueRef QRef) */ void DPPLDeleteSyclQueue (__dppl_take DPPLSyclQueueRef QRef) { - delete unwrap(QRef); + delete unwrap_queue(QRef); } diff --git a/backends/source/dppl_sycl_queue_manager.cpp b/backends/source/dppl_sycl_queue_manager.cpp index 17776fda11..c299269e5d 100644 --- a/backends/source/dppl_sycl_queue_manager.cpp +++ b/backends/source/dppl_sycl_queue_manager.cpp @@ -39,8 +39,8 @@ using namespace cl::sycl; namespace { - // Create wrappers for C Binding types (see CBindingWrapping.h). - DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) +// Create wrappers for C Binding types (see CBindingWrapping.h). +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) void error_reporter (const std::string & msg) { @@ -128,7 +128,7 @@ DPPLSyclQueueRef QMgrHelper::getCurrentQueue () if(active_queues.empty()) error_reporter("No currently active queues."); auto last = QMgrHelper::active_queues.size() - 1; - return wrap(new queue(QMgrHelper::active_queues[last])); + return wrap_queue(new queue(QMgrHelper::active_queues[last])); } /*! @@ -169,7 +169,7 @@ QMgrHelper::getQueue (DPPLSyclDeviceType DeviceTy, error_reporter("Unsupported device type."); } - return wrap(QRef); + return wrap_queue(QRef); } /*! @@ -254,7 +254,7 @@ QMgrHelper::pushSyclQueue (DPPLSyclDeviceType DeviceTy, size_t DNum) } } - return wrap(QRef); + return wrap_queue(QRef); } /*! From c9a0a75914c869b63284f90f7e04903b83bf396d Mon Sep 17 00:00:00 2001 From: Diptorup Deb Date: Wed, 16 Sep 2020 22:41:54 -0500 Subject: [PATCH 39/41] Add an interoperability function to create Sycl kernels from SPIR-V. --- backends/CMakeLists.txt | 1 + backends/include/dppl_sycl_kernel_interface.h | 99 ++++++++++++++++ backends/include/dppl_sycl_types.h | 34 ++++-- .../source/dppl_sycl_kernel_interface.cpp | 110 ++++++++++++++++++ 4 files changed, 233 insertions(+), 11 deletions(-) create mode 100644 backends/include/dppl_sycl_kernel_interface.h create mode 100644 backends/source/dppl_sycl_kernel_interface.cpp diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index abb8c022ff..e3a8819855 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -98,6 +98,7 @@ add_library( SHARED source/dppl_sycl_context_interface.cpp source/dppl_sycl_device_interface.cpp + source/dppl_sycl_kernel_interface.cpp source/dppl_sycl_platform_interface.cpp source/dppl_sycl_queue_interface.cpp source/dppl_sycl_queue_manager.cpp diff --git a/backends/include/dppl_sycl_kernel_interface.h b/backends/include/dppl_sycl_kernel_interface.h new file mode 100644 index 0000000000..3131f9fe0d --- /dev/null +++ b/backends/include/dppl_sycl_kernel_interface.h @@ -0,0 +1,99 @@ +//===---- dppl_sycl_kernel_interface.h - DPPL-SYCL interface --*--C++ --*--===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This header declares a C API to create Sycl kernels from OpenCL kernels. In +/// future, API to create interoperability kernels from other languages such as +/// Level-0 driver API may be added here. +/// +/// \todo Investigate what we should do when we add support for Level-0 API. +/// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "dppl_data_types.h" +#include "dppl_sycl_types.h" +#include "Support/DllExport.h" +#include "Support/ExternC.h" +#include "Support/MemOwnershipAttrs.h" + +DPPL_C_EXTERN_C_BEGIN + +/*! + * @brief Create a Sycl Kernel from an OpenCL SPIR-V binary + * + * Sycl 1.2 does expose any method to create a sycl::program from a SPIR-V IL + * file. To get around this limitation, we need to use the Sycl feature to + * create an interoperability kernel from an OpenCL kernel. This function first + * creates an OpenCL program and kernel from the SPIR-V binary and then using + * the Sycl-OpenCL interoperability feature creates a Sycl kernel from the + * OpenCL kernel. + * + * The feature to create a Sycl kernel from a SPIR-V IL binary will be available + * in Sycl 2.0. + * + * @param Ctx An opaque pointer to a sycl::context + * @param IL SPIR-V binary + * @return A new SyclProgramRef pointer if the program creation succeeded, + * else returns NULL. + */ +DPPL_API +__dppl_give DPPLSyclKernelRef +DPPLKernel_CreateKernelFromSpirv (__dppl_keep const DPPLSyclContextRef Ctx, + __dppl_keep const void *IL, + size_t length, + const char *KernelName = nullptr); + +/*! + * @brief Returns a C string for the kernel name. + * + * @param Kernel DPPLSyclKernelRef pointer to an OpenCL + * interoperability kernel. + * @return If a kernel name exists then returns it as a C string, else + * returns a nullptr. + */ +DPPL_API +__dppl_give const char* +DPPLKernel_GetFunctionName (__dppl_keep const DPPLSyclKernelRef Kernel); + +/*! + * @brief Returns the number of arguments for the OpenCL kernel. + * + * @param Kernel DPPLSyclKernelRef pointer to an OpenCL + * interoperability kernel. + * @return Returns the number of arguments for the OpenCL interoperability + * kernel. + */ +DPPL_API +size_t +DPPLKernel_GetNumArgs (__dppl_keep const DPPLSyclKernelRef Kernel); + +/*! + * @brief Deletes the DPPLSyclKernelRef after casting it to a sycl::kernel. + * + * @param Kernel DPPLSyclKernelRef pointer to an OpenCL + * interoperability kernel. + */ +DPPL_API +void +DPPLKernel_DeleteKernelRef (__dppl_take DPPLSyclKernelRef Kernel); + +DPPL_C_EXTERN_C_END diff --git a/backends/include/dppl_sycl_types.h b/backends/include/dppl_sycl_types.h index 7d265805bd..f14f0f78c7 100644 --- a/backends/include/dppl_sycl_types.h +++ b/backends/include/dppl_sycl_types.h @@ -19,43 +19,55 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file defines types used by DPPL's C interface to SYCL. +/// This file defines opaque pointer types wrapping Sycl object that get used +/// by DPPL's C API. /// //===----------------------------------------------------------------------===// #pragma once /*! - * @brief + * @brief Opaque pointer used to represent references to sycl::context* * + * @see sycl::context */ typedef struct DPPLOpaqueSyclContext *DPPLSyclContextRef; /*! - * @brief + * @brief Opaque pointer used to represent references to sycl::device* * + * @see sycl::device */ typedef struct DPPLOpaqueSyclDevice *DPPLSyclDeviceRef; /*! - * @brief + * @brief Opaque pointer used to represent references to sycl::kernel* * + * @see sycl::kernel + */ +typedef struct DPPLOpaqueSyclProgram *DPPLSyclKernelRef; + +/*! + * @brief Opaque pointer used to represent references to sycl::platform* + * + * @see sycl::platform */ typedef struct DPPLOpaqueSyclPlatform *DPPLSyclPlatformRef; +/*! + * @brief Opaque pointer used to represent references to sycl::program* + * + * @see sycl::program + */ +typedef struct DPPLOpaqueSyclProgram *DPPLSyclProgramRef; + /*! - * @brief Used to pass a sycl::queue opaquely through DPPL interfaces. + * @brief Opaque pointer used to represent references to sycl::queue* * * @see sycl::queue */ typedef struct DPPLOpaqueSyclQueue *DPPLSyclQueueRef; -/*! - * @brief Used to pass a sycl::program opaquely through DPPL interfaces. - * - */ -typedef struct DPPLOpaqueSyclProgram *DPPLSyclProgramRef; - /*! * @brief Used to pass a sycl::usm memory opaquely through DPPL interfaces. * diff --git a/backends/source/dppl_sycl_kernel_interface.cpp b/backends/source/dppl_sycl_kernel_interface.cpp new file mode 100644 index 0000000000..479d501520 --- /dev/null +++ b/backends/source/dppl_sycl_kernel_interface.cpp @@ -0,0 +1,110 @@ +//===--- dppl_sycl_kernel_interface.cpp - DPPL-SYCL interface --*-- C++ -*-===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// 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 +/// This file implements the functions declared in +/// dppl_sycl_kernel_interface.h. +/// +//===----------------------------------------------------------------------===// + +#include "dppl_sycl_kernel_interface.h" +#include "Support/CBindingWrapping.h" + +#include /* Sycl headers */ +#include /* OpenCL headers */ + +using namespace cl::sycl; + +namespace +{ +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(kernel, DPPLSyclKernelRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(context, DPPLSyclContextRef) +} + +__dppl_give DPPLSyclKernelRef +DPPLKernel_CreateKernelFromSpirv (__dppl_keep const DPPLSyclContextRef Ctx, + __dppl_keep const void *IL, + size_t length, + const char *KernelName) +{ + cl_int err; + + auto SyclCtx = unwrap_context(Ctx); + auto CLCtx = SyclCtx->get(); + auto CLProgram = clCreateProgramWithIL(CLCtx, IL, length, &err); + if (err) { + // \todo: record the error string and any other information. + return nullptr; + } + auto SyclDevices = SyclCtx->get_devices(); + + // Get a list of CL Devices from the Sycl devices + auto CLDevices = new cl_device_id[SyclDevices.size()]; + for (auto i = 0ul; i < SyclDevices.size(); ++i) + CLDevices[i] = SyclDevices[i].get(); + + // Create the OpenCL interoperability program + err = clBuildProgram(CLProgram, (cl_uint)(SyclDevices.size()), CLDevices, + nullptr, nullptr, nullptr); + // free the CLDevices array + delete[] CLDevices; + + if (err) { + // \todo: record the error string and any other information. + return nullptr; + } + + // Create the OpenCL interoperability kernel + auto CLKernel = clCreateKernel(CLProgram, KernelName, &err); + if (err) { + // \todo: record the error string and any other information. + return nullptr; + } + auto SyclKernel = new kernel(CLKernel, *SyclCtx); + return wrap_kernel(SyclKernel); +} + +__dppl_give const char* +DPPLKernel_GetFunctionName (__dppl_keep const DPPLSyclKernelRef Kernel) +{ + auto SyclKernel = unwrap_kernel(Kernel); + auto kernel_name = SyclKernel->get_info(); + if(kernel_name.empty()) + return nullptr; + auto cstr_name = new char [kernel_name.length()+1]; + std::strcpy (cstr_name, kernel_name.c_str()); + return cstr_name; +} + +size_t +DPPLKernel_GetNumArgs (__dppl_keep const DPPLSyclKernelRef Kernel) +{ + auto SyclKernel = unwrap_kernel(Kernel); + auto num_args = SyclKernel->get_info(); + return (size_t)num_args; +} + +void +DPPLKernel_DeleteKernelRef (__dppl_take DPPLSyclKernelRef Kernel) +{ + delete unwrap_kernel(Kernel); +} + + From 29b5ae6dbb0c6b266ea50ed07d02478e9baa6a1c Mon Sep 17 00:00:00 2001 From: Diptorup Deb Date: Thu, 17 Sep 2020 22:15:30 -0500 Subject: [PATCH 40/41] Add a kernel submission interface. --- backends/include/dppl_sycl_kernel_interface.h | 132 ++++++++++++++- backends/include/dppl_sycl_types.h | 7 + .../source/dppl_sycl_kernel_interface.cpp | 150 +++++++++++++++++- 3 files changed, 282 insertions(+), 7 deletions(-) diff --git a/backends/include/dppl_sycl_kernel_interface.h b/backends/include/dppl_sycl_kernel_interface.h index 3131f9fe0d..0c0ae453c9 100644 --- a/backends/include/dppl_sycl_kernel_interface.h +++ b/backends/include/dppl_sycl_kernel_interface.h @@ -37,6 +37,92 @@ DPPL_C_EXTERN_C_BEGIN +/*! + * @brief Enum of currently support types for kernel arguments. + * + * \todo Add support for sycl::buffer + * + */ +enum DPPLArgTypes +{ + CHAR, + SIGNED_CHAR, + UNSIGNED_CHAR, + SHORT, + INT, + UNSIGNED_INT, + LONG, + UNSIGNED_LONG, + LONG_LONG, + UNSIGNED_LONG_LONG, + SIZE_T, + FLOAT, + DOUBLE, + LONG_DOUBLE, + CHAR_P, + SIGNED_CHAR_P, + UNSIGNED_CHAR_P, + SHORT_P, + INT_P, + UNSIGNED_INT_P, + LONG_P, + UNSIGNED_LONG_P, + LONG_LONG_P, + UNSIGNED_LONG_LONG_P, + SIZE_T_P, + FLOAT_P, + DOUBLE_P, + LONG_DOUBLE_P +}; + +/*! + * @brief A union representing an OpenCL kernel argument that is either a basic + * C type of a pointer of the type. + * + */ +union DPPLArgValue +{ + char char_arg; + signed char schar_arg; + unsigned char uchar_arg; + short short_arg; + int int_arg; + unsigned int uint_arg; + long long_arg; + unsigned long ulong_arg; + long long longlong_arg; + unsigned long long ulonglong_arg; + size_t size_t_arg; + float float_arg; + double double_arg; + long double longdouble_arg; + char *char_p_arg; + signed char *schar_p_arg; + unsigned char *uchar_p_arg; + short *short_p_arg; + int *int_p_arg; + unsigned int *uint_p_arg; + long *long_p_arg; + unsigned long *ulong_p_arg; + long long *longlong_p_arg; + unsigned long long *ulonglong_p_arg; + size_t *size_t_p_arg; + float *float_p_arg; + double *double_p_arg; + long double *longdouble_p_arg; +}; + +/*! + * @brief The tagged union is used to pass through OpenCL kernel arguments to + * Sycl. + * + */ +struct DPPLKernelArg +{ + enum DPPLArgTypes argType; + union DPPLArgValue argVal; +}; + /*! * @brief Create a Sycl Kernel from an OpenCL SPIR-V binary * @@ -65,35 +151,69 @@ DPPLKernel_CreateKernelFromSpirv (__dppl_keep const DPPLSyclContextRef Ctx, /*! * @brief Returns a C string for the kernel name. * - * @param Kernel DPPLSyclKernelRef pointer to an OpenCL + * @param KRef DPPLSyclKernelRef pointer to an OpenCL * interoperability kernel. * @return If a kernel name exists then returns it as a C string, else * returns a nullptr. */ DPPL_API __dppl_give const char* -DPPLKernel_GetFunctionName (__dppl_keep const DPPLSyclKernelRef Kernel); +DPPLKernel_GetFunctionName (__dppl_keep const DPPLSyclKernelRef KRef); /*! * @brief Returns the number of arguments for the OpenCL kernel. * - * @param Kernel DPPLSyclKernelRef pointer to an OpenCL + * @param KRef DPPLSyclKernelRef pointer to an OpenCL * interoperability kernel. * @return Returns the number of arguments for the OpenCL interoperability * kernel. */ DPPL_API size_t -DPPLKernel_GetNumArgs (__dppl_keep const DPPLSyclKernelRef Kernel); +DPPLKernel_GetNumArgs (__dppl_keep const DPPLSyclKernelRef KRef); /*! * @brief Deletes the DPPLSyclKernelRef after casting it to a sycl::kernel. * - * @param Kernel DPPLSyclKernelRef pointer to an OpenCL + * @param KRef DPPLSyclKernelRef pointer to an OpenCL * interoperability kernel. */ DPPL_API void -DPPLKernel_DeleteKernelRef (__dppl_take DPPLSyclKernelRef Kernel); +DPPLKernel_DeleteKernelRef (__dppl_take DPPLSyclKernelRef KRef); + + +/*! + * @brief Submits the kernel to the specified queue using give arguments. + * + * A wrapper over sycl::queue.submit(). The function takes an OpenCL + * interoperability kernel, the kernel arguments, and a sycl queue as input + * arguments. The kernel arguments are passed in as an array of the + * DPPLKernelArg tagged union. + * + * \todo sycl::buffer arguments are not supported yet. + * + * @param KRef Opaque pointer to a OpenCL interoperability kernel + * wrapped inside a sycl::kernel. + * @param QRef Opaque pointer to the sycl::queue where the kernel + * will be enqueued. + * @param Args An array of the DPPLKernelArg tagged union type that + * represents the kernel arguments for the kernel. + * @param NArgs The number of kernel arguments (size of Args array). + * @param Range Array storing the range dimensions that can have a + * maximum size of three. Note the number of values + * in the array depends on the number of dimensions. + * @param NDims Number of dimensions in the range (size of Range). + * @return A opaque pointer to the sycl::event returned by the + * sycl::queue.submit() function. + */ +DPPL_API +DPPLSyclEventRef +DPPLKernel_Submit (__dppl_keep DPPLSyclKernelRef KRef, + __dppl_keep DPPLSyclQueueRef QRef, + __dppl_keep DPPLKernelArg *Args, + size_t NArgs, + size_t Range[3], + size_t NDims); DPPL_C_EXTERN_C_END diff --git a/backends/include/dppl_sycl_types.h b/backends/include/dppl_sycl_types.h index f14f0f78c7..8d3fd2321f 100644 --- a/backends/include/dppl_sycl_types.h +++ b/backends/include/dppl_sycl_types.h @@ -40,6 +40,13 @@ typedef struct DPPLOpaqueSyclContext *DPPLSyclContextRef; */ typedef struct DPPLOpaqueSyclDevice *DPPLSyclDeviceRef; +/*! + * @brief Opaque pointer used to represent references to sycl::event* + * + * @see sycl::event + */ +typedef struct DPPLOpaqueSyclEvent *DPPLSyclEventRef; + /*! * @brief Opaque pointer used to represent references to sycl::kernel* * diff --git a/backends/source/dppl_sycl_kernel_interface.cpp b/backends/source/dppl_sycl_kernel_interface.cpp index 479d501520..33f4c45999 100644 --- a/backends/source/dppl_sycl_kernel_interface.cpp +++ b/backends/source/dppl_sycl_kernel_interface.cpp @@ -34,10 +34,118 @@ using namespace cl::sycl; namespace { -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(kernel, DPPLSyclKernelRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(context, DPPLSyclContextRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(event, DPPLSyclEventRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(kernel, DPPLSyclKernelRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(queue, DPPLSyclQueueRef) + +/*! + * @brief Set the kernel arg object + * + * @param cgh My Param doc + * @param Arg My Param doc + */ +bool set_kernel_arg (handler &cgh, __dppl_keep DPPLKernelArg Arg, size_t idx) +{ + bool arg_set = true; + + switch (Arg.argType) + { + case CHAR: + cgh.set_arg(idx, Arg.argVal.char_arg); + break; + case SIGNED_CHAR: + cgh.set_arg(idx, Arg.argVal.schar_arg); + break; + case UNSIGNED_CHAR: + cgh.set_arg(idx, Arg.argVal.uchar_arg); + break; + case SHORT: + cgh.set_arg(idx, Arg.argVal.short_arg); + break; + case INT: + cgh.set_arg(idx, Arg.argVal.int_arg); + break; + case UNSIGNED_INT: + cgh.set_arg(idx, Arg.argVal.uint_arg); + break; + case LONG: + cgh.set_arg(idx, Arg.argVal.long_arg); + break; + case UNSIGNED_LONG: + cgh.set_arg(idx, Arg.argVal.ulong_arg); + break; + case LONG_LONG: + cgh.set_arg(idx, Arg.argVal.longlong_arg); + break; + case UNSIGNED_LONG_LONG: + cgh.set_arg(idx, Arg.argVal.ulonglong_arg); + break; + case SIZE_T: + cgh.set_arg(idx, Arg.argVal.size_t_arg); + break; + case FLOAT: + cgh.set_arg(idx, Arg.argVal.float_arg); + break; + case DOUBLE: + cgh.set_arg(idx, Arg.argVal.double_arg); + break; + case LONG_DOUBLE: + cgh.set_arg(idx, Arg.argVal.longdouble_arg); + break; + case CHAR_P: + cgh.set_arg(idx, Arg.argVal.char_p_arg); + break; + case SIGNED_CHAR_P: + cgh.set_arg(idx, Arg.argVal.schar_p_arg); + break; + case UNSIGNED_CHAR_P: + cgh.set_arg(idx, Arg.argVal.uchar_p_arg); + break; + case SHORT_P: + cgh.set_arg(idx, Arg.argVal.short_p_arg); + break; + case INT_P: + cgh.set_arg(idx, Arg.argVal.int_p_arg); + break; + case UNSIGNED_INT_P: + cgh.set_arg(idx, Arg.argVal.uint_p_arg); + break; + case LONG_P: + cgh.set_arg(idx, Arg.argVal.long_p_arg); + break; + case UNSIGNED_LONG_P: + cgh.set_arg(idx, Arg.argVal.ulong_p_arg); + break; + case LONG_LONG_P: + cgh.set_arg(idx, Arg.argVal.longlong_p_arg); + break; + case UNSIGNED_LONG_LONG_P: + cgh.set_arg(idx, Arg.argVal.ulonglong_p_arg); + break; + case SIZE_T_P: + cgh.set_arg(idx, Arg.argVal.size_t_p_arg); + break; + case FLOAT_P: + cgh.set_arg(idx, Arg.argVal.float_p_arg); + break; + case DOUBLE_P: + cgh.set_arg(idx, Arg.argVal.double_p_arg); + break; + case LONG_DOUBLE_P: + cgh.set_arg(idx, Arg.argVal.longdouble_p_arg); + break; + default: + // \todo handle errors + arg_set = false; + std::cerr << "Kernel argument could not be created.\n"; + break; + } + return arg_set; } +} /* end of anonymous namespace */ + __dppl_give DPPLSyclKernelRef DPPLKernel_CreateKernelFromSpirv (__dppl_keep const DPPLSyclContextRef Ctx, __dppl_keep const void *IL, @@ -108,3 +216,43 @@ DPPLKernel_DeleteKernelRef (__dppl_take DPPLSyclKernelRef Kernel) } +DPPL_API +DPPLSyclEventRef +DPPLKernel_Submit (__dppl_keep DPPLSyclKernelRef KRef, + __dppl_keep DPPLSyclQueueRef QRef, + __dppl_keep DPPLKernelArg *Args, + size_t NArgs, + size_t Range[3], + size_t NDims) +{ + auto Kernel = unwrap_kernel(KRef); + auto Queue = unwrap_queue(QRef); + event e; + + e = Queue->submit([&](handler& cgh) { + for (auto i = 0ul; i < 4; ++i) { + // \todo add support for Sycl buffers + // \todo handle errors properly + if(!set_kernel_arg(cgh, Args[i], i)) + exit(1); + } + switch(NDims) + { + case 1: + cgh.parallel_for(range<1>{Range[0]}, *Kernel); + break; + case 2: + cgh.parallel_for(range<2>{Range[0], Range[1]}, *Kernel); + break; + case 3: + cgh.parallel_for(range<3>{Range[0], Range[1], Range[2]}, *Kernel); + break; + default: + // \todo handle the error + std::cerr << "Range cannot be greater than three dimensions.\n"; + exit(1); + } + }); + + return wrap_event(new event(e)); +} From 6b5209be65715ec42f71b38404440f7fa90aab44 Mon Sep 17 00:00:00 2001 From: Diptorup Deb Date: Fri, 18 Sep 2020 13:06:42 -0500 Subject: [PATCH 41/41] Add a change to ChameLists.txt to localte the libDPPLSyclInterface when running tests. --- backends/tests/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backends/tests/CMakeLists.txt b/backends/tests/CMakeLists.txt index c3add176ba..75bce82ac5 100644 --- a/backends/tests/CMakeLists.txt +++ b/backends/tests/CMakeLists.txt @@ -3,9 +3,9 @@ string(COMPARE EQUAL "${GTEST_LIB_DIR}" "" no_gtest_lib_dir) if(${no_gtest_incl_dir} OR ${no_gtest_lib_dir}) message(WARNING - "GTest is needed to test PyDPPL's backend test cases. Pass in \ - -DGTEST_INCLUDE_DIR and -DGTEST_LIB_DIR when you configure Cmake if\ - you wish to run PyDPPL backend tests." + "GTest is needed to test PyDPPL's backend test cases. Pass in \ + -DGTEST_INCLUDE_DIR and -DGTEST_LIB_DIR when you configure Cmake \ + if you wish to run PyDPPL backend tests." ) else() # We need thread support for gtest @@ -21,6 +21,7 @@ else() include_directories(../include) link_directories(${GTEST_LIB_DIR}) + link_directories(${CMAKE_BINARY_DIR}) set(PYDPPL_BACKEND_TEST_CASES test_sycl_queue_manager