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

Draft: Valloc Interface for New Reducer #1690

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion examples/forall-param-reductions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ int main(int RAJA_UNUSED_ARG(argc), char** RAJA_UNUSED_ARG(argv[]))
a[minloc_ref] = -100;

constexpr int maxloc_ref = N / 2 + 1;
a[maxloc_ref] = 100;
a[maxloc_ref] = 103;
// _reductions_array_init_end

//
Expand Down Expand Up @@ -146,6 +146,62 @@ int main(int RAJA_UNUSED_ARG(argc), char** RAJA_UNUSED_ARG(argv[]))
// _reductions_raja_seq_end


//
// Define RefLoc Type
//

using REF_INT_SUM = RAJA::expt::ValOp<int, RAJA::operators::plus>;
using REF_INT_MIN = RAJA::expt::ValOp<int, RAJA::operators::minimum>;
using REF_INT_MAX = RAJA::expt::ValOp<int, RAJA::operators::maximum>;
using REFLOC_INT_MIN = RAJA::expt::ValLocOp<int, RAJA::operators::minimum>;
Copy link
Member

@MrBurmark MrBurmark Jul 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have an option to change the loc type?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean you want something like ValLocOp<double, int, minimum>, where int represents the loc type? I don't think we've had that in the past.

Copy link
Member

@MrBurmark MrBurmark Jul 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, and we always should have had it.

using REFLOC_INT_MAX = RAJA::expt::ValLocOp<int, RAJA::operators::maximum>;
//----------------------------------------------------------------------------//

std::cout << "\n Running RAJA sequential REF reductions...\n";

// _reductions_raja_seq_start
using EXEC_POL1R = RAJA::seq_exec;

REF_INT_SUM rseq_sum(0);
REF_INT_MIN rseq_min(std::numeric_limits<int>::max());
REF_INT_MAX rseq_max(std::numeric_limits<int>::min());
REFLOC_INT_MIN rseq_minloc(std::numeric_limits<int>::max(), -1);
REFLOC_INT_MAX rseq_maxloc(std::numeric_limits<int>::min(), -1);

RAJA::forall<EXEC_POL1R>(arange,
RAJA::expt::Reduce(&rseq_sum),
RAJA::expt::Reduce(&rseq_min),
RAJA::expt::Reduce(&rseq_max),
RAJA::expt::Reduce(&rseq_minloc),
RAJA::expt::Reduce(&rseq_maxloc),
[=](int i, REF_INT_SUM &_rseq_sum, REF_INT_MIN &_rseq_min, REF_INT_MAX &_rseq_max, REFLOC_INT_MIN &_rseq_minloc, REFLOC_INT_MAX &_rseq_maxloc) {
_rseq_sum += a[i];

_rseq_min.min(a[i]);
_rseq_max.max(a[i]);
//_rseq_min = RAJA_MIN(a[i], _rseq_min);
//_rseq_max = RAJA_MAX(a[i], _rseq_max);

//_rseq_minloc = RAJA_MIN(REFLOC_INT(a[i], i), _rseq_minloc);
//_rseq_maxloc = RAJA_MAX(REFLOC_INT(a[i], i), _rseq_maxloc);
_rseq_minloc.minloc(a[i], i);
_rseq_maxloc.maxloc(a[i], i);
// Note : RAJA::expt::ValLoc<T> objects provide min() and max() methods
// that are equivalent to the assignments with RAJA_MIN and RAJA_MAX
// above.
}
);

std::cout << "\tsum = " << rseq_sum.get() << std::endl;
std::cout << "\tmin = " << rseq_min.get() << std::endl;
std::cout << "\tmax = " << rseq_max.get() << std::endl;
std::cout << "\tmin, loc = " << rseq_minloc.getVal() << " , "
<< rseq_minloc.getLoc() << std::endl;
std::cout << "\tmax, loc = " << rseq_maxloc.getVal() << " , "
<< rseq_maxloc.getLoc() << std::endl;
// _reductions_raja_seq_end


//----------------------------------------------------------------------------//

#if defined(RAJA_ENABLE_OPENMP)
Expand Down
126 changes: 116 additions & 10 deletions include/RAJA/pattern/params/reducer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "RAJA/policy/sycl/MemUtils_SYCL.hpp"
#endif

#include "RAJA/pattern/params/refloc_base.hpp"

