Skip to content

Commit

Permalink
tests: parameterise backends
Browse files Browse the repository at this point in the history
  • Loading branch information
casperdcl committed Feb 19, 2024
1 parent 6735e2d commit 84bee0d
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 424 deletions.
File renamed without changes.
2 changes: 1 addition & 1 deletion cuvec/cpython.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import numpy as np

from . import cuvec_cpython as cu
from ._common import Shape, _generate_helpers, typecodes
from ._utils import Shape, _generate_helpers, typecodes

__all__ = [
'CuVec', 'zeros', 'ones', 'zeros_like', 'ones_like', 'copy', 'asarray', 'Shape', 'typecodes']
Expand Down
14 changes: 7 additions & 7 deletions cuvec/pybind11.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import numpy as np

from . import cuvec_pybind11 as cu # type: ignore [attr-defined] # yapf: disable
from ._common import CVector, Shape, _generate_helpers, typecodes
from ._utils import CVector, Shape, _generate_helpers, typecodes

__all__ = [
'CuVec', 'zeros', 'ones', 'zeros_like', 'ones_like', 'copy', 'asarray', 'retarray', 'Shape',
Expand Down Expand Up @@ -69,14 +69,14 @@ def __new__(cls, arr):
if Pybind11Vector.is_instance(arr):
log.debug("wrap pyraw %s", type(arr))
obj = np.asarray(arr).view(cls)
obj.pyvec = arr
obj._vec = arr
obj.cuvec = arr.cuvec
return obj
if isinstance(arr, CuVec) and hasattr(arr, 'pyvec'):
if isinstance(arr, CuVec) and hasattr(arr, '_vec'):
log.debug("new view")
obj = np.asarray(arr).view(cls)
obj.pyvec = arr.pyvec
obj.cuvec = arr.pyvec.cuvec
obj._vec = arr._vec
obj.cuvec = arr._vec.cuvec
return obj
if isinstance(arr, np.ndarray):
log.debug("copy")
Expand All @@ -94,11 +94,11 @@ def __cuda_array_interface__(self) -> Dict[str, Any]:
dedent("""\
`numpy.ndarray` object has no attribute `cuvec`:
try using `cuvec.asarray()` first."""))
return self.pyvec.__cuda_array_interface__
return self._vec.__cuda_array_interface__

Check warning on line 97 in cuvec/pybind11.py

View check run for this annotation

Codecov / codecov/patch

cuvec/pybind11.py#L97

Added line #L97 was not covered by tests

def resize(self, new_shape: Shape):
"""Change shape (but not size) of array in-place."""
self.pyvec.shape = new_shape
self._vec.shape = new_shape
super().resize(new_shape, refcheck=False)


Expand Down
14 changes: 7 additions & 7 deletions cuvec/swig.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import numpy as np

from . import swvec as sw # type: ignore [attr-defined] # yapf: disable
from ._common import CVector, Shape, _generate_helpers, typecodes
from ._utils import CVector, Shape, _generate_helpers, typecodes

__all__ = [
'CuVec', 'zeros', 'ones', 'zeros_like', 'ones_like', 'copy', 'asarray', 'retarray', 'Shape',
Expand Down Expand Up @@ -75,14 +75,14 @@ def __new__(cls, arr):
if SWIGVector.is_instance(arr):
log.debug("wrap swraw %s", type(arr))
obj = np.asarray(arr).view(cls)
obj.swvec = arr
obj._vec = arr
obj.cuvec = arr.cuvec
return obj
if isinstance(arr, CuVec) and hasattr(arr, 'swvec'):
if isinstance(arr, CuVec) and hasattr(arr, '_vec'):
log.debug("new view")
obj = np.asarray(arr).view(cls)
obj.swvec = arr.swvec
obj.cuvec = arr.swvec.cuvec
obj._vec = arr._vec
obj.cuvec = arr._vec.cuvec
return obj
if isinstance(arr, np.ndarray):
log.debug("copy")
Expand All @@ -100,11 +100,11 @@ def __cuda_array_interface__(self) -> Dict[str, Any]:
dedent("""\
`numpy.ndarray` object has no attribute `cuvec`:
try using `cuvec.asarray()` first."""))
return self.swvec.__cuda_array_interface__
return self._vec.__cuda_array_interface__

Check warning on line 103 in cuvec/swig.py

View check run for this annotation

Codecov / codecov/patch

cuvec/swig.py#L103

Added line #L103 was not covered by tests

def resize(self, new_shape: Shape):
"""Change shape (but not size) of array in-place."""
self.swvec.shape = new_shape
self._vec.shape = new_shape
super().resize(new_shape, refcheck=False)


Expand Down
10 changes: 0 additions & 10 deletions tests/conftest.py

This file was deleted.

193 changes: 193 additions & 0 deletions tests/test_common.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,30 @@
"""Common (parameterised) tests for cuvec.{cpython,pybind11,swig}"""
import logging

import numpy as np
from pytest import importorskip, mark, raises

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/
from cuvec import example_pybind11 # type: ignore # yapf: disable
from cuvec import pybind11 as py
except ImportError:
py, example_pybind11 = None, None # type: ignore # yapf: disable


shape = 127, 344, 344


def test_includes():
Expand All @@ -14,3 +40,170 @@ def test_cmake_prefix():
for i in cu.cmake_prefix.iterdir()} == {
f'AMYPADcuvec{i}.cmake'
for i in ('Config', 'ConfigVersion', 'Targets', 'Targets-release')}


@mark.parametrize("cu,CVector", [(py, 'Pybind11Vector'), (sw, 'SWIGVector')])
def test_CVector_strides(cu, CVector):
v = getattr(cu, CVector)('f', shape)
a = np.asarray(v)
assert a.shape == shape
assert a.strides == (473344, 1376, 4)


