Fix abort in dpnp.all / dpnp.any over an empty axis - #3021
Conversation
dpnp.all / dpnp.any submitted the reduction kernel unconditionally. When the input has no elements to reduce over - e.g. all(zeros((0, 3, 4))) or a reduction along a zero-length axis - the reduction extent is zero and the kernel is launched with a zero-sized nd_range. That is a silent no-op on runtimes built with NDEBUG, but aborts on an assertions-enabled SYCL runtime (adjustNDRangePerKernel asserts NDR.LocalSize[0] == 0 when GlobalSize is 0). Short-circuit in _boolean_reduction when the (permuted) input is empty: build the result directly with the reduction identity (True for all, False for any). This is correct for both empty sub-cases - an empty output (fill value is irrelevant) and a zero-length reduced axis (identity is the answer) - and submits no kernel.
Use an if/else so the empty-input and reduction paths share the single trailing keepdims block instead of repeating it.
|
View rendered docs @ https://intelpython.github.io/dpnp/pull/3021/index.html |
|
Array API standard conformance tests for dpnp=0.21.0dev3=py314h509198e_42 ran successfully. |
|
@antonwolfy |
|
I was thinking about that.. and it should be added to if (dst_nelems == 0) {
// empty result: nothing to write
return std::make_pair(sycl::event(), sycl::event());
}
if (red_nelems == 0) {
// empty reduction extent: result is the op identity, which this kernel
// cannot produce; the caller must handle it
throw py::value_error(
"Reduction over an empty axis is not supported");
}but I wondering why we already had in the code a hadnling depending on // TODO: should be dst_nelems == 0?
if ((is_src_c_contig && is_dst_c_contig) ||
(is_src_f_contig && dst_nelems == 0)) {@ndgrigorian, if you remember why it was added this way and can confirm it's not needed, I'll add the above handling to |
dpnp.allanddpnp.anyaborted the process when reducing over an empty axis, e.g.:_boolean_reductionalways allocated a temporary and launched the reduction kernel. When the reduced extent is zero (a reduced dimension has length 0), the kernel is submitted with a zero-sizednd_range. That is a silent no-op on a SYCL runtime built withNDEBUG, but aborts on an assertions-enabled runtime, whereadjustNDRangePerKernelassertsNDR.LocalSize[0] == 0wheneverGlobalSize[0]is0:This PR proposes to short-circuit in
_boolean_reductionwhen the (permuted) input has no elements, building the result directly with the reduction identity instead of launching a kernel.alluses identityTrue,anyusesFalse. A singlex_tmp.size == 0check covers both empty sub-cases correctly:all([]) is True,any([]) is False.Note, the issue was identified when building with the nightly LLVM SYCL compiler and running dpnp tests.
And the tests are passing now without any crash.