Skip to content

Commit 0168438

Browse files
committed
Add more tests to cover different use cases
1 parent a0e32c0 commit 0168438

File tree

2 files changed

+249
-0
lines changed

2 files changed

+249
-0
lines changed

tests/test_dlpack.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import sys
2+
import pytest
3+
4+
import numpy
5+
import dpnp
6+
from numpy.testing import assert_array_equal
7+
from .helper import (
8+
get_all_dtypes,
9+
)
10+
11+
device_oneAPI = 14 # DLDeviceType.kDLOneAPI
12+
13+
class TestDLPack:
14+
# @pytest.mark.parametrize("max_version", [(0, 0), None, (1, 0), (100, 3)])
15+
# def test_dunder_dlpack_refcount(self, max_version):
16+
# x = dpnp.arange(5)
17+
# y = x.__dlpack__(max_version=max_version)
18+
# print()
19+
# print(sys.getrefcount(x), sys.getrefcount(y))
20+
# assert sys.getrefcount(x) == 2
21+
# del y
22+
# print(sys.getrefcount(x))
23+
# assert sys.getrefcount(x) == 2
24+
25+
@pytest.mark.parametrize("stream", [None, 1])
26+
def test_stream(self, stream):
27+
x = dpnp.arange(5)
28+
x.__dlpack__(stream=stream)
29+
30+
@pytest.mark.parametrize("copy", [True, None, False])
31+
def test_copy(self, copy):
32+
x = dpnp.arange(5)
33+
x.__dlpack__(copy=copy)
34+
35+
def test_wrong_copy(self):
36+
x = dpnp.arange(5)
37+
x.__dlpack__(copy=dpnp.array([1, 2, 3]))
38+
39+
@pytest.mark.parametrize("xp", [dpnp, numpy])
40+
@pytest.mark.parametrize("dt", get_all_dtypes(no_none=True))
41+
def test_dtype_passthrough(self, xp, dt):
42+
x = xp.arange(5).astype(dt)
43+
y = xp.from_dlpack(x)
44+
45+
assert y.dtype == x.dtype
46+
assert_array_equal(x, y)
47+
48+
@pytest.mark.parametrize("xp", [dpnp, numpy])
49+
def test_non_contiguous(self, xp):
50+
x = xp.arange(25).reshape((5, 5))
51+
52+
y1 = x[0]
53+
assert_array_equal(y1, xp.from_dlpack(y1))
54+
55+
y2 = x[:, 0]
56+
assert_array_equal(y2, xp.from_dlpack(y2))
57+
58+
y3 = x[1, :]
59+
assert_array_equal(y3, xp.from_dlpack(y3))
60+
61+
y4 = x[1]
62+
assert_array_equal(y4, xp.from_dlpack(y4))
63+
64+
y5 = xp.diagonal(x).copy()
65+
assert_array_equal(y5, xp.from_dlpack(y5))
66+
67+
def test_device(self):
68+
x = dpnp.arange(5)
69+
assert x.__dlpack_device__()[0] == device_oneAPI
70+
y = dpnp.from_dlpack(x)
71+
assert y.__dlpack_device__()[0] == device_oneAPI
72+
z = y[::2]
73+
assert z.__dlpack_device__()[0] == device_oneAPI
74+
75+
# def dlpack_deleter_exception(self, max_version):
76+
# x = np.arange(5)
77+
# _ = x.__dlpack__(max_version=max_version)
78+
# raise RuntimeError
79+
80+
# @pytest.mark.parametrize("max_version", [None, (1, 0)])
81+
# def test_dlpack_destructor_exception(self, max_version):
82+
# with pytest.raises(RuntimeError):
83+
# self.dlpack_deleter_exception(max_version=max_version)
84+
85+
# def test_readonly(self):
86+
# x = np.arange(5)
87+
# x.flags.writeable = False
88+
# # Raises without max_version
89+
# with pytest.raises(BufferError):
90+
# x.__dlpack__()
91+
92+
# # But works fine if we try with version
93+
# y = np.from_dlpack(x)
94+
# assert not y.flags.writeable
95+
96+
# def test_ndim0(self):
97+
# x = np.array(1.0)
98+
# y = np.from_dlpack(x)
99+
# assert_array_equal(x, y)
100+
101+
# def test_size1dims_arrays(self):
102+
# x = np.ndarray(dtype='f8', shape=(10, 5, 1), strides=(8, 80, 4),
103+
# buffer=np.ones(1000, dtype=np.uint8), order='F')
104+
# y = np.from_dlpack(x)
105+
# assert_array_equal(x, y)
106+
107+
# def test_copy(self):
108+
# x = np.arange(5)
109+
110+
# y = np.from_dlpack(x)
111+
# assert np.may_share_memory(x, y)
112+
# y = np.from_dlpack(x, copy=False)
113+
# assert np.may_share_memory(x, y)
114+
# y = np.from_dlpack(x, copy=True)
115+
# assert not np.may_share_memory(x, y)
116+
117+
# def test_device(self):
118+
# x = np.arange(5)
119+
# # requesting (1, 0), i.e. CPU device works in both calls:
120+
# x.__dlpack__(dl_device=(1, 0))
121+
# np.from_dlpack(x, device="cpu")
122+
# np.from_dlpack(x, device=None)
123+
124+
# with pytest.raises(ValueError):
125+
# x.__dlpack__(dl_device=(10, 0))
126+
# with pytest.raises(ValueError):
127+
# np.from_dlpack(x, device="gpu")
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import unittest
2+
3+
import pytest
4+
5+
import numpy
6+
import dpnp as cupy
7+
import dpctl.tensor._dlpack as dlp
8+
from tests.third_party.cupy import testing
9+
10+
11+
def _gen_array(dtype):
12+
if cupy.issubdtype(dtype, numpy.unsignedinteger):
13+
array = cupy.random.randint(
14+
0, 10, size=(2, 3)).astype(dtype)
15+
elif cupy.issubdtype(dtype, cupy.integer):
16+
array = cupy.random.randint(
17+
-10, 10, size=(2, 3)).astype(dtype)
18+
elif cupy.issubdtype(dtype, cupy.floating):
19+
array = cupy.random.rand(
20+
2, 3).astype(dtype)
21+
elif cupy.issubdtype(dtype, cupy.complexfloating):
22+
array = cupy.random.random((2, 3)).astype(dtype)
23+
elif dtype == cupy.bool_:
24+
array = cupy.random.randint(0, 2, size=(2, 3)).astype(cupy.bool_)
25+
else:
26+
assert False, f'unrecognized dtype: {dtype}'
27+
return array
28+
29+
30+
class TestDLPackConversion(unittest.TestCase):
31+
@testing.for_all_dtypes(no_bool=False)
32+
def test_conversion(self, dtype):
33+
orig_array = _gen_array(dtype)
34+
tensor = orig_array.__dlpack__()
35+
out_array = dlp.from_dlpack_capsule(tensor)
36+
testing.assert_array_equal(orig_array, out_array)
37+
assert orig_array._pointer == out_array._pointer
38+
39+
40+
@testing.parameterize(*testing.product({
41+
'memory': ('device', 'managed')
42+
}))
43+
class TestNewDLPackConversion(unittest.TestCase):
44+
@testing.for_all_dtypes(no_bool=False)
45+
def test_conversion(self, dtype):
46+
orig_array = _gen_array(dtype)
47+
out_array = cupy.from_dlpack(orig_array)
48+
testing.assert_array_equal(orig_array, out_array)
49+
assert orig_array._pointer == out_array._pointer
50+
51+
@pytest.mark.skip(reason="no stream support")
52+
def test_stream(self):
53+
allowed_streams = ['null', True]
54+
if not cuda.runtime.is_hip:
55+
allowed_streams.append('ptds')
56+
57+
# stream order is automatically established via DLPack protocol
58+
for src_s in [self._get_stream(s) for s in allowed_streams]:
59+
for dst_s in [self._get_stream(s) for s in allowed_streams]:
60+
with src_s:
61+
orig_array = _gen_array(cupy.float32)
62+
# If src_s != dst_s, dst_s waits until src_s complete.
63+
# Null stream (0) must be passed as streamLegacy (1)
64+
# on CUDA.
65+
if not cuda.runtime.is_hip and dst_s.ptr == 0:
66+
s_ptr = 1
67+
else:
68+
s_ptr = dst_s.ptr
69+
dltensor = orig_array.__dlpack__(stream=s_ptr)
70+
71+
with dst_s:
72+
out_array = cupy.from_dlpack(dltensor)
73+
testing.assert_array_equal(orig_array, out_array)
74+
testing.assert_array_equal(
75+
orig_array.data.ptr, out_array.data.ptr)
76+
77+
78+
class TestDLTensorMemory(unittest.TestCase):
79+
# def setUp(self):
80+
# self.old_pool = cupy.get_default_memory_pool()
81+
# self.pool = cupy.cuda.MemoryPool()
82+
# cupy.cuda.set_allocator(self.pool.malloc)
83+
84+
# def tearDown(self):
85+
# self.pool.free_all_blocks()
86+
# cupy.cuda.set_allocator(self.old_pool.malloc)
87+
88+
def test_deleter(self):
89+
# memory is freed when tensor is deleted, as it's not consumed
90+
array = cupy.empty(10)
91+
tensor = array.__dlpack__()
92+
# str(tensor): <capsule object "dltensor" at 0x7f7c4c835330>
93+
assert "\"dltensor\"" in str(tensor)
94+
# assert self.pool.n_free_blocks() == 0
95+
# del array
96+
# assert self.pool.n_free_blocks() == 0
97+
# del tensor
98+
# assert self.pool.n_free_blocks() == 1
99+
100+
def test_deleter2(self):
101+
# memory is freed when array2 is deleted, as tensor is consumed
102+
array = cupy.empty(10)
103+
tensor = array.__dlpack__()
104+
assert "\"dltensor\"" in str(tensor)
105+
array2 = dlp.from_dlpack_capsule(tensor)
106+
assert "\"used_dltensor\"" in str(tensor)
107+
# assert self.pool.n_free_blocks() == 0
108+
# del array
109+
# assert self.pool.n_free_blocks() == 0
110+
# del array2
111+
# assert self.pool.n_free_blocks() == 1
112+
# del tensor
113+
# assert self.pool.n_free_blocks() == 1
114+
115+
def test_multiple_consumption_error(self):
116+
# Prevent segfault, see #3611
117+
array = cupy.empty(10)
118+
tensor = array.__dlpack__()
119+
array2 = dlp.from_dlpack_capsule(tensor)
120+
with pytest.raises(ValueError) as e:
121+
array3 = dlp.from_dlpack_capsule(tensor)
122+
assert 'consumed multiple times' in str(e.value)

0 commit comments

Comments
 (0)