1043 lines
32 KiB
C++
1043 lines
32 KiB
C++
/*
|
|
//@HEADER
|
|
// ************************************************************************
|
|
//
|
|
// Kokkos v. 3.0
|
|
// Copyright (2020) National Technology & Engineering
|
|
// Solutions of Sandia, LLC (NTESS).
|
|
//
|
|
// Under the terms of Contract DE-NA0003525 with NTESS,
|
|
// the U.S. Government retains certain rights in this software.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// 1. Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// 2. Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
//
|
|
// 3. Neither the name of the Corporation nor the names of the
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
|
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
|
|
//
|
|
// ************************************************************************
|
|
//@HEADER
|
|
*/
|
|
|
|
#include <stdexcept>
|
|
#include <sstream>
|
|
#include <iostream>
|
|
#include <limits>
|
|
|
|
#include <Kokkos_Core.hpp>
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
namespace Test {
|
|
|
|
struct ReducerTag {};
|
|
|
|
template <class Scalar, class ExecSpace = Kokkos::DefaultExecutionSpace>
|
|
struct TestReducers {
|
|
struct SumFunctor {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const int& i, Scalar& value) const { value += values(i); }
|
|
};
|
|
|
|
struct ProdFunctor {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const int& i, Scalar& value) const { value *= values(i); }
|
|
};
|
|
|
|
struct MinFunctor {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const int& i, Scalar& value) const {
|
|
if (values(i) < value) value = values(i);
|
|
}
|
|
};
|
|
|
|
struct MaxFunctor {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const int& i, Scalar& value) const {
|
|
if (values(i) > value) value = values(i);
|
|
}
|
|
};
|
|
|
|
struct MinLocFunctor {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(
|
|
const int& i,
|
|
typename Kokkos::MinLoc<Scalar, int>::value_type& value) const {
|
|
if (values(i) < value.val) {
|
|
value.val = values(i);
|
|
value.loc = i;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct MaxLocFunctor {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(
|
|
const int& i,
|
|
typename Kokkos::MaxLoc<Scalar, int>::value_type& value) const {
|
|
if (values(i) > value.val) {
|
|
value.val = values(i);
|
|
value.loc = i;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct MinMaxLocFunctor {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(
|
|
const int& i,
|
|
typename Kokkos::MinMaxLoc<Scalar, int>::value_type& value) const {
|
|
if (values(i) > value.max_val) {
|
|
value.max_val = values(i);
|
|
value.max_loc = i;
|
|
}
|
|
|
|
if (values(i) < value.min_val) {
|
|
value.min_val = values(i);
|
|
value.min_loc = i;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct BAndFunctor {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const int& i, Scalar& value) const {
|
|
value = value & values(i);
|
|
}
|
|
};
|
|
|
|
struct BOrFunctor {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const int& i, Scalar& value) const {
|
|
value = value | values(i);
|
|
}
|
|
};
|
|
|
|
struct LAndFunctor {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const int& i, Scalar& value) const {
|
|
value = value && values(i);
|
|
}
|
|
};
|
|
|
|
struct LOrFunctor {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const int& i, Scalar& value) const {
|
|
value = value || values(i);
|
|
}
|
|
};
|
|
|
|
struct SumFunctorTag {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const ReducerTag, const int& i, Scalar& value) const {
|
|
value += values(i);
|
|
}
|
|
};
|
|
|
|
struct ProdFunctorTag {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const ReducerTag, const int& i, Scalar& value) const {
|
|
value *= values(i);
|
|
}
|
|
};
|
|
|
|
struct MinFunctorTag {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const ReducerTag, const int& i, Scalar& value) const {
|
|
if (values(i) < value) value = values(i);
|
|
}
|
|
};
|
|
|
|
struct MaxFunctorTag {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const ReducerTag, const int& i, Scalar& value) const {
|
|
if (values(i) > value) value = values(i);
|
|
}
|
|
};
|
|
|
|
struct MinLocFunctorTag {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(
|
|
const ReducerTag, const int& i,
|
|
typename Kokkos::MinLoc<Scalar, int>::value_type& value) const {
|
|
if (values(i) < value.val) {
|
|
value.val = values(i);
|
|
value.loc = i;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct MaxLocFunctorTag {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(
|
|
const ReducerTag, const int& i,
|
|
typename Kokkos::MaxLoc<Scalar, int>::value_type& value) const {
|
|
if (values(i) > value.val) {
|
|
value.val = values(i);
|
|
value.loc = i;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct MinMaxLocFunctorTag {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(
|
|
const ReducerTag, const int& i,
|
|
typename Kokkos::MinMaxLoc<Scalar, int>::value_type& value) const {
|
|
if (values(i) > value.max_val) {
|
|
value.max_val = values(i);
|
|
value.max_loc = i;
|
|
}
|
|
|
|
if (values(i) < value.min_val) {
|
|
value.min_val = values(i);
|
|
value.min_loc = i;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct BAndFunctorTag {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const ReducerTag, const int& i, Scalar& value) const {
|
|
value = value & values(i);
|
|
}
|
|
};
|
|
|
|
struct BOrFunctorTag {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const ReducerTag, const int& i, Scalar& value) const {
|
|
value = value | values(i);
|
|
}
|
|
};
|
|
|
|
struct LAndFunctorTag {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const ReducerTag, const int& i, Scalar& value) const {
|
|
value = value && values(i);
|
|
}
|
|
};
|
|
|
|
struct LOrFunctorTag {
|
|
Kokkos::View<const Scalar*, ExecSpace> values;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const ReducerTag, const int& i, Scalar& value) const {
|
|
value = value || values(i);
|
|
}
|
|
};
|
|
static void test_sum(int N) {
|
|
Kokkos::View<Scalar*, ExecSpace> values("Values", N);
|
|
auto h_values = Kokkos::create_mirror_view(values);
|
|
Scalar reference_sum = 0;
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
int denom = sizeof(Scalar) <= 2 ? 10 : 100;
|
|
h_values(i) = (Scalar)(rand() % denom);
|
|
reference_sum += h_values(i);
|
|
}
|
|
Kokkos::deep_copy(values, h_values);
|
|
|
|
SumFunctor f;
|
|
f.values = values;
|
|
SumFunctorTag f_tag;
|
|
f_tag.values = values;
|
|
Scalar init = 0;
|
|
|
|
{
|
|
Scalar sum_scalar = Scalar(1);
|
|
Kokkos::Sum<Scalar> reducer_scalar(sum_scalar);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, 0), f,
|
|
reducer_scalar);
|
|
ASSERT_EQ(sum_scalar, init);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_scalar);
|
|
ASSERT_EQ(sum_scalar, reference_sum);
|
|
|
|
sum_scalar = init;
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace, ReducerTag>(0, N),
|
|
f_tag, reducer_scalar);
|
|
ASSERT_EQ(sum_scalar, reference_sum);
|
|
|
|
Scalar sum_scalar_view = reducer_scalar.reference();
|
|
ASSERT_EQ(sum_scalar_view, reference_sum);
|
|
}
|
|
|
|
{
|
|
Kokkos::View<Scalar, Kokkos::HostSpace> sum_view("View");
|
|
sum_view() = Scalar(1);
|
|
Kokkos::Sum<Scalar> reducer_view(sum_view);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, 0), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
Scalar sum_view_scalar = sum_view();
|
|
ASSERT_EQ(sum_view_scalar, init);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
sum_view_scalar = sum_view();
|
|
ASSERT_EQ(sum_view_scalar, reference_sum);
|
|
|
|
Scalar sum_view_view = reducer_view.reference();
|
|
ASSERT_EQ(sum_view_view, reference_sum);
|
|
}
|
|
|
|
{
|
|
Kokkos::View<Scalar, typename ExecSpace::memory_space> sum_view("View");
|
|
Kokkos::deep_copy(sum_view, Scalar(1));
|
|
Kokkos::Sum<Scalar, typename ExecSpace::memory_space> reducer_view(
|
|
sum_view);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, 0), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
Scalar sum_view_scalar;
|
|
Kokkos::deep_copy(sum_view_scalar, sum_view);
|
|
ASSERT_EQ(sum_view_scalar, init);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
Kokkos::deep_copy(sum_view_scalar, sum_view);
|
|
ASSERT_EQ(sum_view_scalar, reference_sum);
|
|
}
|
|
}
|
|
|
|
static void test_prod(int N) {
|
|
Kokkos::View<Scalar*, ExecSpace> values("Values", N);
|
|
auto h_values = Kokkos::create_mirror_view(values);
|
|
Scalar reference_prod = 1;
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
h_values(i) = (Scalar)(rand() % 4 + 1);
|
|
reference_prod *= h_values(i);
|
|
}
|
|
Kokkos::deep_copy(values, h_values);
|
|
|
|
ProdFunctor f;
|
|
f.values = values;
|
|
ProdFunctorTag f_tag;
|
|
f_tag.values = values;
|
|
Scalar init = 1;
|
|
|
|
{
|
|
Scalar prod_scalar = Scalar(0);
|
|
Kokkos::Prod<Scalar> reducer_scalar(prod_scalar);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, 0), f,
|
|
reducer_scalar);
|
|
ASSERT_EQ(prod_scalar, init);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_scalar);
|
|
ASSERT_EQ(prod_scalar, reference_prod);
|
|
|
|
prod_scalar = init;
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace, ReducerTag>(0, N),
|
|
f_tag, reducer_scalar);
|
|
ASSERT_EQ(prod_scalar, reference_prod);
|
|
|
|
Scalar prod_scalar_view = reducer_scalar.reference();
|
|
ASSERT_EQ(prod_scalar_view, reference_prod);
|
|
}
|
|
|
|
{
|
|
Kokkos::View<Scalar, Kokkos::HostSpace> prod_view("View");
|
|
prod_view() = Scalar(0);
|
|
Kokkos::Prod<Scalar> reducer_view(prod_view);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, 0), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
Scalar prod_view_scalar = prod_view();
|
|
ASSERT_EQ(prod_view_scalar, init);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
prod_view_scalar = prod_view();
|
|
ASSERT_EQ(prod_view_scalar, reference_prod);
|
|
|
|
Scalar prod_view_view = reducer_view.reference();
|
|
ASSERT_EQ(prod_view_view, reference_prod);
|
|
}
|
|
|
|
{
|
|
Kokkos::View<Scalar, typename ExecSpace::memory_space> prod_view("View");
|
|
Kokkos::deep_copy(prod_view, Scalar(0));
|
|
Kokkos::Prod<Scalar, typename ExecSpace::memory_space> reducer_view(
|
|
prod_view);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, 0), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
Scalar prod_view_scalar;
|
|
Kokkos::deep_copy(prod_view_scalar, prod_view);
|
|
ASSERT_EQ(prod_view_scalar, init);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
Kokkos::deep_copy(prod_view_scalar, prod_view);
|
|
ASSERT_EQ(prod_view_scalar, reference_prod);
|
|
}
|
|
}
|
|
|
|
static void test_min(int N) {
|
|
Kokkos::View<Scalar*, ExecSpace> values("Values", N);
|
|
auto h_values = Kokkos::create_mirror_view(values);
|
|
Scalar reference_min = std::numeric_limits<Scalar>::max();
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
h_values(i) = (Scalar)(rand() % 100000);
|
|
|
|
if (h_values(i) < reference_min) reference_min = h_values(i);
|
|
}
|
|
Kokkos::deep_copy(values, h_values);
|
|
|
|
MinFunctor f;
|
|
f.values = values;
|
|
MinFunctorTag f_tag;
|
|
f_tag.values = values;
|
|
Scalar init = std::numeric_limits<Scalar>::max();
|
|
|
|
{
|
|
Scalar min_scalar = init;
|
|
Kokkos::Min<Scalar> reducer_scalar(min_scalar);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_scalar);
|
|
ASSERT_EQ(min_scalar, reference_min);
|
|
|
|
min_scalar = init;
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace, ReducerTag>(0, N),
|
|
f_tag, reducer_scalar);
|
|
ASSERT_EQ(min_scalar, reference_min);
|
|
|
|
Scalar min_scalar_view = reducer_scalar.reference();
|
|
ASSERT_EQ(min_scalar_view, reference_min);
|
|
}
|
|
|
|
{
|
|
Kokkos::View<Scalar, Kokkos::HostSpace> min_view("View");
|
|
min_view() = init;
|
|
Kokkos::Min<Scalar> reducer_view(min_view);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
|
|
Scalar min_view_scalar = min_view();
|
|
ASSERT_EQ(min_view_scalar, reference_min);
|
|
|
|
Scalar min_view_view = reducer_view.reference();
|
|
ASSERT_EQ(min_view_view, reference_min);
|
|
}
|
|
}
|
|
|
|
static void test_max(int N) {
|
|
Kokkos::View<Scalar*, ExecSpace> values("Values", N);
|
|
auto h_values = Kokkos::create_mirror_view(values);
|
|
Scalar reference_max = std::numeric_limits<Scalar>::min();
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
h_values(i) = (Scalar)(rand() % 100000 + 1);
|
|
|
|
if (h_values(i) > reference_max) reference_max = h_values(i);
|
|
}
|
|
Kokkos::deep_copy(values, h_values);
|
|
|
|
MaxFunctor f;
|
|
f.values = values;
|
|
MaxFunctorTag f_tag;
|
|
f_tag.values = values;
|
|
Scalar init = std::numeric_limits<Scalar>::min();
|
|
|
|
{
|
|
Scalar max_scalar = init;
|
|
Kokkos::Max<Scalar> reducer_scalar(max_scalar);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_scalar);
|
|
ASSERT_EQ(max_scalar, reference_max);
|
|
|
|
max_scalar = init;
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace, ReducerTag>(0, N),
|
|
f_tag, reducer_scalar);
|
|
ASSERT_EQ(max_scalar, reference_max);
|
|
|
|
Scalar max_scalar_view = reducer_scalar.reference();
|
|
ASSERT_EQ(max_scalar_view, reference_max);
|
|
}
|
|
|
|
{
|
|
Kokkos::View<Scalar, Kokkos::HostSpace> max_view("View");
|
|
max_view() = init;
|
|
Kokkos::Max<Scalar> reducer_view(max_view);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
|
|
Scalar max_view_scalar = max_view();
|
|
ASSERT_EQ(max_view_scalar, reference_max);
|
|
|
|
Scalar max_view_view = reducer_view.reference();
|
|
ASSERT_EQ(max_view_view, reference_max);
|
|
}
|
|
}
|
|
|
|
static void test_minloc(int N) {
|
|
using value_type = typename Kokkos::MinLoc<Scalar, int>::value_type;
|
|
|
|
Kokkos::View<Scalar*, ExecSpace> values("Values", N);
|
|
auto h_values = Kokkos::create_mirror_view(values);
|
|
Scalar reference_min = std::numeric_limits<Scalar>::max();
|
|
int reference_loc = -1;
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
h_values(i) = (Scalar)(rand() % 100000 + 2);
|
|
|
|
if (h_values(i) < reference_min) {
|
|
reference_min = h_values(i);
|
|
reference_loc = i;
|
|
} else if (h_values(i) == reference_min) {
|
|
// Make min unique.
|
|
h_values(i) += Scalar(1);
|
|
}
|
|
}
|
|
Kokkos::deep_copy(values, h_values);
|
|
|
|
MinLocFunctor f;
|
|
f.values = values;
|
|
MinLocFunctorTag f_tag;
|
|
f_tag.values = values;
|
|
|
|
{
|
|
value_type min_scalar;
|
|
Kokkos::MinLoc<Scalar, int> reducer_scalar(min_scalar);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_scalar);
|
|
ASSERT_EQ(min_scalar.val, reference_min);
|
|
ASSERT_EQ(min_scalar.loc, reference_loc);
|
|
|
|
min_scalar = value_type();
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace, ReducerTag>(0, N),
|
|
f_tag, reducer_scalar);
|
|
ASSERT_EQ(min_scalar.val, reference_min);
|
|
ASSERT_EQ(min_scalar.loc, reference_loc);
|
|
|
|
value_type min_scalar_view = reducer_scalar.reference();
|
|
ASSERT_EQ(min_scalar_view.val, reference_min);
|
|
ASSERT_EQ(min_scalar_view.loc, reference_loc);
|
|
}
|
|
|
|
{
|
|
Kokkos::View<value_type, Kokkos::HostSpace> min_view("View");
|
|
Kokkos::MinLoc<Scalar, int> reducer_view(min_view);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
|
|
value_type min_view_scalar = min_view();
|
|
ASSERT_EQ(min_view_scalar.val, reference_min);
|
|
ASSERT_EQ(min_view_scalar.loc, reference_loc);
|
|
|
|
value_type min_view_view = reducer_view.reference();
|
|
ASSERT_EQ(min_view_view.val, reference_min);
|
|
ASSERT_EQ(min_view_view.loc, reference_loc);
|
|
}
|
|
}
|
|
|
|
static void test_maxloc(int N) {
|
|
using value_type = typename Kokkos::MaxLoc<Scalar, int>::value_type;
|
|
|
|
Kokkos::View<Scalar*, ExecSpace> values("Values", N);
|
|
auto h_values = Kokkos::create_mirror_view(values);
|
|
Scalar reference_max = std::numeric_limits<Scalar>::min();
|
|
int reference_loc = -1;
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
h_values(i) = (Scalar)(rand() % 100000 + 2);
|
|
|
|
if (h_values(i) > reference_max) {
|
|
reference_max = h_values(i);
|
|
reference_loc = i;
|
|
} else if (h_values(i) == reference_max) {
|
|
// Make max unique.
|
|
h_values(i) -= Scalar(1);
|
|
}
|
|
}
|
|
Kokkos::deep_copy(values, h_values);
|
|
|
|
MaxLocFunctor f;
|
|
f.values = values;
|
|
MaxLocFunctorTag f_tag;
|
|
f_tag.values = values;
|
|
|
|
{
|
|
value_type max_scalar;
|
|
Kokkos::MaxLoc<Scalar, int> reducer_scalar(max_scalar);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_scalar);
|
|
ASSERT_EQ(max_scalar.val, reference_max);
|
|
ASSERT_EQ(max_scalar.loc, reference_loc);
|
|
|
|
max_scalar = value_type();
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace, ReducerTag>(0, N),
|
|
f_tag, reducer_scalar);
|
|
ASSERT_EQ(max_scalar.val, reference_max);
|
|
ASSERT_EQ(max_scalar.loc, reference_loc);
|
|
|
|
value_type max_scalar_view = reducer_scalar.reference();
|
|
ASSERT_EQ(max_scalar_view.val, reference_max);
|
|
ASSERT_EQ(max_scalar_view.loc, reference_loc);
|
|
}
|
|
|
|
{
|
|
Kokkos::View<value_type, Kokkos::HostSpace> max_view("View");
|
|
Kokkos::MaxLoc<Scalar, int> reducer_view(max_view);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
|
|
value_type max_view_scalar = max_view();
|
|
ASSERT_EQ(max_view_scalar.val, reference_max);
|
|
ASSERT_EQ(max_view_scalar.loc, reference_loc);
|
|
|
|
value_type max_view_view = reducer_view.reference();
|
|
ASSERT_EQ(max_view_view.val, reference_max);
|
|
ASSERT_EQ(max_view_view.loc, reference_loc);
|
|
}
|
|
}
|
|
|
|
static void test_minmaxloc(int N) {
|
|
using value_type = typename Kokkos::MinMaxLoc<Scalar, int>::value_type;
|
|
|
|
Kokkos::View<Scalar*, ExecSpace> values("Values", N);
|
|
auto h_values = Kokkos::create_mirror_view(values);
|
|
Scalar reference_max = std::numeric_limits<Scalar>::min();
|
|
Scalar reference_min = std::numeric_limits<Scalar>::max();
|
|
int reference_minloc = -1;
|
|
int reference_maxloc = -1;
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
h_values(i) = (Scalar)(rand() % 100000 + 2);
|
|
}
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
if (h_values(i) > reference_max) {
|
|
reference_max = h_values(i);
|
|
reference_maxloc = i;
|
|
} else if (h_values(i) == reference_max) {
|
|
// Make max unique.
|
|
h_values(i) -= Scalar(1);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
if (h_values(i) < reference_min) {
|
|
reference_min = h_values(i);
|
|
reference_minloc = i;
|
|
} else if (h_values(i) == reference_min) {
|
|
// Make min unique.
|
|
h_values(i) += Scalar(1);
|
|
}
|
|
}
|
|
|
|
Kokkos::deep_copy(values, h_values);
|
|
|
|
MinMaxLocFunctor f;
|
|
f.values = values;
|
|
MinMaxLocFunctorTag f_tag;
|
|
f_tag.values = values;
|
|
|
|
{
|
|
value_type minmax_scalar;
|
|
Kokkos::MinMaxLoc<Scalar, int> reducer_scalar(minmax_scalar);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_scalar);
|
|
ASSERT_EQ(minmax_scalar.min_val, reference_min);
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
if ((i == minmax_scalar.min_loc) && (h_values(i) == reference_min)) {
|
|
reference_minloc = i;
|
|
}
|
|
}
|
|
|
|
ASSERT_EQ(minmax_scalar.min_loc, reference_minloc);
|
|
ASSERT_EQ(minmax_scalar.max_val, reference_max);
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
if ((i == minmax_scalar.max_loc) && (h_values(i) == reference_max)) {
|
|
reference_maxloc = i;
|
|
}
|
|
}
|
|
|
|
ASSERT_EQ(minmax_scalar.max_loc, reference_maxloc);
|
|
|
|
minmax_scalar = value_type();
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace, ReducerTag>(0, N),
|
|
f_tag, reducer_scalar);
|
|
ASSERT_EQ(minmax_scalar.min_val, reference_min);
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
if ((i == minmax_scalar.min_loc) && (h_values(i) == reference_min)) {
|
|
reference_minloc = i;
|
|
}
|
|
}
|
|
|
|
ASSERT_EQ(minmax_scalar.min_loc, reference_minloc);
|
|
ASSERT_EQ(minmax_scalar.max_val, reference_max);
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
if ((i == minmax_scalar.max_loc) && (h_values(i) == reference_max)) {
|
|
reference_maxloc = i;
|
|
}
|
|
}
|
|
|
|
ASSERT_EQ(minmax_scalar.max_loc, reference_maxloc);
|
|
|
|
value_type minmax_scalar_view = reducer_scalar.reference();
|
|
ASSERT_EQ(minmax_scalar_view.min_val, reference_min);
|
|
ASSERT_EQ(minmax_scalar_view.min_loc, reference_minloc);
|
|
ASSERT_EQ(minmax_scalar_view.max_val, reference_max);
|
|
ASSERT_EQ(minmax_scalar_view.max_loc, reference_maxloc);
|
|
}
|
|
|
|
{
|
|
Kokkos::View<value_type, Kokkos::HostSpace> minmax_view("View");
|
|
Kokkos::MinMaxLoc<Scalar, int> reducer_view(minmax_view);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
|
|
value_type minmax_view_scalar = minmax_view();
|
|
ASSERT_EQ(minmax_view_scalar.min_val, reference_min);
|
|
ASSERT_EQ(minmax_view_scalar.min_loc, reference_minloc);
|
|
ASSERT_EQ(minmax_view_scalar.max_val, reference_max);
|
|
ASSERT_EQ(minmax_view_scalar.max_loc, reference_maxloc);
|
|
|
|
value_type minmax_view_view = reducer_view.reference();
|
|
ASSERT_EQ(minmax_view_view.min_val, reference_min);
|
|
ASSERT_EQ(minmax_view_view.min_loc, reference_minloc);
|
|
ASSERT_EQ(minmax_view_view.max_val, reference_max);
|
|
ASSERT_EQ(minmax_view_view.max_loc, reference_maxloc);
|
|
}
|
|
}
|
|
|
|
static void test_BAnd(int N) {
|
|
Kokkos::View<Scalar*, ExecSpace> values("Values", N);
|
|
auto h_values = Kokkos::create_mirror_view(values);
|
|
Scalar reference_band = Scalar() | (~Scalar());
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
h_values(i) = (Scalar)(rand() % 100000 + 1);
|
|
reference_band = reference_band & h_values(i);
|
|
}
|
|
Kokkos::deep_copy(values, h_values);
|
|
|
|
BAndFunctor f;
|
|
f.values = values;
|
|
BAndFunctorTag f_tag;
|
|
f_tag.values = values;
|
|
Scalar init = Scalar() | (~Scalar());
|
|
|
|
{
|
|
Scalar band_scalar = init;
|
|
Kokkos::BAnd<Scalar> reducer_scalar(band_scalar);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_scalar);
|
|
ASSERT_EQ(band_scalar, reference_band);
|
|
|
|
band_scalar = init;
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace, ReducerTag>(0, N),
|
|
f_tag, reducer_scalar);
|
|
ASSERT_EQ(band_scalar, reference_band);
|
|
|
|
Scalar band_scalar_view = reducer_scalar.reference();
|
|
|
|
ASSERT_EQ(band_scalar_view, reference_band);
|
|
}
|
|
|
|
{
|
|
Kokkos::View<Scalar, Kokkos::HostSpace> band_view("View");
|
|
band_view() = init;
|
|
Kokkos::BAnd<Scalar> reducer_view(band_view);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
|
|
Scalar band_view_scalar = band_view();
|
|
ASSERT_EQ(band_view_scalar, reference_band);
|
|
|
|
Scalar band_view_view = reducer_view.reference();
|
|
ASSERT_EQ(band_view_view, reference_band);
|
|
}
|
|
}
|
|
|
|
static void test_BOr(int N) {
|
|
Kokkos::View<Scalar*, ExecSpace> values("Values", N);
|
|
auto h_values = Kokkos::create_mirror_view(values);
|
|
Scalar reference_bor = Scalar() & (~Scalar());
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
h_values(i) = (Scalar)((rand() % 100000 + 1) * 2);
|
|
reference_bor = reference_bor | h_values(i);
|
|
}
|
|
Kokkos::deep_copy(values, h_values);
|
|
|
|
BOrFunctor f;
|
|
f.values = values;
|
|
BOrFunctorTag f_tag;
|
|
f_tag.values = values;
|
|
Scalar init = Scalar() & (~Scalar());
|
|
|
|
{
|
|
Scalar bor_scalar = init;
|
|
Kokkos::BOr<Scalar> reducer_scalar(bor_scalar);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_scalar);
|
|
ASSERT_EQ(bor_scalar, reference_bor);
|
|
|
|
bor_scalar = init;
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace, ReducerTag>(0, N),
|
|
f_tag, reducer_scalar);
|
|
ASSERT_EQ(bor_scalar, reference_bor);
|
|
|
|
Scalar bor_scalar_view = reducer_scalar.reference();
|
|
ASSERT_EQ(bor_scalar_view, reference_bor);
|
|
}
|
|
|
|
{
|
|
Kokkos::View<Scalar, Kokkos::HostSpace> bor_view("View");
|
|
bor_view() = init;
|
|
Kokkos::BOr<Scalar> reducer_view(bor_view);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
|
|
Scalar bor_view_scalar = bor_view();
|
|
ASSERT_EQ(bor_view_scalar, reference_bor);
|
|
|
|
Scalar bor_view_view = reducer_view.reference();
|
|
ASSERT_EQ(bor_view_view, reference_bor);
|
|
}
|
|
}
|
|
|
|
static void test_LAnd(int N) {
|
|
Kokkos::View<Scalar*, ExecSpace> values("Values", N);
|
|
auto h_values = Kokkos::create_mirror_view(values);
|
|
Scalar reference_land = 1;
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
h_values(i) = (Scalar)(rand() % 2);
|
|
reference_land = reference_land && h_values(i);
|
|
}
|
|
Kokkos::deep_copy(values, h_values);
|
|
|
|
LAndFunctor f;
|
|
f.values = values;
|
|
LAndFunctorTag f_tag;
|
|
f_tag.values = values;
|
|
Scalar init = 1;
|
|
|
|
{
|
|
Scalar land_scalar = init;
|
|
Kokkos::LAnd<Scalar> reducer_scalar(land_scalar);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_scalar);
|
|
ASSERT_EQ(land_scalar, reference_land);
|
|
|
|
land_scalar = init;
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace, ReducerTag>(0, N),
|
|
f_tag, reducer_scalar);
|
|
ASSERT_EQ(land_scalar, reference_land);
|
|
|
|
Scalar land_scalar_view = reducer_scalar.reference();
|
|
ASSERT_EQ(land_scalar_view, reference_land);
|
|
}
|
|
|
|
{
|
|
Kokkos::View<Scalar, Kokkos::HostSpace> land_view("View");
|
|
land_view() = init;
|
|
Kokkos::LAnd<Scalar> reducer_view(land_view);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
|
|
Scalar land_view_scalar = land_view();
|
|
ASSERT_EQ(land_view_scalar, reference_land);
|
|
|
|
Scalar land_view_view = reducer_view.reference();
|
|
ASSERT_EQ(land_view_view, reference_land);
|
|
}
|
|
}
|
|
|
|
static void test_LOr(int N) {
|
|
Kokkos::View<Scalar*, ExecSpace> values("Values", N);
|
|
auto h_values = Kokkos::create_mirror_view(values);
|
|
Scalar reference_lor = 0;
|
|
|
|
for (int i = 0; i < N; i++) {
|
|
h_values(i) = (Scalar)(rand() % 2);
|
|
reference_lor = reference_lor || h_values(i);
|
|
}
|
|
Kokkos::deep_copy(values, h_values);
|
|
|
|
LOrFunctor f;
|
|
f.values = values;
|
|
LOrFunctorTag f_tag;
|
|
f_tag.values = values;
|
|
Scalar init = 0;
|
|
|
|
{
|
|
Scalar lor_scalar = init;
|
|
Kokkos::LOr<Scalar> reducer_scalar(lor_scalar);
|
|
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_scalar);
|
|
ASSERT_EQ(lor_scalar, reference_lor);
|
|
|
|
lor_scalar = init;
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace, ReducerTag>(0, N),
|
|
f_tag, reducer_scalar);
|
|
ASSERT_EQ(lor_scalar, reference_lor);
|
|
|
|
Scalar lor_scalar_view = reducer_scalar.reference();
|
|
ASSERT_EQ(lor_scalar_view, reference_lor);
|
|
}
|
|
|
|
{
|
|
Kokkos::View<Scalar, Kokkos::HostSpace> lor_view("View");
|
|
lor_view() = init;
|
|
Kokkos::LOr<Scalar> reducer_view(lor_view);
|
|
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecSpace>(0, N), f,
|
|
reducer_view);
|
|
Kokkos::fence();
|
|
|
|
Scalar lor_view_scalar = lor_view();
|
|
ASSERT_EQ(lor_view_scalar, reference_lor);
|
|
|
|
Scalar lor_view_view = reducer_view.reference();
|
|
ASSERT_EQ(lor_view_view, reference_lor);
|
|
}
|
|
}
|
|
|
|
static void execute_float() {
|
|
test_sum(10001);
|
|
test_prod(35);
|
|
test_min(10003);
|
|
test_minloc(10003);
|
|
test_max(10007);
|
|
test_maxloc(10007);
|
|
#if defined(KOKKOS_ENABLE_OPENMPTARGET) && defined(KOKKOS_COMPILER_CLANG) && \
|
|
(KOKKOS_COMPILER_CLANG < 1300)
|
|
// FIXME_OPENMPTARGET - The minmaxloc test fails llvm <= 13 version.
|
|
#else
|
|
test_minmaxloc(10007);
|
|
#endif
|
|
}
|
|
|
|
// NOTE test_prod generates N random numbers between 1 and 4.
|
|
// Although unlikely, the test below could still in principle overflow.
|
|
// For reference log(numeric_limits<int>)/log(4) is 15.5
|
|
static void execute_integer() {
|
|
test_sum(10001);
|
|
test_prod(sizeof(Scalar) > 4 ? 35 : 19); // avoid int overflow (see above)
|
|
test_min(10003);
|
|
test_minloc(10003);
|
|
test_max(10007);
|
|
test_maxloc(10007);
|
|
#if defined(KOKKOS_ENABLE_OPENMPTARGET) && defined(KOKKOS_COMPILER_CLANG) && \
|
|
(KOKKOS_COMPILER_CLANG < 1300)
|
|
// FIXME_OPENMPTARGET - The minmaxloc test fails llvm <= 13 version.
|
|
#else
|
|
test_minmaxloc(10007);
|
|
#endif
|
|
test_BAnd(35);
|
|
test_BOr(35);
|
|
test_LAnd(35);
|
|
test_LOr(35);
|
|
}
|
|
|
|
static void execute_basic() {
|
|
test_sum(10001);
|
|
test_prod(35);
|
|
}
|
|
|
|
static void execute_bool() {
|
|
test_LAnd(10001);
|
|
test_LOr(35);
|
|
}
|
|
};
|
|
|
|
} // namespace Test
|