namespace RAJA
{

Expand All @@ -23,29 +25,115 @@ struct ValLoc {
using index_type = RAJA::Index_type;
using value_type = T;

RAJA_HOST_DEVICE ValLoc() {}
RAJA_HOST_DEVICE ValLoc(value_type v) : val(v) {}
RAJA_HOST_DEVICE ValLoc(value_type v, RAJA::Index_type l) : val(v), loc(l) {}

RAJA_HOST_DEVICE void min(value_type v, index_type l) { if (v < val) { val = v; loc = l; } }
RAJA_HOST_DEVICE void max(value_type v, index_type l) { if (v > val) { val = v; loc = l; } }
RAJA_HOST_DEVICE constexpr ValLoc() {}
RAJA_HOST_DEVICE constexpr explicit ValLoc(value_type v) : val(v) {}
RAJA_HOST_DEVICE constexpr ValLoc(value_type v, RAJA::Index_type l) : val(v), loc(l) {}

bool constexpr operator<(const ValLoc& rhs) const { return val < rhs.val; }
bool constexpr operator>(const ValLoc& rhs) const { return val > rhs.val; }
RAJA_HOST_DEVICE constexpr bool operator<(const ValLoc& rhs) const { return val < rhs.val; }
RAJA_HOST_DEVICE constexpr bool operator>(const ValLoc& rhs) const { return val > rhs.val; }

value_type getVal() {return val;}
RAJA::Index_type getLoc() {return loc;}
RAJA_HOST_DEVICE constexpr value_type getVal() const {return val;}
MrBurmark marked this conversation as resolved.
Show resolved Hide resolved
RAJA_HOST_DEVICE constexpr RAJA::Index_type getLoc() const {return loc;}

private:
value_type val;
index_type loc = -1;
};

template<typename T, template <typename, typename, typename> class Op>
struct ValOp {
using value_type = T;
using op_type = Op<T,T,T>;

RAJA_HOST_DEVICE constexpr ValOp() {}
RAJA_HOST_DEVICE constexpr explicit ValOp(value_type v) : val(v) {}

template <typename U = op_type, std::enable_if_t<std::is_same<U, RAJA::operators::minimum<T,T,T>>::value> * = nullptr>
RAJA_HOST_DEVICE constexpr ValOp & min(value_type v) { if (v < val) { val = v; } return *this; }
template <typename U = op_type, std::enable_if_t<std::is_same<U, RAJA::operators::maximum<T,T,T>>::value> * = nullptr>
RAJA_HOST_DEVICE constexpr ValOp & max(value_type v) { if (v > val) { val = v; } return *this; }

template <typename U = op_type, std::enable_if_t<std::is_same<U, RAJA::operators::plus<T,T,T>>::value> * = nullptr>
RAJA_HOST_DEVICE constexpr ValOp & operator+=(const value_type& rhs) { val += rhs; return *this; }

template <typename U = op_type, std::enable_if_t<std::is_same<U, RAJA::operators::bit_and<T,T,T>>::value> * = nullptr>
RAJA_HOST_DEVICE constexpr ValOp & operator&=(const value_type& rhs) { val &= rhs; return *this; }

template <typename U = op_type, std::enable_if_t<std::is_same<U, RAJA::operators::bit_or<T,T,T>>::value> * = nullptr>
RAJA_HOST_DEVICE constexpr ValOp & operator|=(const value_type& rhs) { val |= rhs; return *this; }

template <typename U = op_type, std::enable_if_t<std::is_same<U, RAJA::operators::bit_and<T,T,T>>::value> * = nullptr>
RAJA_HOST_DEVICE ValOp & operator&=(value_type& rhs) { val &= rhs; return *this; }

template <typename U = op_type, std::enable_if_t<std::is_same<U, RAJA::operators::bit_or<T,T,T>>::value> * = nullptr>
RAJA_HOST_DEVICE ValOp & operator|=(value_type& rhs) { val |= rhs; return *this; }
rchen20 marked this conversation as resolved.
Show resolved Hide resolved

RAJA_HOST_DEVICE constexpr bool operator<(const ValOp& rhs) const { val < rhs.val; return *this; }
RAJA_HOST_DEVICE constexpr bool operator>(const ValOp& rhs) const { val > rhs.val; return *this; }

RAJA_HOST_DEVICE constexpr value_type get() const {return val;}

//private:
value_type val;
};

template<typename T, template <typename, typename, typename> class Op>
struct ValOp <ValLoc<T>, Op> {
using index_type = RAJA::Index_type;
using value_type = ValLoc<T>;
using op_type = Op<value_type,value_type,value_type>;
using valloc_value_type = typename value_type::value_type;
using valloc_index_type = typename value_type::index_type;

RAJA_HOST_DEVICE constexpr ValOp() {}
RAJA_HOST_DEVICE constexpr explicit ValOp(value_type v) : val(v) {}
RAJA_HOST_DEVICE constexpr explicit ValOp(valloc_value_type v) : val(v) {}
RAJA_HOST_DEVICE constexpr ValOp(valloc_value_type v, valloc_index_type l) : val(v, l) {}

template <typename U = op_type, std::enable_if_t<std::is_same<U, RAJA::operators::minimum<value_type,value_type,value_type>>::value> * = nullptr>
RAJA_HOST_DEVICE constexpr ValOp & min(value_type v) { if (v < val) { val = v; } return *this; }
template <typename U = op_type, std::enable_if_t<std::is_same<U, RAJA::operators::maximum<value_type,value_type,value_type>>::value> * = nullptr>
RAJA_HOST_DEVICE constexpr ValOp & max(value_type v) { if (v > val) { val = v; } return *this; }

template <typename U = op_type, std::enable_if_t<std::is_same<U, RAJA::operators::minimum<value_type,value_type,value_type>>::value> * = nullptr>
RAJA_HOST_DEVICE constexpr ValOp & minloc(valloc_value_type v, valloc_index_type l) { return min(value_type(v,l)); }

template <typename U = op_type, std::enable_if_t<std::is_same<U, RAJA::operators::maximum<value_type,value_type,value_type>>::value> * = nullptr>
RAJA_HOST_DEVICE constexpr ValOp & maxloc(valloc_value_type v, valloc_index_type l) { return max(value_type(v,l)); }

RAJA_HOST_DEVICE constexpr bool operator<(const ValOp& rhs) const { return val < rhs.val; }
RAJA_HOST_DEVICE constexpr bool operator>(const ValOp& rhs) const { return val > rhs.val; }

RAJA_HOST_DEVICE constexpr value_type get() const {return val;}
RAJA_HOST_DEVICE constexpr valloc_value_type getVal() const {return val.getVal();}
RAJA_HOST_DEVICE constexpr valloc_index_type getLoc() const {return val.getLoc();}

private:
value_type val;
};

template<typename T, template <typename, typename, typename> class Op>
using ValLocOp = ValOp<ValLoc<T>, Op>;

} // namespace expt

