-
Notifications
You must be signed in to change notification settings - Fork 412
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add bound checks in RangePolicy and MDRangePolicy #6617
Conversation
core/src/KokkosExp_MDRangePolicy.hpp
Outdated
if (m_upper[i] < m_lower[i]) { | ||
std::stringstream msg; | ||
msg << "Kokkos::MDRangePolicy bounds error: The lower bound (" | ||
<< m_lower[i] << ") is greater than its upper bound (" << m_upper[i] | ||
<< ") in rank " << i + 1 << "."; | ||
Kokkos::abort(msg.str().c_str()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you consider just treating it as an empty range if the upper bound is lower than the lower bound?
Isn't that what we are doing for RangePolicy
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't realize that RangePolicy
behaves this way, but the idea of silently changing a policy to be an empty range seems unhelpful for the users, although I admit that given a lower bound that's higher than its upper bound, making it an empty range is most logical.
In case of MDRangePolicy
, since the lower bound and upper bound checks will be needed for all ranks, should all ranges become empty ranges upon finding a failed bound check or should only failing ranks be empty ranges?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally think we should do something that is the most useful for the users, which IMO is catching the problem as early as possible. Adopting the solution proposed in this PR seems good to me because the problem is caught immediately during the construction of the policy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, at first I was also thinking that aborting was the right thing to do; but just emptying the range is also a good solution, afterall when doing for(int i=0; i<-10;i++)
this is valid code that may happen when implementating an algorithm where the bound are computed using analytical expressions, and the desired behavior is doing nothing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"when implementating an algorithm where the bound are computed using analytical expressions, and the desired behavior is doing nothing." what do you mean by:
- using analytical expressions,
- the desired behavor is doing nothing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to differentiate what concerns the algirithm vs how the MDRangePolicy works.
I don't think it would be right to tie the implementation/semantics of the MDRangePolicy to something that pertains a certain algorithm.
It should be up to the algorithm to translate its requirements into something that makes sense for MDRangePolicy.
if you algorithm has meaning for a range like [15, -20], then it should be up to you to translate that into an empty MDRangePolicy if you want it do nothing.
IMO, the MDRangePolicy should either accept a valid set of bounds or empty bounds but NOT "flipped" bounds.
Does it make sense what I am trying to convey?
Another option is to state clearly somewhere that the behavior of MDRangePolicy is such that:
- empty bounds yield empty md range
- valid bounds yield valid md range
- invalid bounds (like above) are internally transformed into empty md range
and define what is valid and invalid. But now we get into a rabbit hole, bc for example what if one rank has valid bounds and one rank does not? do you treat the whole thing an empty md range?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with your last option (3 bullets above) and that it should be clearly stated in the documentation.
IMHO, if one rank has upper bound < lower bound then the right behavior, is don't do any iteration at all; afterall this is what happen when you have two nest for loops, and one of them has invalid range.
Somehow, about your 3rd bullet above, when upper bound is < lower bound, it is not really an invalid range, just an empty range, but for a different reason.
The last point is that Range and MDRange policy should behave the same. If you think aborting is best in case of invalid range in MDRange, then Range policy should behave likewise.
Finally, I don't have strong opinion here, just saying that first I was thinking aborting was the right behavior, but finally I can live fine with emptying the range.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe, we just discuss it on Wednesday in the meeting.
c1e32ce
to
341b464
Compare
@@ -93,6 +93,27 @@ TEST(TEST_CATEGORY_DEATH, policy_bounds_unsafe_narrowing_conversions) { | |||
}, | |||
"unsafe narrowing conversion"); | |||
} | |||
|
|||
TEST(TEST_CATEGORY_DEATH, policy_invalid_bounds) { | |||
using Policy = Kokkos::MDRangePolicy<TEST_EXECSPACE, Kokkos::Rank<5>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why rank 5 if we can trigger with 2?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No real reason. Changed to 2 ranks and removed the second test case.
}, | ||
"Kokkos::MDRangePolicy bounds error: The lower bound \\(100\\) is " | ||
"greater " | ||
"than its upper bound \\(90\\) in dimension 1\\."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hope the test fails...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(should fail in dimension 0 no?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The failing dimension depends if you use Iterate::Left
or Iterate::Right
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we expect the test as is should not pass on all backends?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the test should pass for some backends and fail for others
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have we decided anyway that the bounds check should always produce an error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(should fail in dimension 0 no?)
@dalg24
@Rombur is correct here. It's Iterate::Right
by default here. So the check would start from rank-1
dimension first.
Looks like I didn't think this all the way through. I'll modify this based on the backend.
@masterleinad No, we haven't decided on that. If we do an abort here for MDRangePolicy
, it's inconsistent from how RangePolicy
handles this, so I think we definitely should discuss at some point before merging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would vote to abort and also change range policy to reflect this for the same reason of what I said in the other comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed to check against the policy's iteration pattern.
I would vote to abort and also change range policy to reflect this for the same reason of what I said in the other comment
I agree with this approach as well. My only concern is if that will cause many breakages for the users. Although the change is for a corner case, it's a sudden behavioral change in a commonly used policy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update the API doc to clearly state that begin[d] <= end[d]
for all dimensions is a precondition for the constructors.
If merged, must appear in the changelog under "incpompatibilies" |
Also if we proceed with this PR, we'd probably want to also enforce the precondition for |
We might need to guard against |
Formatting. Co-authored-by: Damien L-G <dalg24+github@gmail.com>
Yes, we still need to have a discussion on that to come to a decision. |
Updated |
set_auto_chunk_size(); | ||
} | ||
|
||
/** \brief Total range */ | ||
inline RangePolicy(const member_type work_begin, const member_type work_end) | ||
: RangePolicy(typename traits::execution_space(), work_begin, work_end) { | ||
check_bounds_validity(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'd never get here since the construction is deferred to the other RangePolicy
constructor that would error out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did notice it before, but I placed it in just to have this check logic be paired with each set_auto_chunk_size()
call, which makes uses of m_begin
and m_end
.
If you feel strongly that we don't want this in this constructor (and in the other similar constructor that takes in Args...
), I'll remove the checks from the two constructors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can live with it. There are things that bother me more in that file :)
Retest this please. |
CI failures are unrelated |
Resolves #6616.
Added a simple check in MDRangePolicy that checks if any of the
end index
is less than its correspondingstart index
for all ranks.