Skip to content

Update implementation of dpnp.putmask - #3014

Open
vlad-perevezentsev wants to merge 17 commits into
masterfrom
add_putmask_impl
Open

Update implementation of dpnp.putmask#3014
vlad-perevezentsev wants to merge 17 commits into
masterfrom
add_putmask_impl

Conversation

@vlad-perevezentsev

@vlad-perevezentsev vlad-perevezentsev commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

This PR proposes a new implementation of dpnp.putmask replacing the legacy dpnp_putmask implementation with dedicated SYCL kernels : a vectorized contiguous kernel and a strided kernel for F-contiguous/transposed arrays.
It also fully reworks the putmask tests by adding TestPutMask

Performance results on PVC are below:

image
  • Have you provided a meaningful PR description?
  • Have you added a test, reproducer or referred to an issue with a reproducer?
  • Have you tested your changes locally for CPU and GPU devices?
  • Have you made sure that new changes do not introduce compiler warnings?
  • Have you checked performance impact of proposed changes?
  • Have you added documentation for your changes, if necessary?
  • Have you added your changes to the changelog?

@vlad-perevezentsev vlad-perevezentsev self-assigned this Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

View rendered docs @ https://intelpython.github.io/dpnp/pull/3014/index.html

@vlad-perevezentsev
vlad-perevezentsev marked this pull request as ready for review August 7, 2026 12:25
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Array API standard conformance tests for dpnp=0.21.0dev6=py314ha0e2e8e_18 ran successfully.
Passed: 1375
Failed: 0
Skipped: 7

@coveralls

coveralls commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Coverage Status

coverage: 78.507% (+0.04%) from 78.472% — add_putmask_impl into master

@antonwolfy antonwolfy added this to the 0.21.0 release milestone Aug 19, 2026
Comment thread dpnp/backend/extensions/indexing/CMakeLists.txt Outdated
Comment thread dpnp/dpnp_iface_indexing.py Outdated
Comment thread dpnp/backend/extensions/indexing/indexing_py.cpp Outdated
Comment thread dpnp/dpnp_iface_indexing.py Outdated
Comment thread dpnp/dpnp_iface_indexing.py Outdated
Comment thread dpnp/tests/third_party/cupy/indexing_tests/test_insert.py Outdated
Comment thread dpnp/backend/extensions/indexing/putmask.cpp
Comment thread dpnp/backend/kernels/indexing/putmask.hpp Outdated
Comment thread dpnp/backend/kernels/indexing/putmask.hpp Outdated
Comment thread dpnp/backend/kernels/indexing/putmask.hpp Outdated
@antonwolfy antonwolfy mentioned this pull request Aug 21, 2026
7 tasks
Comment thread dpnp/backend/kernels/indexing/putmask.hpp Outdated
usm_mask = dpt.astype(usm_mask, dpnp.bool, copy=False)

if usm_a.shape != usm_mask.shape:
raise ValueError("mask and data must be the same size")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raise ValueError("mask and data must be the same size")
raise ValueError("mask and data must be the same shape")

numpy.putmask(a, m, v)
dpnp.putmask(ia, im, iv)
assert_array_equal(a, ia)
class TestPutMask:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing cross-queue / usm_type propagation tests in test_sycl_queue.py / test_usm_type.py

numpy.putmask(a, m, v)
dpnp.putmask(ia, im, iv)
assert_array_equal(a, ia)
class TestPutMask:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vectorized fast path is still untested. The contig vectorized branch needs nelems ≳ 128–256; every array in TestPutMask is ≤ 24 elements.

assert_array_equal(ia, a)

@pytest.mark.parametrize("dt", get_all_dtypes(no_none=True))
def test_scalar_values(self, dt):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scalar unsafe-cast path is untested. Needs to cover also unsafe scalar truncation/wraparound.


x1_desc = dpnp.get_dpnp_descriptor(
x1, copy_when_strides=False, copy_when_nondefault_queue=False
dpnp.check_supported_arrays_type(a)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed, the same check is done by dpnp.get_usm_ndarray

// THE POSSIBILITY OF SUCH DAMAGE.
//*****************************************************************************

#include <algorithm>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing <cstdint>

check_writable({&dst}, names);

// values must be C-contiguous
check_c_contig({&values}, names);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing overlap check

// the contig kernel cycles `values` by the memory-linear index, which
// matches numpy's C-order `values.flat` only for C-contiguous data
const bool all_c_contig = dst.is_c_contiguous() && mask.is_c_contiguous() &&
values.is_c_contiguous();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to remove values.is_c_contiguous() from here?

* @tparam T Type of input vector `dst` and `values` and of result vector `dst`.
*/
template <typename T>
struct PutMaskOutputType

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not seem we need that, and so can be dropped.
Similarly to dpnp/tensor/libtensor/include/kernels/where.hpp:

template <typename fnT, typename T, typename condT>
struct WhereStridedFactory
{
    fnT get()
    {
        fnT fn = where_strided_impl<T, condT>;
        return fn;
    }
};

template <typename fnT, typename T, typename condT>
struct WhereContigFactory
{
    fnT get()
    {
        fnT fn = where_contig_impl<T, condT>;
        return fn;
    }
};


int eff_nd = nd;
if (nd == 0) {
// scalar arrays: single-element 1D iteration

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems unreachable defensive code (0-d dst → contig path).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants