From 96061733e1bdbf47d42e21ac5a012cd68226bc34 Mon Sep 17 00:00:00 2001 From: Casper da Costa-Luis Date: Thu, 22 Feb 2024 11:32:12 +0000 Subject: [PATCH 1/4] docs: fix C++ pointer --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 46e1665..da9722e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -358,7 +358,7 @@ C++: if (!dst) throw pybind11::value_error("could not allocate output"); - mycudafunction(dst->vec.data(), src->vec.data(), dst_shape.data()); + mycudafunction(dst->vec.data(), src.vec.data(), dst_shape.data()); return dst; From 4db216aecb474cd8e447d8cc4e853ce4848a7675 Mon Sep 17 00:00:00 2001 From: Casper da Costa-Luis Date: Thu, 22 Feb 2024 11:33:13 +0000 Subject: [PATCH 2/4] tests: skip unavailable backends --- tests/test_common.py | 33 +++++++++++++++++++-------------- tests/test_perf.py | 18 +++++++++--------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/tests/test_common.py b/tests/test_common.py index ec611c1..75ac884 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -2,19 +2,11 @@ import logging import numpy as np -from pytest import importorskip, mark, raises +from pytest import importorskip, mark, raises, skip import cuvec as cu import cuvec.cpython as cp -try: - # `cuvec.swig` alternative to `cuvec.cpython` - # `example_swig` is defined in ../cuvec/src/example_swig/ - from cuvec import example_swig # type: ignore # yapf: disable - from cuvec import swig as sw -except ImportError: - sw, example_swig = None, None # type: ignore # yapf: disable - try: # `cuvec.pybind11` alternative to `cuvec.cpython` # `example_pybind11` is defined in ../cuvec/src/example_pybind11/ @@ -23,6 +15,13 @@ except ImportError: py, example_pybind11 = None, None # type: ignore # yapf: disable +try: + # `cuvec.swig` alternative to `cuvec.cpython` + # `example_swig` is defined in ../cuvec/src/example_swig/ + from cuvec import example_swig # type: ignore # yapf: disable + from cuvec import swig as sw +except ImportError: + sw, example_swig = None, None # type: ignore # yapf: disable shape = 127, 344, 344 @@ -44,6 +43,8 @@ def test_cmake_prefix(): @mark.parametrize("cu,CVector", [(py, 'Pybind11Vector'), (sw, 'SWIGVector')]) def test_CVector_strides(cu, CVector): + if cu is None: + skip("cuvec.pybind11 or cuvec.swig not available") v = getattr(cu, CVector)('f', shape) a = np.asarray(v) assert a.shape == shape @@ -52,7 +53,7 @@ def test_CVector_strides(cu, CVector): @mark.parametrize("spec,result", [("i", np.int32), ("d", np.float64)]) @mark.parametrize("init", ["zeros", "ones"]) -@mark.parametrize("cu", [cp, py, sw]) +@mark.parametrize("cu", filter(None, [cp, py, sw])) def test_create(cu, init, spec, result): a = np.asarray(getattr(cu, init)(shape, spec)) assert a.dtype == result @@ -64,7 +65,7 @@ def test_create(cu, init, spec, result): assert b.dtype == a.dtype -@mark.parametrize("cu", [cp, py, sw]) +@mark.parametrize("cu", filter(None, [cp, py, sw])) def test_copy(cu): a = np.random.random(shape) b = np.asarray(cu.copy(a)) @@ -77,6 +78,8 @@ def test_copy(cu): (py, "pyraw "), (sw, "swraw ")]) def test_CuVec_creation(cu, classname, caplog): + if cu is None: + skip("cuvec.pybind11 or cuvec.swig not available") with raises(TypeError): cu.CuVec() @@ -112,7 +115,7 @@ def test_CuVec_creation(cu, classname, caplog): assert not caplog.record_tuples -@mark.parametrize("cu", [py, sw]) +@mark.parametrize("cu", filter(None, [py, sw])) def test_asarray(cu): v = cu.asarray(np.random.random(shape)) w = cu.CuVec(v) @@ -144,7 +147,7 @@ def test_asarray(cu): cu.asarray(s._vec.cuvec, ownership='error') -@mark.parametrize("cu", [py, sw]) +@mark.parametrize("cu", filter(None, [py, sw])) def test_resize(cu): v = cu.asarray(np.random.random(shape)) v.resize(shape[::-1]) @@ -155,7 +158,7 @@ def test_resize(cu): assert v._vec.shape == v.shape -@mark.parametrize("cu", [cp, py, sw]) +@mark.parametrize("cu", filter(None, [cp, py, sw])) def test_cuda_array_interface(cu): cupy = importorskip("cupy") from cuvec import dev_sync @@ -190,6 +193,8 @@ def test_cuda_array_interface(cu): @mark.parametrize("cu,ex", [(py, example_pybind11), (sw, example_swig)]) def test_increment(cu, ex): + if cu is None: + skip("cuvec.pybind11 or cuvec.swig not available") a = cu.zeros((1337, 42), 'f') assert (a == 0).all() ex.increment2d_f(a.cuvec, a.cuvec) diff --git a/tests/test_perf.py b/tests/test_perf.py index fd0be94..47009ea 100644 --- a/tests/test_perf.py +++ b/tests/test_perf.py @@ -9,14 +9,6 @@ # `example_cpython` is defined in ../cuvec/src/example_cpython/ from cuvec import example_cpython # type: ignore # yapf: disable -try: - # `cuvec.swig` alternative to `cuvec.cpython` - # `example_swig` is defined in ../cuvec/src/example_swig/ - from cuvec import example_swig # type: ignore # yapf: disable - from cuvec import swig as sw -except ImportError: - sw, example_swig = None, None # type: ignore # yapf: disable - try: # `cuvec.pybind11` alternative to `cuvec.cpython` # `example_pybind11` is defined in ../cuvec/src/example_pybind11/ @@ -25,6 +17,14 @@ except ImportError: py, example_pybind11 = None, None # type: ignore # yapf: disable +try: + # `cuvec.swig` alternative to `cuvec.cpython` + # `example_swig` is defined in ../cuvec/src/example_swig/ + from cuvec import example_swig # type: ignore # yapf: disable + from cuvec import swig as sw +except ImportError: + sw, example_swig = None, None # type: ignore # yapf: disable + def _time_overhead(): tic = time() @@ -65,7 +65,7 @@ def test_inner(*args, **kwargs): @retry_on_except() def test_perf(cu, ex, shape=(1337, 42), quiet=False, return_time=False): if cu is None: - skip("SWIG not available") + skip("cuvec.pybind11 or cuvec.swig not available") retarray = getattr(cu, 'retarray', cu.asarray) overhead = np.mean([_time_overhead() for _ in range(100)]) t = {} From b45074d37e2f883a31cbaa09a84268dab2c99c89 Mon Sep 17 00:00:00 2001 From: Casper da Costa-Luis Date: Thu, 22 Feb 2024 11:35:36 +0000 Subject: [PATCH 3/4] pybind11: use properties --- cuvec/include/cuvec_pybind11.cuh | 7 ++++--- cuvec/pybind11.py | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cuvec/include/cuvec_pybind11.cuh b/cuvec/include/cuvec_pybind11.cuh index 08e5886..b466ebd 100644 --- a/cuvec/include/cuvec_pybind11.cuh +++ b/cuvec/include/cuvec_pybind11.cuh @@ -29,8 +29,9 @@ PYBIND11_MAKE_OPAQUE(NDCuVec); pybind11::class_>(m, PYBIND11_TOSTRING(NDCuVec_##typechar)) \ .def(pybind11::init<>()) \ .def(pybind11::init>()) \ - .def("reshape", &NDCuVec::reshape) \ - .def("shape", [](const NDCuVec &v) { return v.shape; }) \ - .def("address", [](NDCuVec &v) { return (size_t)v.vec.data(); }) + .def_property( \ + "shape", [](const NDCuVec *v) { return &(v->shape); }, &NDCuVec::reshape) \ + .def_property_readonly("address", \ + [](const NDCuVec *v) { return (size_t)v->vec.data(); }) #endif // _CUVEC_PYBIND11_H_ diff --git a/cuvec/pybind11.py b/cuvec/pybind11.py index 578e206..6abef8a 100644 --- a/cuvec/pybind11.py +++ b/cuvec/pybind11.py @@ -44,16 +44,16 @@ def __init__(self, typechar: str, shape: Shape, cuvec=None): @property def shape(self) -> tuple: - return tuple(self.cuvec.shape()) + return tuple(self.cuvec.shape) @shape.setter def shape(self, shape: Shape): shape = cu.Shape(shape if isinstance(shape, Sequence) else (shape,)) - self.cuvec.reshape(shape) + self.cuvec.shape = shape @property def address(self) -> int: - return self.cuvec.address() + return self.cuvec.address Pybind11Vector.vec_types = {np.dtype(c): partial(Pybind11Vector, c) for c in typecodes} From 2f5ef976de611a64be260eab628bb3aa3ade3554 Mon Sep 17 00:00:00 2001 From: Casper da Costa-Luis Date: Thu, 22 Feb 2024 11:39:05 +0000 Subject: [PATCH 4/4] build: split `make test`s --- CONTRIBUTING.md | 4 ++-- Makefile | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 447c3aa..d67b1a0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,12 +15,12 @@ make CUVEC_DEBUG=1 build-editable Once installed in development/editable mode, tests may be run using: ```sh -pytest -k "not perf" +make test-cov ``` To run performance tests, build with debugging disabled (`CUVEC_DEBUG=0`), then run: ```sh -pytest -k "perf" -n=0 +make test-perf python tests/test_perf.py ``` diff --git a/Makefile b/Makefile index f3abdbb..7e83b17 100644 --- a/Makefile +++ b/Makefile @@ -9,13 +9,15 @@ CCACHE= ifneq ($(CCACHE),) BUILD_CMAKE_FLAGS+= -Ccmake.define.CMAKE_CXX_COMPILER_LAUNCHER=ccache endif -.PHONY: build-editable clean deps-build deps-run build-wheel deps-docs docs docs-serve +.PHONY: build-editable test test-cov test-perf clean deps-build deps-run build-wheel deps-docs docs docs-serve build-editable: git diff --exit-code --quiet '*/src/**' || (echo "Uncommitted changes in */src"; exit 1) pip install --no-build-isolation --check-build-dependencies -Cbuild-dir=build --no-deps -t . -U -v . $(BUILD_CMAKE_FLAGS) git restore '*/src/**' -test: +test: test-cov test-perf +test-cov: pytest -k "not perf" -n=3 +test-perf: pytest -k "perf" -n=0 --cov-append clean: git clean -Xdf