-
Notifications
You must be signed in to change notification settings - Fork 407
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
core/src: Add half math functions to private header #6124
Conversation
Looks like this needs a rebase? After that I assume its ready for review? We probably should decide which order the two half moving things should come in. |
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 provide a proper description.
Make sure you discuss why we cast to float and do not bother using native half precision intrinsics when available.
The CI failures appear to be unrelated to these changes. |
Do we have no tests for this? |
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 some nesting. Can we reuse the existing one?
#include <Kokkos_MathematicalFunctions.hpp> // For the float overloads | ||
namespace Kokkos { | ||
#if defined(KOKKOS_HALF_T_IS_FLOAT) && !KOKKOS_HALF_T_IS_FLOAT | ||
#if defined(KOKKOS_BHALF_T_IS_FLOAT) && !KOKKOS_BHALF_T_IS_FLOAT |
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.
since we anyway have clang-format off here, can we indent the preprocess if clauses so its easier to see the if/else/endif structure of this nested clause?
It is tested already via the float math functions. Shall I add tests for these wrappers? |
@dalg24: I made these changes in the description above; does it address your feedback? |
@dalg24: Is it best to add |
// clang-format off | ||
#include <Kokkos_MathematicalFunctions.hpp> // For the float overloads | ||
namespace Kokkos { |
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.
Where are you reenabling/intending to reenable clang-format
?
I would appreciate at least some separation after the header include like
// clang-format off | |
#include <Kokkos_MathematicalFunctions.hpp> // For the float overloads | |
namespace Kokkos { | |
#include <Kokkos_MathematicalFunctions.hpp> // For the float overloads | |
// clang-format off | |
namespace Kokkos { |
I do not see a way to reuse the existing one as expected values are computed from |
A bare minimum test would be calling a few selected math functions on the device and make sure it compiles and executes. |
Co-authored-by: Damien L-G <dalg24+github@gmail.com>
Co-authored-by: Damien L-G <dalg24+github@gmail.com>
You will need to fix the indentation. |
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.
Assuming this is passing testing.
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 realize there is virtually no coverage for this with the fundamental types either but where do we define the promotion rules when mixing half types with other fundamental types in binary functions?
@@ -53,6 +61,14 @@ template <class T> | |||
using math_unary_function_return_type_t = typename math_unary_function_return_type<T>::type; | |||
template <class, class> | |||
struct math_binary_function_return_type; | |||
#if defined(KOKKOS_HALF_T_IS_FLOAT) && !KOKKOS_HALF_T_IS_FLOAT | |||
template <> struct math_binary_function_return_type<KE::half_t, KE::half_t> { using type = KE::half_t; }; | |||
template <> struct math_binary_function_return_type<int, KE::half_t> { using type = KE::half_t; }; |
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.
This look fishy
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 would need to provide much more than that.
Where is it being used?
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 math binary function test calls. Please add what's missing.
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.
do we mix int and half_t with the first argument as int and not the second?
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.
Sorry, I also do not follow this question.
Thank you for your detailed reviews, @dalg24 and @masterleinad.
static auto eval_std(T x) { \ | ||
if constexpr (std::is_same<T, KE::half_t>::value || \ | ||
std::is_same<T, KE::bhalf_t>::value) { \ | ||
return std::FUNC(static_cast<float>(x)); \ |
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 don't quite understand why comparing them as float is the right thing to do.
@dalg24: I don't understand your question. We always upcast for mixed precision, though. Please feel free to make any further changes you see fit to this PR. |
Is |
I see. I would expect integral types to be cast to the floating point type, always. I would also expect to always upcast to higher-precision floating point type. In the case of |
@dalg24: I think what you're looking for here are the mixed precision operator overloads defined in Kokkos_Half_FloatingPointWrapper.hpp. IIRC, we do not support mixed precision for operators that result in a binary type. |
No. We want to be aligned with standard C++ which states that integral types will be promoted to double |
@dalg24: Can you offer a appropriate alternative? e.g. comparing as double. |
KOKKOS_IMPL_MATH_BINARY_FUNCTION_HALF_MIXED(FUNC, HALF_TYPE, long) \ | ||
KOKKOS_IMPL_MATH_BINARY_FUNCTION_HALF_MIXED(FUNC, HALF_TYPE, unsigned long) \ | ||
KOKKOS_IMPL_MATH_BINARY_FUNCTION_HALF_MIXED(FUNC, HALF_TYPE, long long) \ | ||
KOKKOS_IMPL_MATH_BINARY_FUNCTION_HALF_MIXED(FUNC, HALF_TYPE, unsigned long long) |
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 we be also adding
long double FUNC(long double x, HALF_TYPE y) { \
return Kokkos::FUNC(x, static_cast<long double>(y)); \
} \
long double FUNC(HALF_TYPE x, long double y) { \
return Kokkos::FUNC(static_cast<long double>(x), y); \
} \
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.
We could do this. It would require adding a cast_from_half specialization that accepts long double as well as a explicit conversion constructor to support static_cast from half to long double. Would you like me to add those changes to this PR?
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.
We discussed this in the developer meeting today and came to a consensus. Since long double
is not supported in all backend and archuitectures, we will not be adding support for this at this time.
|
||
|
||
#define KOKKOS_IMPL_MATH_UNARY_FUNCTION_HALF_TYPE(FUNC, HALF_TYPE) \ | ||
KOKKOS_INLINE_FUNCTION HALF_TYPE FUNC(HALF_TYPE x) { \ |
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.
Just a thought, should we be specializing the function templates rather than adding new overloads?
@nliber please advise
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 overloads are the way to go. I keep going back to the advice in P0551 Thou Shalt Not Specialize std Function Templates! (and his various talks on the subject). Fewer surprises with overloads.
Function template specializations don't participate in overload resolution; basically, they are just an implementation detail once overload resolution picks the function to call.
Summary of changes
This PR introduces initial support for half math functions which rely on the floating_point_wrapper explicit conversion constructors to cast half_t and bhalf_t arguments to float in order to fall back on the float implementation of math functions. If this fall back approach is found to be a bottleneck by users, we could add a follow on PR to see if invoking backend-specific implementations (where available) of half_t and bhalf_t math functions helps.
Required for kokkos/kokkos-kernels#1774.