From 9ac1e2f7af3168b82e2b71e186231b52fd4dd2cd Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Wed, 8 Sep 2021 14:36:43 -0500 Subject: [PATCH 1/2] Static method SyclQueue._create_from_context_and_device change 1. Added docstrings 2. Added optional keyword argument props, to allow queue creation with properties. This method is not covered in test suite. To solve this, test suite needs to learn to build and use Cython extensions --- dpctl/_sycl_queue.pxd | 2 +- dpctl/_sycl_queue.pyx | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/dpctl/_sycl_queue.pxd b/dpctl/_sycl_queue.pxd index 92a9102021..f052550e46 100644 --- a/dpctl/_sycl_queue.pxd +++ b/dpctl/_sycl_queue.pxd @@ -66,7 +66,7 @@ cdef public api class SyclQueue (_SyclQueue) [ cdef SyclQueue _create(DPCTLSyclQueueRef qref) @staticmethod cdef SyclQueue _create_from_context_and_device( - SyclContext ctx, SyclDevice dev + SyclContext ctx, SyclDevice dev, int props=* ) cdef cpp_bool equals(self, SyclQueue q) cpdef SyclContext get_sycl_context(self) diff --git a/dpctl/_sycl_queue.pyx b/dpctl/_sycl_queue.pyx index de719de049..1091bbd765 100644 --- a/dpctl/_sycl_queue.pyx +++ b/dpctl/_sycl_queue.pyx @@ -537,13 +537,24 @@ cdef class SyclQueue(_SyclQueue): @staticmethod cdef SyclQueue _create_from_context_and_device( - SyclContext ctx, SyclDevice dev + SyclContext ctx, SyclDevice dev, int props=0 ): + """ + Static factory method to create :class:`dpctl.SyclQueue` instance + from given :class:`dpctl.SyclContext`, :class:`dpctl.SyclDevice` + and optional integer `props` encoding the queue properties. + """ cdef _SyclQueue ret = _SyclQueue.__new__(_SyclQueue) cdef DPCTLSyclContextRef cref = ctx.get_context_ref() cdef DPCTLSyclDeviceRef dref = dev.get_device_ref() - cdef DPCTLSyclQueueRef qref = DPCTLQueue_Create(cref, dref, NULL, 0) + cdef DPCTLSyclQueueRef qref = NULL + qref = DPCTLQueue_Create( + cref, + dref, + &default_async_error_handler, + props + ) if qref is NULL: raise SyclQueueCreationError("Queue creation failed.") ret._queue_ref = qref From 97c97028b1363534c1e163d46be055c43b784430 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Wed, 8 Sep 2021 16:55:33 -0500 Subject: [PATCH 2/2] Added a Cython extension to be built in place and used in tests to test Cython API functions The extension is built in temp folder. Added cython as Cython test dependency Pass --cov-config option to pytest with coverage. This works around coverage config discrepancy between the main process and a subprocess. See pytest-dev/pytest-cov#243 added _cython_api.pyx to flake exception list Exclude dpctl/tests/* and dpctl/_version from coverage reporting Fix loading of Cython extension _cython_api on Windows Add test for property=int usage --- .flake8 | 1 + .github/workflows/generate-coverage.yaml | 2 +- MANIFEST.in | 1 + conda-recipe/meta.yaml | 1 + dpctl/tests/_cython_api.pyx | 18 ++++++++++ dpctl/tests/setup_cython_api.py | 12 +++++++ dpctl/tests/test_sycl_queue.py | 46 ++++++++++++++++++++++-- pyproject.toml | 6 ++++ 8 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 dpctl/tests/_cython_api.pyx create mode 100644 dpctl/tests/setup_cython_api.py diff --git a/.flake8 b/.flake8 index 557ad738ea..f261c8a691 100644 --- a/.flake8 +++ b/.flake8 @@ -24,6 +24,7 @@ per-file-ignores = dpctl/program/_program.pyx: E999, E225, E226, E227 dpctl/tensor/_usmarray.pyx: E999, E225, E226, E227 dpctl/tensor/numpy_usm_shared.py: F821 + dpctl/tests/_cython_api.pyx: E999, E225, E227, E402 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 diff --git a/.github/workflows/generate-coverage.yaml b/.github/workflows/generate-coverage.yaml index 41f77b4279..69fd5b9ddf 100644 --- a/.github/workflows/generate-coverage.yaml +++ b/.github/workflows/generate-coverage.yaml @@ -87,7 +87,7 @@ jobs: source /opt/intel/oneapi/setvars.sh python setup.py develop --coverage=True python -c "import dpctl; print(dpctl.__version__); dpctl.lsplatform()" - pytest -q -ra --disable-warnings --cov dpctl --cov-report term-missing --pyargs dpctl -vv + pytest -q -ra --disable-warnings --cov-config pyproject.toml --cov dpctl --cov-report term-missing --pyargs dpctl -vv - name: Install coverall dependencies shell: bash -l {0} diff --git a/MANIFEST.in b/MANIFEST.in index 8452ac3331..19f37e5a30 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -14,3 +14,4 @@ include dpctl/memory/_memory_api.h include dpctl/tensor/_usmarray.h include dpctl/tensor/_usmarray_api.h include dpctl/tests/input_files/* +include dpctl/tests/*.pyx diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index 7630cd38c8..77c7814890 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -32,6 +32,7 @@ requirements: test: requires: + - cython - pytest - pytest-cov diff --git a/dpctl/tests/_cython_api.pyx b/dpctl/tests/_cython_api.pyx new file mode 100644 index 0000000000..da10e976aa --- /dev/null +++ b/dpctl/tests/_cython_api.pyx @@ -0,0 +1,18 @@ +# cython: language=c++ +# cython: language_level=3 + +cimport dpctl as c_dpctl + +import dpctl + + +def call_create_from_context_and_devices(): + cdef c_dpctl.SyclQueue q + d = dpctl.SyclDevice() + ctx = dpctl.SyclContext(d) + # calling static method + q = c_dpctl.SyclQueue._create_from_context_and_device( + ctx, + d + ) + return q diff --git a/dpctl/tests/setup_cython_api.py b/dpctl/tests/setup_cython_api.py new file mode 100644 index 0000000000..a8c347e9b9 --- /dev/null +++ b/dpctl/tests/setup_cython_api.py @@ -0,0 +1,12 @@ +import setuptools + +import dpctl + +ext = setuptools.Extension( + "_cython_api", + ["_cython_api.pyx"], + include_dirs=[dpctl.get_include()], + language="c++", +) + +setuptools.setup(name="_cython_api", version="0.0.0", ext_modules=[ext]) diff --git a/dpctl/tests/test_sycl_queue.py b/dpctl/tests/test_sycl_queue.py index 8c31dcc8b0..305b36e81a 100644 --- a/dpctl/tests/test_sycl_queue.py +++ b/dpctl/tests/test_sycl_queue.py @@ -433,7 +433,7 @@ def test_queue_submit_barrier(valid_filter): def test_queue__repr__(): - q1 = dpctl.SyclQueue() + q1 = dpctl.SyclQueue(property=0) r1 = q1.__repr__() q2 = dpctl.SyclQueue(property="in_order") r2 = q2.__repr__() @@ -441,7 +441,7 @@ def test_queue__repr__(): r3 = q3.__repr__() q4 = dpctl.SyclQueue(property="default") r4 = q4.__repr__() - q5 = dpctl.SyclQueue(property=["in_order", "enable_profiling"]) + q5 = dpctl.SyclQueue(property=["in_order", "enable_profiling", 0]) r5 = q5.__repr__() assert type(r1) is str assert type(r2) is str @@ -552,3 +552,45 @@ def test_queue_memops(): q.prefetch(list(), 512) with pytest.raises(TypeError): q.mem_advise(list(), 512, 0) + + +@pytest.fixture(scope="session") +def dpctl_cython_extension(tmp_path_factory): + import os.path + import shutil + import subprocess + import sys + import sysconfig + + curr_dir = os.path.dirname(__file__) + dr = tmp_path_factory.mktemp("_cython_api") + for fn in ["_cython_api.pyx", "setup_cython_api.py"]: + shutil.copy( + src=os.path.join(curr_dir, fn), + dst=dr, + follow_symlinks=False, + ) + res = subprocess.run( + [sys.executable, "setup_cython_api.py", "build_ext", "--inplace"], + cwd=dr, + ) + if res.returncode == 0: + import glob + from importlib.util import module_from_spec, spec_from_file_location + + sfx = sysconfig.get_config_vars()["EXT_SUFFIX"] + pth = glob.glob(os.path.join(dr, "_cython_api*" + sfx)) + if not pth: + pytest.skip("Cython extension was not built") + spec = spec_from_file_location("_cython_api", pth[0]) + builder_module = module_from_spec(spec) + spec.loader.exec_module(builder_module) + return builder_module + else: + pytest.skip("Cython extension could not be built") + + +def test_cython_api(dpctl_cython_extension): + q = dpctl_cython_extension.call_create_from_context_and_devices() + d = dpctl.SyclDevice() + assert q.sycl_device == d diff --git a/pyproject.toml b/pyproject.toml index fc41334816..e6e21f2cb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,12 @@ omit = [ "dpctl/_version.py", ] +[tool.coverage.report] +omit = [ + "dpctl/tests/*", + "dpctl/_version.py", +] + [tool.pytest.ini.options] minversion = "6.0" norecursedirs= [