From 78a858c6b1f28ee6a989f20583fd1c54f43cf330 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Tue, 8 Nov 2022 11:04:57 -0600 Subject: [PATCH 1/6] Implements #972 by adding dpctl/sycl.pxd This Cython declaration file contains incomplete redeclarations of SYCL runtime classes, as well as wrap/unwrap casters to convert SyclInterface opaque pointers to these. --- dpctl/sycl.pxd | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 dpctl/sycl.pxd diff --git a/dpctl/sycl.pxd b/dpctl/sycl.pxd new file mode 100644 index 0000000000..dab9bfe6ad --- /dev/null +++ b/dpctl/sycl.pxd @@ -0,0 +1,59 @@ +# Copyright 2022 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# distutils: language = c++ +# cython: language_level=3 + +# SYCL static imports for Cython + +from . cimport _backend as dpctl_backend + + +cdef extern from "CL/sycl.hpp" namespace "sycl": + cdef cppclass queue "sycl::queue": + pass + + cdef cppclass device "sycl::device": + pass + + cdef cppclass context "sycl::context": + pass + + cdef cppclass event "sycl::event": + pass + + cdef cppclass kernel "sycl::kernel": + pass + + cdef cppclass executable_kernel_bundle \ + "sycl::kernel_bundle": + pass + +cdef extern from "syclinterface/dpctl_sycl_type_casters.hpp" \ + namespace "dpctl::syclinterface": + # queue + cdef dpctl_backend.DPCTLSyclQueueRef wrap_queue "dpctl::syclinterface::wrap" (const queue *) + cdef queue * unwrap_queue "dpctl::syclinterface::unwrap" (dpctl_backend.DPCTLSyclQueueRef) + + # device + cdef dpctl_backend.DPCTLSyclDeviceRef wrap_device "dpctl::syclinterface::wrap" (const device *) + cdef device * unwrap_device "dpctl::syclinterface::unwrap" (dpctl_backend.DPCTLSyclDeviceRef) + + # context + cdef dpctl_backend.DPCTLSyclContextRef wrap_context "dpctl::syclinterface::wrap" (const context *) + cdef context * unwrap_context "dpctl::syclinterface::unwrap" (dpctl_backend.DPCTLSyclContextRef) + + # event + cdef dpctl_backend.DPCTLSyclEventRef wrap_event "dpctl::syclinterface::wrap" (const event *) + cdef event * unwrap_event "dpctl::syclinterface::unwrap" (dpctl_backend.DPCTLSyclEventRef) From ad6bd2619538dd437a08ddc017757c557fdeabc6 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Tue, 8 Nov 2022 11:48:56 -0600 Subject: [PATCH 2/6] Added Cython example exercising dpctl.sycl --- examples/cython/use_dpctl_sycl/.gitignore | 2 + examples/cython/use_dpctl_sycl/README.md | 20 +++++++ examples/cython/use_dpctl_sycl/setup.py | 49 +++++++++++++++++ .../use_dpctl_sycl/tests/test_example.py | 48 +++++++++++++++++ .../use_dpctl_sycl/use_dpctl_sycl/__init__.py | 23 ++++++++ .../use_dpctl_sycl/_cython_api.pyx | 53 +++++++++++++++++++ .../use_dpctl_sycl/use_dpctl_sycl/utils.hpp | 20 +++++++ 7 files changed, 215 insertions(+) create mode 100644 examples/cython/use_dpctl_sycl/.gitignore create mode 100644 examples/cython/use_dpctl_sycl/README.md create mode 100644 examples/cython/use_dpctl_sycl/setup.py create mode 100644 examples/cython/use_dpctl_sycl/tests/test_example.py create mode 100644 examples/cython/use_dpctl_sycl/use_dpctl_sycl/__init__.py create mode 100644 examples/cython/use_dpctl_sycl/use_dpctl_sycl/_cython_api.pyx create mode 100644 examples/cython/use_dpctl_sycl/use_dpctl_sycl/utils.hpp diff --git a/examples/cython/use_dpctl_sycl/.gitignore b/examples/cython/use_dpctl_sycl/.gitignore new file mode 100644 index 0000000000..f379fa27cc --- /dev/null +++ b/examples/cython/use_dpctl_sycl/.gitignore @@ -0,0 +1,2 @@ +use_dpctl_sycl/_cython_api.cpp +*~ diff --git a/examples/cython/use_dpctl_sycl/README.md b/examples/cython/use_dpctl_sycl/README.md new file mode 100644 index 0000000000..8e7df96e56 --- /dev/null +++ b/examples/cython/use_dpctl_sycl/README.md @@ -0,0 +1,20 @@ +# Example illustrating use of dpctl.sycl in Cython + +Dpctl include `dpctl/sycl.pxd` file with incomplete definitions +of SYCL runtime classes and conversion routines from SYCLInterface +library opaque pointers to pointers to these SYCL classes. + +This files simplifies usage of SYCL routines from Python extensions +written in Cython. + +## Building + +```bash +python setup.py develop +``` + +## Testing + +```bash +python -m pytest tests +``` diff --git a/examples/cython/use_dpctl_sycl/setup.py b/examples/cython/use_dpctl_sycl/setup.py new file mode 100644 index 0000000000..487e43831e --- /dev/null +++ b/examples/cython/use_dpctl_sycl/setup.py @@ -0,0 +1,49 @@ +# Data Parallel Control (dpctl) +# +# Copyright 2020-2022 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 Cython.Build +import setuptools +import setuptools.command.build_ext + +import dpctl + + +class custom_build_ext( + setuptools.command.build_ext.build_ext, Cython.Build.build_ext +): + def build_extensions(self): + self.compiler.set_executable("compiler_so", "icx -fsycl -fPIC") + self.compiler.set_executable("compiler_cxx", "icpx -fsycl -fPIC") + self.compiler.set_executable( + "linker_so", + "icpx -fsycl -shared -fpic -fsycl-device-code-split=per_kernel", + ) + super().build_extensions() + + +ext = setuptools.Extension( + "use_dpctl_sycl._cython_api", + ["./use_dpctl_sycl/_cython_api.pyx"], + include_dirs=[dpctl.get_include(), "./use_dpctl_sycl"], + language="c++", +) + +setuptools.setup( + name="use_dpctl_sycl", + version="0.0.0", + ext_modules=[ext], + cmdclass={"build_ext": custom_build_ext}, +) diff --git a/examples/cython/use_dpctl_sycl/tests/test_example.py b/examples/cython/use_dpctl_sycl/tests/test_example.py new file mode 100644 index 0000000000..aefd781fb0 --- /dev/null +++ b/examples/cython/use_dpctl_sycl/tests/test_example.py @@ -0,0 +1,48 @@ +# Data Parallel Control (dpctl) +# +# Copyright 2020-2022 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 pytest +import use_dpctl_sycl + +import dpctl + + +def test_device_name(): + try: + d = dpctl.SyclDevice() + except dpctl.SyclDeviceCreationError: + pytest.skip("Could not create default device. Nothing to do") + d_n = use_dpctl_sycl.device_name(d) + assert d_n.decode("utf-8") == d.name + + +def test_device_driver_version(): + try: + d = dpctl.SyclDevice() + except dpctl.SyclDeviceCreationError: + pytest.skip("Could not create default device. Nothing to do") + d_dv = use_dpctl_sycl.device_driver_version(d) + assert d_dv.decode("utf-8") == d.driver_version + + +def test_device_copy(): + try: + d = dpctl.SyclDevice() + except dpctl.SyclDeviceCreationError: + pytest.skip("Could not create default device. Nothing to do") + d_copy = use_dpctl_sycl.device_copy(d) + assert d_copy == d + assert d_copy.addressof_ref() != d.addressof_ref() diff --git a/examples/cython/use_dpctl_sycl/use_dpctl_sycl/__init__.py b/examples/cython/use_dpctl_sycl/use_dpctl_sycl/__init__.py new file mode 100644 index 0000000000..0f75d05e57 --- /dev/null +++ b/examples/cython/use_dpctl_sycl/use_dpctl_sycl/__init__.py @@ -0,0 +1,23 @@ +# Data Parallel Control (dpctl) +# +# Copyright 2020-2022 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. + +from ._cython_api import device_copy, device_driver_version, device_name + +__all__ = [ + "device_name", + "device_driver_version", + "device_copy", +] diff --git a/examples/cython/use_dpctl_sycl/use_dpctl_sycl/_cython_api.pyx b/examples/cython/use_dpctl_sycl/use_dpctl_sycl/_cython_api.pyx new file mode 100644 index 0000000000..6c77600a1e --- /dev/null +++ b/examples/cython/use_dpctl_sycl/use_dpctl_sycl/_cython_api.pyx @@ -0,0 +1,53 @@ +# Data Parallel Control (dpctl) +# +# Copyright 2020-2022 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# distutils: language = c++ +# cython: language_level=3 +# cython: linetrace=True + +cimport libcpp.string + +cimport dpctl +cimport dpctl.sycl + + +cdef extern from "utils.hpp": + cdef libcpp.string.string get_device_name(dpctl.sycl.device) + cdef libcpp.string.string get_device_driver_version(dpctl.sycl.device) + cdef dpctl.sycl.device *copy_device(dpctl.sycl.device) + + +def device_name(dpctl.SyclDevice dev): + cdef dpctl.DPCTLSyclDeviceRef d_ref = dev.get_device_ref() + cdef const dpctl.sycl.device *dpcpp_device = dpctl.sycl.unwrap_device(d_ref) + + return get_device_name(dpcpp_device[0]) + + +def device_driver_version(dpctl.SyclDevice dev): + cdef dpctl.DPCTLSyclDeviceRef d_ref = dev.get_device_ref() + cdef const dpctl.sycl.device *dpcpp_device = dpctl.sycl.unwrap_device(d_ref) + + return get_device_driver_version(dpcpp_device[0]) + + +cpdef dpctl.SyclDevice device_copy(dpctl.SyclDevice dev): + cdef dpctl.DPCTLSyclDeviceRef d_ref = dev.get_device_ref() + cdef const dpctl.sycl.device *dpcpp_device = dpctl.sycl.unwrap_device(d_ref) + cdef dpctl.sycl.device *copied_device = copy_device(dpcpp_device[0]) + cdef dpctl.DPCTLSyclDeviceRef copied_d_ref = dpctl.sycl.wrap_device(copied_device) + + return dpctl.SyclDevice._create(copied_d_ref) diff --git a/examples/cython/use_dpctl_sycl/use_dpctl_sycl/utils.hpp b/examples/cython/use_dpctl_sycl/use_dpctl_sycl/utils.hpp new file mode 100644 index 0000000000..9afe162c4a --- /dev/null +++ b/examples/cython/use_dpctl_sycl/use_dpctl_sycl/utils.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +std::string get_device_name(sycl::device d) +{ + return d.get_info(); +} + +std::string get_device_driver_version(sycl::device d) +{ + return d.get_info(); +} + +sycl::device *copy_device(const sycl::device &d) +{ + auto copy_ptr = new sycl::device(d); + return copy_ptr; +} From 76c6b2b677ee455cafe1fd3e68f62c6ccb49e552 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Tue, 8 Nov 2022 11:59:52 -0600 Subject: [PATCH 3/6] Added exceptions to .flake8 for new cython example source file --- .flake8 | 1 + 1 file changed, 1 insertion(+) diff --git a/.flake8 b/.flake8 index 798db28c42..44679ac08e 100644 --- a/.flake8 +++ b/.flake8 @@ -32,3 +32,4 @@ per-file-ignores = examples/cython/sycl_buffer/_buffer_example.pyx: E999, E225, E402 examples/cython/sycl_direct_linkage/_buffer_example.pyx: E999, E225, E402 examples/cython/usm_memory/blackscholes.pyx: E999, E225, E226, E402 + examples/cython/use_dpctl_sycl/use_dpctl_sycl/_cython_api.pyx: E999, E225, E226, E402 From 715a506613d22b74232715a7b1252dbf14b2dd62 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Tue, 8 Nov 2022 12:45:57 -0600 Subject: [PATCH 4/6] cython tests should try to run tests if present --- .github/workflows/conda-package.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/conda-package.yml b/.github/workflows/conda-package.yml index 07bb77e3b2..585da5b770 100644 --- a/.github/workflows/conda-package.yml +++ b/.github/workflows/conda-package.yml @@ -473,7 +473,12 @@ jobs: CC=dpcpp CXX=dpcpp LDSHARED="dpcpp -shared" \ python setup.py build_ext --inplace || exit 1 conda deactivate - LD_LIBRARY_PATH=${CONDA_PREFIX}/lib python run.py || exit 1 + if [ -e tests ] + then + LD_LIBRARY_PATH=${CONDA_PREFIX}/lib python -m pytest tests || exit 1 + else + LD_LIBRARY_PATH=${CONDA_PREFIX}/lib python run.py || exit 1 + fi popd done cd ../c From 9f95522079b661dce53071b8b07129b988f55033 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Tue, 8 Nov 2022 15:35:28 -0600 Subject: [PATCH 5/6] Fixed long lines --- dpctl/sycl.pxd | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/dpctl/sycl.pxd b/dpctl/sycl.pxd index dab9bfe6ad..918f476298 100644 --- a/dpctl/sycl.pxd +++ b/dpctl/sycl.pxd @@ -43,17 +43,25 @@ cdef extern from "CL/sycl.hpp" namespace "sycl": cdef extern from "syclinterface/dpctl_sycl_type_casters.hpp" \ namespace "dpctl::syclinterface": # queue - cdef dpctl_backend.DPCTLSyclQueueRef wrap_queue "dpctl::syclinterface::wrap" (const queue *) - cdef queue * unwrap_queue "dpctl::syclinterface::unwrap" (dpctl_backend.DPCTLSyclQueueRef) + cdef dpctl_backend.DPCTLSyclQueueRef wrap_queue \ + "dpctl::syclinterface::wrap" (const queue *) + cdef queue * unwrap_queue "dpctl::syclinterface::unwrap" ( + dpctl_backend.DPCTLSyclQueueRef) # device - cdef dpctl_backend.DPCTLSyclDeviceRef wrap_device "dpctl::syclinterface::wrap" (const device *) - cdef device * unwrap_device "dpctl::syclinterface::unwrap" (dpctl_backend.DPCTLSyclDeviceRef) + cdef dpctl_backend.DPCTLSyclDeviceRef wrap_device \ + "dpctl::syclinterface::wrap" (const device *) + cdef device * unwrap_device "dpctl::syclinterface::unwrap" ( + dpctl_backend.DPCTLSyclDeviceRef) # context - cdef dpctl_backend.DPCTLSyclContextRef wrap_context "dpctl::syclinterface::wrap" (const context *) - cdef context * unwrap_context "dpctl::syclinterface::unwrap" (dpctl_backend.DPCTLSyclContextRef) + cdef dpctl_backend.DPCTLSyclContextRef wrap_context \ + "dpctl::syclinterface::wrap" (const context *) + cdef context * unwrap_context "dpctl::syclinterface::unwrap" ( + dpctl_backend.DPCTLSyclContextRef) # event - cdef dpctl_backend.DPCTLSyclEventRef wrap_event "dpctl::syclinterface::wrap" (const event *) - cdef event * unwrap_event "dpctl::syclinterface::unwrap" (dpctl_backend.DPCTLSyclEventRef) + cdef dpctl_backend.DPCTLSyclEventRef wrap_event \ + "dpctl::syclinterface::wrap" (const event *) + cdef event * unwrap_event "dpctl::syclinterface::unwrap" ( + dpctl_backend.DPCTLSyclEventRef) From 73a39c14bc89d1971b4dc57f2c7a75cbd10620fd Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Tue, 8 Nov 2022 15:36:19 -0600 Subject: [PATCH 6/6] Fixed AttributeError: cython_create_listing with some setuptools --- examples/cython/use_dpctl_sycl/setup.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/cython/use_dpctl_sycl/setup.py b/examples/cython/use_dpctl_sycl/setup.py index 487e43831e..4f51ad3b75 100644 --- a/examples/cython/use_dpctl_sycl/setup.py +++ b/examples/cython/use_dpctl_sycl/setup.py @@ -16,14 +16,12 @@ import Cython.Build import setuptools -import setuptools.command.build_ext +from setuptools.command.build_ext import build_ext as build_ext_base import dpctl -class custom_build_ext( - setuptools.command.build_ext.build_ext, Cython.Build.build_ext -): +class custom_build_ext(build_ext_base): def build_extensions(self): self.compiler.set_executable("compiler_so", "icx -fsycl -fPIC") self.compiler.set_executable("compiler_cxx", "icpx -fsycl -fPIC") @@ -41,9 +39,15 @@ def build_extensions(self): language="c++", ) +(cythonized_ext,) = Cython.Build.cythonize( + [ + ext, + ] +) + setuptools.setup( name="use_dpctl_sycl", version="0.0.0", - ext_modules=[ext], + ext_modules=[cythonized_ext], cmdclass={"build_ext": custom_build_ext}, )