@mark.parametrize("spec,result", [("i", np.int32), ("d", np.float64)])
@mark.parametrize("init", ["zeros", "ones"])
@mark.parametrize("cu", [cp, py, sw])
def test_create(cu, init, spec, result):
a = np.asarray(getattr(cu, init)(shape, spec))
assert a.dtype == result
assert a.shape == shape
assert (a == (0 if init == 'zeros' else 1)).all()

b = getattr(cu, f'{init}_like')(a)
assert b.shape == a.shape
assert b.dtype == a.dtype


@mark.parametrize("cu", [cp, py, sw])
def test_copy(cu):
a = np.random.random(shape)
b = np.asarray(cu.copy(a))
assert a.shape == b.shape
assert a.dtype == b.dtype
assert (a == b).all()


@mark.parametrize("cu,classname", [(cp, "raw <class 'PyCuVec_{typechar}'>"),
(py, "pyraw <class 'cuvec.pybind11.Pybind11Vector'>"),
(sw, "swraw <class 'cuvec.swig.SWIGVector'>")])
def test_CuVec_creation(cu, classname, caplog):
with raises(TypeError):
cu.CuVec()

with raises(NotImplementedError):
cu.CuVec(shape)

caplog.set_level(logging.DEBUG)
caplog.clear()
v = cu.CuVec(np.ones(shape, dtype='h'))
assert [i[1:] for i in caplog.record_tuples] == [
(10, 'copy'), (10, f"wrap {classname}".format(typechar='h'))]
assert v.shape == shape
assert v.dtype.char == 'h'
assert (v == 1).all()

caplog.clear()
v = cu.zeros(shape, 'd')
assert [i[1:] for i in caplog.record_tuples] == [
(10, f"wrap {classname}".format(typechar='d'))]

caplog.clear()
v[0, 0, 0] = 1
assert not caplog.record_tuples
w = cu.CuVec(v)
assert [i[1:] for i in caplog.record_tuples] == [(10, "new view")]

caplog.clear()
assert w[0, 0, 0] == 1
v[0, 0, 0] = 9
assert w[0, 0, 0] == 9
assert v.cuvec is w.cuvec
assert v.data == w.data
assert not caplog.record_tuples


@mark.parametrize("cu", [py, sw])
def test_asarray(cu):
v = cu.asarray(np.random.random(shape))
w = cu.CuVec(v)
assert w.cuvec == v.cuvec
assert (w == v).all()
assert str(w._vec) == str(v._vec)
assert np.asarray(w._vec).data == np.asarray(v._vec).data
x = cu.asarray(w._vec)
assert x.cuvec == v.cuvec
assert (x == v).all()
assert str(x._vec) == str(v._vec)
assert np.asarray(x._vec).data == np.asarray(v._vec).data
y = cu.asarray(x.tolist())
assert y.cuvec != v.cuvec
assert (y == v).all()
assert str(y._vec) != str(v._vec)
assert np.asarray(y._vec).data == np.asarray(v._vec).data
z = cu.asarray(v[:])
assert z.cuvec != v.cuvec
assert (z == v[:]).all()
assert str(z._vec) != str(v._vec)
assert np.asarray(z._vec).data == np.asarray(v._vec).data
s = cu.asarray(v[1:])
assert s.cuvec != v.cuvec
assert (s == v[1:]).all()
assert str(s._vec) != str(v._vec)
assert np.asarray(s._vec).data != np.asarray(v._vec).data
with raises(IOError):
cu.asarray(s._vec.cuvec, ownership='error')


@mark.parametrize("cu", [py, sw])
def test_resize(cu):
v = cu.asarray(np.random.random(shape))
v.resize(shape[::-1])
assert v.shape == shape[::-1]
assert v._vec.shape == v.shape
v.resize(v.size)
assert v.shape == (v.size,)
assert v._vec.shape == v.shape


@mark.parametrize("cu", [cp, py, sw])
def test_cuda_array_interface(cu):
cupy = importorskip("cupy")
from cuvec import dev_sync

v = cu.asarray(np.random.random(shape))
assert set(v.__cuda_array_interface__) == {'shape', 'typestr', 'data', 'version'}

c = cupy.asarray(v)
assert (c == v).all()
c[0, 0, 0] = 1
dev_sync()
assert c[0, 0, 0] == v[0, 0, 0]
c[0, 0, 0] = 0
dev_sync()
assert c[0, 0, 0] == v[0, 0, 0]

if hasattr(v, '_vec'):
d = cupy.asarray(v._vec)
d[0, 0, 0] = 1
dev_sync()
assert d[0, 0, 0] == c[0, 0, 0] == v[0, 0, 0]
d[0, 0, 0] = 0
dev_sync()
assert d[0, 0, 0] == c[0, 0, 0] == v[0, 0, 0]

ndarr = v + 1
assert ndarr.shape == v.shape
assert ndarr.dtype == v.dtype
with raises(AttributeError):
ndarr.__cuda_array_interface__


@mark.parametrize("cu,ex", [(py, example_pybind11), (sw, example_swig)])
def test_increment(cu, ex):
a = cu.zeros((1337, 42), 'f')
assert (a == 0).all()
ex.increment2d_f(a.cuvec, a.cuvec)
assert (a == 1).all()

a[:] = 0
assert (a == 0).all()

b = cu.retarray(ex.increment2d_f(a.cuvec))
assert (b == 1).all()

c = cu.retarray(ex.increment2d_f(b.cuvec, a.cuvec), a)
assert (a == 2).all()
assert c.cuvec == a.cuvec
assert (c == a).all()
assert str(c._vec) == str(a._vec)
assert np.asarray(c._vec).data == np.asarray(a._vec).data
Loading

0 comments on commit 84bee0d

Please sign in to comment.