namespace operators
{

template <typename T, template <typename, typename, typename> class Op>
struct limits<RAJA::expt::ValOp<T, Op>, void> {
RAJA_INLINE RAJA_HOST_DEVICE static constexpr RAJA::expt::ValOp<T, Op> min()
{
return RAJA::expt::ValOp<T, Op>(RAJA::operators::limits<T>::min());
}

RAJA_INLINE RAJA_HOST_DEVICE static constexpr RAJA::expt::ValOp<T, Op> max()
{
return RAJA::expt::ValOp<T, Op>(RAJA::operators::limits<T>::max());
}
};


template <typename T>
struct limits<RAJA::expt::ValLoc<T>> {
RAJA_INLINE RAJA_HOST_DEVICE static constexpr RAJA::expt::ValLoc<T> min()
Expand Down Expand Up @@ -85,14 +173,19 @@ namespace detail
//
template <typename Op, typename T>
struct Reducer : public ForallParamBase {
//using op = Op<T,T,T>;
using op = Op;
using value_type = T;
//using value_op = ValOp<T, Op>;

RAJA_HOST_DEVICE Reducer() {}
Reducer(value_type *target_in) : target(target_in), val(op::identity()) {}
//Reducer(value_type *target_in) : target(target_in), val(op::identity()), vop(value_op(*target_in)) {}
//Reducer(value_op *target_in) : target(target_in->get()), val(op::identity()), vop(value_op(*target_in)) {}

value_type *target = nullptr;
value_type val = op::identity();
//value_op *vop = nullptr;

#if defined(RAJA_CUDA_ACTIVE) || defined(RAJA_HIP_ACTIVE) || defined(RAJA_SYCL_ACTIVE)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reminds me that we should specialize SoAPtr on ValLoc, etc.

// Device related attributes.
Expand All @@ -106,10 +199,23 @@ namespace detail

using ARG_LIST_T = typename ARG_TUP_T::TList;
static constexpr size_t num_lambda_args = camp::tuple_size<ARG_TUP_T>::value ;

};

} // namespace detail

template <template <typename, typename, typename> class Op, typename T>
auto constexpr Reduce(ValOp<ValLoc<T>,Op> *target)
{
return detail::Reducer<Op<ValOp<ValLoc<T>,Op>, ValOp<ValLoc<T>,Op>, ValOp<ValLoc<T>,Op>>, ValOp<ValLoc<T>,Op>>(target);
}

template <template <typename, typename, typename> class Op, typename T>
auto constexpr Reduce(ValOp<T,Op> *target)
{
return detail::Reducer<Op<ValOp<T,Op>, ValOp<T,Op>, ValOp<T,Op>>, ValOp<T,Op>>(target);
}

template <template <typename, typename, typename> class Op, typename T>
auto constexpr Reduce(T *target)
{
Expand Down
44 changes: 44 additions & 0 deletions include/RAJA/policy/sequential/params/reduce.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,50 @@ namespace RAJA {
namespace expt {
namespace detail {

// Init
template<typename EXEC_POL, template <typename, typename, typename> class OP, typename T>
camp::concepts::enable_if< std::is_same< EXEC_POL, RAJA::seq_exec> >
init(Reducer<OP<ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>>, ValOp<ValLoc<T>,OP>>& red) {
red.val = OP<ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>>::identity();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should figure out why using Op<ValOp<ValLoc<T>,OP>, ...>::identity() works here but Op<ValOp<T,OP>, ...>::identity() doesn't work below.

}
// Combine
template<typename EXEC_POL, template <typename, typename, typename> class OP, typename T>
camp::concepts::enable_if< std::is_same< EXEC_POL, RAJA::seq_exec> >
combine(Reducer<OP<ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>>, ValOp<ValLoc<T>,OP>>& out, const Reducer<OP<ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>>, ValOp<ValLoc<T>,OP>>& in) {
out.val = OP<ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>>{}(out.val, in.val);
}
// Resolve
template<typename EXEC_POL, template <typename, typename, typename> class OP, typename T>
camp::concepts::enable_if< std::is_same< EXEC_POL, RAJA::seq_exec> >
resolve(Reducer<OP<ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>>, ValOp<ValLoc<T>,OP>>& red) {
*red.target = OP<ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>, ValOp<ValLoc<T>,OP>>{}(*red.target, red.val);
}

// Init
template<typename EXEC_POL, template <typename, typename, typename> class OP, typename T>
camp::concepts::enable_if< std::is_same< EXEC_POL, RAJA::seq_exec> >
init(Reducer<OP<ValOp<T,OP>, ValOp<T,OP>, ValOp<T,OP>>, ValOp<T,OP>>& red) {
// RCC trying to understand what these types are
//decltype(red.val)::nothing;
//decltype(OP<T,T,T>::identity())::nothing;
//red.val comes from include/RAJA/pattern/params/reducer.hpp struct Reducer{value_type val = op::identity()}
// RCC doesn't work red.val = ValOp<T,OP>::identity(); // need to get OP<T,T,T>::identity()
// CHANGE THIS TO USE A set() function for val in ValOp
red.val.val = OP<T,T,T>::identity();
}
// Combine
template<typename EXEC_POL, template <typename, typename, typename> class OP, typename T>
camp::concepts::enable_if< std::is_same< EXEC_POL, RAJA::seq_exec> >
combine(Reducer<OP<ValOp<T,OP>, ValOp<T,OP>, ValOp<T,OP>>, ValOp<T,OP>>& out, const Reducer<OP<ValOp<T,OP>, ValOp<T,OP>, ValOp<T,OP>>, ValOp<T,OP>>& in) {
out.val.val = OP<T,T,T>{}(out.val.val, in.val.val);
}
// Resolve
template<typename EXEC_POL, template <typename, typename, typename> class OP, typename T>
camp::concepts::enable_if< std::is_same< EXEC_POL, RAJA::seq_exec> >
resolve(Reducer<OP<ValOp<T,OP>, ValOp<T,OP>, ValOp<T,OP>>, ValOp<T,OP>>& red) {
red.target->val = OP<T,T,T>{}(red.target->val, red.val.val);
}

// Init
template<typename EXEC_POL, typename OP, typename T>
camp::concepts::enable_if< std::is_same< EXEC_POL, RAJA::seq_exec> >
Expand Down
Loading