Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/array-api-skips.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,6 @@ array_api_tests/test_sorting_functions.py::test_sort
array_api_tests/test_signatures.py::test_func_signature[std]
array_api_tests/test_signatures.py::test_func_signature[var]

# missing 'stream' keyword argument
array_api_tests/test_signatures.py::test_array_method_signature[to_device]

# wrong shape is returned
array_api_tests/test_linalg.py::test_vecdot
array_api_tests/test_linalg.py::test_linalg_vecdot
Expand Down
49 changes: 42 additions & 7 deletions dpnp/dpnp_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,6 @@ def mT(self):

return dpnp_array._create_from_usm_ndarray(self._array_obj.mT)

def to_device(self, target_device):
"""Transfer array to target device."""

return dpnp_array(
shape=self.shape, buffer=self.get_array().to_device(target_device)
)

@property
def sycl_queue(self):
return self._array_obj.sycl_queue
Expand Down Expand Up @@ -1693,6 +1686,48 @@ def take(self, indices, axis=None, out=None, mode="wrap"):

return dpnp.take(self, indices, axis=axis, out=out, mode=mode)

def to_device(self, device, /, *, stream=None):
"""
Transfers this array to specified target device.

Parameters
----------
device : {string, SyclDevice, SyclQueue}
Array API concept of target device. It can be an OneAPI filter
selector string, an instance of :class:`dpctl.SyclDevice`
corresponding to a non-partitioned SYCL device, an instance of
:class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device` object
returned by :obj:`dpnp.dpnp_array.dpnp_array.device` property.
stream : SyclQueue, optional
Execution queue to synchronize with. If ``None``, synchronization
is not performed.
Default: ``None``.

Returns
-------
out : dpnp.ndarray
A view if data copy is not required, and a copy otherwise.
If copying is required, it is done by copying from the original
allocation device to the host, followed by copying from host
to the target device.

Examples
--------
>>> import dpnp as np, dpctl
>>> x = np.full(100, 2, dtype=np.int64)
>>> q_prof = dpctl.SyclQueue(x.sycl_device, property="enable_profiling")
>>> # return a view with profile-enabled queue
>>> y = x.to_device(q_prof)
>>> timer = dpctl.SyclTimer()
>>> with timer(q_prof):
... z = y * y
>>> print(timer.dt)

"""

usm_res = self._array_obj.to_device(device, stream=stream)
return dpnp_array._create_from_usm_ndarray(usm_res)

# 'tobytes',
# 'tofile',
# 'tolist',
Expand Down
58 changes: 43 additions & 15 deletions dpnp/tests/test_sycl_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -1932,23 +1932,51 @@ def test_svd(shape, full_matrices, compute_uv, device):
assert_sycl_queue_equal(dpnp_s_queue, expected_queue)


@pytest.mark.parametrize(
"device_from",
valid_devices,
ids=[device.filter_string for device in valid_devices],
)
@pytest.mark.parametrize(
"device_to",
valid_devices,
ids=[device.filter_string for device in valid_devices],
)
def test_to_device(device_from, device_to):
data = [1.0, 1.0, 1.0, 1.0, 1.0]
class TestToDevice:
@pytest.mark.parametrize(
"device_from",
valid_devices,
ids=[device.filter_string for device in valid_devices],
)
@pytest.mark.parametrize(
"device_to",
valid_devices,
ids=[device.filter_string for device in valid_devices],
)
def test_basic(self, device_from, device_to):
data = [1.0, 1.0, 1.0, 1.0, 1.0]
x = dpnp.array(data, dtype=dpnp.float32, device=device_from)

y = x.to_device(device_to)
assert y.sycl_device == device_to

def test_to_queue(self):
x = dpnp.full(100, 2, dtype=dpnp.int64)
q_prof = dpctl.SyclQueue(x.sycl_device, property="enable_profiling")

y = x.to_device(q_prof)
assert_sycl_queue_equal(y.sycl_queue, q_prof)

def test_stream(self):
x = dpnp.full(100, 2, dtype=dpnp.int64)
q_prof = dpctl.SyclQueue(x.sycl_device, property="enable_profiling")
q_exec = dpctl.SyclQueue(x.sycl_device)

y = x.to_device(q_prof, stream=q_exec)
assert_sycl_queue_equal(y.sycl_queue, q_prof)

q_exec = dpctl.SyclQueue(x.sycl_device)
_ = dpnp.linspace(0, 20, num=10**5, sycl_queue=q_exec)
y = x.to_device(q_prof, stream=q_exec)
assert_sycl_queue_equal(y.sycl_queue, q_prof)

x = dpnp.array(data, dtype=dpnp.float32, device=device_from)
y = x.to_device(device_to)
def test_stream_no_sync(self):
x = dpnp.full(100, 2, dtype=dpnp.int64)
q_prof = dpctl.SyclQueue(x.sycl_device, property="enable_profiling")

assert y.sycl_device == device_to
for stream in [None, 1, dpctl.SyclDevice(), x.sycl_queue]:
y = x.to_device(q_prof, stream=stream)
assert_sycl_queue_equal(y.sycl_queue, q_prof)


@pytest.mark.parametrize(
Expand Down
Loading