Fix too strict interleaved/unique layout check#9788
Conversation
Signed-off-by: Kamil Tokarski <ktokarski@nvidia.com>
|
@mhoemmen could you take a look at this? |
fbusato
left a comment
There was a problem hiding this comment.
The improvement makes sense at high-level, but I'm still not 100% sure about the implications of having situations like the example you provided. Namely, a row that "starts" before the previous one ends. It is not overlapping at index level, but still hard to predict potentially issues.
| # include <cuda/experimental/__copy_bytes/mdspan_to_raw_tensor.cuh> | ||
| # include <cuda/experimental/__copy_bytes/types.cuh> | ||
|
|
||
| # include <iostream> |
| { | ||
| const auto __extent = static_cast<__stride_t>(__extents[__i]); | ||
| if (__extent * cudax::__abs_integer(__strides[__i]) > cudax::__abs_integer(__strides[__i + 1])) | ||
| const __stride_t extent = __extents[__i]; |
There was a problem hiding this comment.
| const __stride_t extent = __extents[__i]; | |
| const auto __extent = static_cast<__stride_t>(__extents[__i]); |
| { | ||
| return true; | ||
| } | ||
| // note that slicing a layout, while it may increase _abs_stride, |
There was a problem hiding this comment.
please use 120 columns width
| const auto __tensor = cudax::__to_raw_tensor(__mdspan); | ||
| const auto __sorted = cudax::__sort_by_stride(__tensor); | ||
| using __stride_t = decltype(__sorted.__strides[0]); | ||
| using __stride_t = ::cuda::std::remove_cvref_t<decltype(__sorted.__strides[0])>; |
| } | ||
| // note that slicing a layout, while it may increase _abs_stride, | ||
| // cannot increase dimension's contribution to max_dist | ||
| __max_dist += (extent - 1) * __abs_stride; |
There was a problem hiding this comment.
| __max_dist += (extent - 1) * __abs_stride; | |
| __max_dist += (__extent - 1) * __abs_stride; |
| // max_offset = sum((e_j - 1) * s_j for j in range(i) if s_j > 0) | ||
| // min_offset = sum((e_j - 1) * s_j for j in range(i) if s_j < 0) | ||
| // max_dist = max_offset - min_offset = sum((e_j - 1) * |s_j| for j in range(i)) | ||
| __stride_t __max_dist = 0; |
There was a problem hiding this comment.
this should be the extent type because it needs to be representable by required_span_size()
There was a problem hiding this comment.
Arbitrary layout mappings aren't necessarily strided, so I'm not sure if speaking of "strides" would generally make sense.
There was a problem hiding this comment.
I think I understand now. Is the goal to test specifically layout_stride_relaxed::mapping to see whether it's unique? If so, then this test might make sense.
| //! @brief Conservative check for non-unique/interleaved layout. | ||
| //! | ||
| //! Sorts modes by ascending absolute stride, then verifies two conditions: | ||
| //! 1. No mode with extent > 1 has stride == 0 (broadcast) | ||
| //! 2. No mode's span (extent * |stride|) exceeds the next mode's |stride| | ||
| //! A layout is non-unique/interleaved if there exists two different indices | ||
| //! that map to the same element (i.e. `dot(idx1, strides) == dot(idx2, strides)`). |
There was a problem hiding this comment.
I don't quite understand the purpose of this check. Is the goal to check the preconditions of the strides in the layout_stride::mapping(extents, array) constructor? Is the goal to check the strides of a general is_strided() == true mapping? Or is the goal to check whether an arbitrary mapping is unique?
If the goal is to check whether an arbitrary mapping is unique, then why not use the is_unique() query?
There was a problem hiding this comment.
I think I understand now. Is the goal to test specifically layout_stride_relaxed::mapping to see whether it's unique? If so, then this test might make sense.
| //! vectorizing) applied to a dense layout. In general case, it may | ||
| //! incorrectly return true for non-interleaved/unique layouts. | ||
| //! | ||
| //! @param[in] __mdspan Mdspan view to inspect |
There was a problem hiding this comment.
If I have an mdspan with arbitrary layout, then I can just ask its layout mapping if is_unique() is true.
Layout mappings can implement that check conservatively by returning false, but It's up to the layout mapping to decide that. For the special case of layout_stride_relaxed, the right approach would be for layout_stride_relaxed::mapping to have this code.
|
@Jacobfaib wrote:
Thanks for asking! : - ) I'm not quite sure what's going on here. If I have an For the special case of For user-defined strided layouts (i.e., layouts that aren't |
Description
closes
The
__has_interleaved_stride_orderutility blocks callers from writing into (used incopy(mdspan_dst, mdspan_src)orfill_bytes(mdspan)) mdspans that have multiple indices mapped to the same memory offset. However, the check is too strict, blocking valid cases that arise from slicing a tensor with step > 1.For instance
The new check, is still a conservative approximation (never misses interleaved layout but may flag too much as interleaved),
but returns less false postives and should handle all layouts that are a result of permuting, slicing, reshaping or broadcasting dense layout.
Checklist