Skip to content
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

Merged
merged 7 commits into from
Jan 17, 2024

Conversation

ldh4
Copy link
Contributor

@ldh4 ldh4 commented Nov 22, 2023

Resolves #6616.

Added a simple check in MDRangePolicy that checks if any of the end index is less than its corresponding start index for all ranks.

Comment on lines 332 to 338
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());
}
Copy link
Contributor

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?

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor

@pkestene pkestene Nov 28, 2023

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.

Copy link
Contributor

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:

  1. using analytical expressions,
  2. the desired behavor is doing nothing

Copy link
Contributor

@fnrizzi fnrizzi Nov 28, 2023

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?

Copy link
Contributor

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.

Copy link
Contributor

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.

@@ -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>>;
Copy link
Member

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?

Copy link
Contributor Author

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\\.");
Copy link
Member

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...

Copy link
Member

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?)

Copy link
Member

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

Copy link
Member

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?

Copy link
Member

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

Copy link
Contributor

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?

Copy link
Contributor Author

@ldh4 ldh4 Dec 1, 2023

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.

Copy link
Contributor

@fnrizzi fnrizzi Dec 1, 2023

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

Copy link
Contributor Author

@ldh4 ldh4 Dec 1, 2023

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.

Copy link
Member

@dalg24 dalg24 left a 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.

@dalg24
Copy link
Member

dalg24 commented Jan 9, 2024

If merged, must appear in the changelog under "incpompatibilies"

@dalg24
Copy link
Member

dalg24 commented Jan 9, 2024

Also if we proceed with this PR, we'd probably want to also enforce the precondition for RangePolicy.

@dalg24
Copy link
Member

dalg24 commented Jan 9, 2024

We might need to guard against KOKKOS_ENABLE_DEPRECATED_CODE_4 to be safe.

Formatting.

Co-authored-by: Damien L-G <dalg24+github@gmail.com>
@ldh4
Copy link
Contributor Author

ldh4 commented Jan 9, 2024

Also if we proceed with this PR, we'd probably want to also enforce the precondition for RangePolicy.

Yes, we still need to have a discussion on that to come to a decision.
For consistency, either RangePolicy will need to have a similar precondition with an abort or MDRangePolicy will need to use a silently emptied range upon violating its precondition.

@ldh4
Copy link
Contributor Author

ldh4 commented Jan 11, 2024

Updated RangePolicy to enforce the same precondition.

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();
Copy link
Member

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.

Copy link
Contributor Author

@ldh4 ldh4 Jan 11, 2024

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.

Copy link
Member

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 :)

@ldh4
Copy link
Contributor Author

ldh4 commented Jan 16, 2024

Retest this please.

@ldh4 ldh4 changed the title Add a bounds check in MDRangePolicy Add bound checks in RangePolicy and MDRangePolicy Jan 16, 2024
@dalg24
Copy link
Member

dalg24 commented Jan 17, 2024

CI failures are unrelated

@dalg24 dalg24 merged commit 179d2e6 into kokkos:develop Jan 17, 2024
30 of 31 checks passed
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.

None yet

8 participants