/* //@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 #include #include #include //-------------------------------------------------------------------------- namespace Test { struct ReducerTag {}; template struct TestReducers { struct SumFunctor { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()(const int& i, Scalar& value) const { value += values(i); } }; struct ProdFunctor { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()(const int& i, Scalar& value) const { value *= values(i); } }; struct MinFunctor { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()(const int& i, Scalar& value) const { if (values(i) < value) value = values(i); } }; struct MaxFunctor { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()(const int& i, Scalar& value) const { if (values(i) > value) value = values(i); } }; struct MinLocFunctor { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()( const int& i, typename Kokkos::MinLoc::value_type& value) const { if (values(i) < value.val) { value.val = values(i); value.loc = i; } } }; struct MaxLocFunctor { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()( const int& i, typename Kokkos::MaxLoc::value_type& value) const { if (values(i) > value.val) { value.val = values(i); value.loc = i; } } }; struct MinMaxLocFunctor { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()( const int& i, typename Kokkos::MinMaxLoc::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 values; KOKKOS_INLINE_FUNCTION void operator()(const int& i, Scalar& value) const { value = value & values(i); } }; struct BOrFunctor { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()(const int& i, Scalar& value) const { value = value | values(i); } }; struct LAndFunctor { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()(const int& i, Scalar& value) const { value = value && values(i); } }; struct LOrFunctor { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()(const int& i, Scalar& value) const { value = value || values(i); } }; struct SumFunctorTag { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()(const ReducerTag, const int& i, Scalar& value) const { value += values(i); } }; struct ProdFunctorTag { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()(const ReducerTag, const int& i, Scalar& value) const { value *= values(i); } }; struct MinFunctorTag { Kokkos::View 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 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 values; KOKKOS_INLINE_FUNCTION void operator()( const ReducerTag, const int& i, typename Kokkos::MinLoc::value_type& value) const { if (values(i) < value.val) { value.val = values(i); value.loc = i; } } }; struct MaxLocFunctorTag { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()( const ReducerTag, const int& i, typename Kokkos::MaxLoc::value_type& value) const { if (values(i) > value.val) { value.val = values(i); value.loc = i; } } }; struct MinMaxLocFunctorTag { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()( const ReducerTag, const int& i, typename Kokkos::MinMaxLoc::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 values; KOKKOS_INLINE_FUNCTION void operator()(const ReducerTag, const int& i, Scalar& value) const { value = value & values(i); } }; struct BOrFunctorTag { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()(const ReducerTag, const int& i, Scalar& value) const { value = value | values(i); } }; struct LAndFunctorTag { Kokkos::View values; KOKKOS_INLINE_FUNCTION void operator()(const ReducerTag, const int& i, Scalar& value) const { value = value && values(i); } }; struct LOrFunctorTag { Kokkos::View 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 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; // clang-format off // For bhalf, we start overflowing integer values at 2^8. // after 2^8, we lose representation of odd numbers; // after 2^9, we lose representation of odd and even numbers in position 1. // after 2^10, we lose representation of odd and even numbers in position 1-3. // after 2^11, we lose representation of odd and even numbers in position 1-7. // ... // Generally, for IEEE 754 floating point numbers, we start this overflow pattern at: 2^(num_fraction_bits+1). // brain float has num_fraction_bits = 7. // This mask addresses #4719 for N <= 51. // The mask is not needed for N <= 25. // clang-format on int mask = std::is_same::value && N > 25 ? (int)0xfffffffe : (int)0xffffffff; h_values(i) = (Scalar)((rand() % denom) & mask); 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 reducer_scalar(sum_scalar); Kokkos::parallel_reduce(Kokkos::RangePolicy(0, 0), f, reducer_scalar); ASSERT_EQ(sum_scalar, init) << "N: " << N; Kokkos::parallel_reduce(Kokkos::RangePolicy(0, N), f, reducer_scalar); ASSERT_EQ(sum_scalar, reference_sum) << "N: " << N; sum_scalar = init; Kokkos::parallel_reduce(Kokkos::RangePolicy(0, N), f_tag, reducer_scalar); ASSERT_EQ(sum_scalar, reference_sum) << "N: " << N; Scalar sum_scalar_view = reducer_scalar.reference(); ASSERT_EQ(sum_scalar_view, reference_sum) << "N: " << N; } { Kokkos::View sum_view("View"); sum_view() = Scalar(1); Kokkos::Sum reducer_view(sum_view); Kokkos::parallel_reduce(Kokkos::RangePolicy(0, 0), f, reducer_view); Kokkos::fence(); Scalar sum_view_scalar = sum_view(); ASSERT_EQ(sum_view_scalar, init) << "N: " << N; Kokkos::parallel_reduce(Kokkos::RangePolicy(0, N), f, reducer_view); Kokkos::fence(); sum_view_scalar = sum_view(); ASSERT_EQ(sum_view_scalar, reference_sum) << "N: " << N; Scalar sum_view_view = reducer_view.reference(); ASSERT_EQ(sum_view_view, reference_sum) << "N: " << N; } { Kokkos::View sum_view("View"); Kokkos::deep_copy(sum_view, Scalar(1)); Kokkos::Sum reducer_view( sum_view); Kokkos::parallel_reduce(Kokkos::RangePolicy(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) << "N: " << N; Kokkos::parallel_reduce(Kokkos::RangePolicy(0, N), f, reducer_view); Kokkos::fence(); Kokkos::deep_copy(sum_view_scalar, sum_view); ASSERT_EQ(sum_view_scalar, reference_sum) << "N: " << N; } } static void test_prod(int N) { Kokkos::View 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 reducer_scalar(prod_scalar); Kokkos::parallel_reduce(Kokkos::RangePolicy(0, 0), f, reducer_scalar); ASSERT_EQ(prod_scalar, init); Kokkos::parallel_reduce(Kokkos::RangePolicy(0, N), f, reducer_scalar); ASSERT_EQ(prod_scalar, reference_prod); prod_scalar = init; Kokkos::parallel_reduce(Kokkos::RangePolicy(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 prod_view("View"); prod_view() = Scalar(0); Kokkos::Prod reducer_view(prod_view); Kokkos::parallel_reduce(Kokkos::RangePolicy(0, 0), f, reducer_view); Kokkos::fence(); Scalar prod_view_scalar = prod_view(); ASSERT_EQ(prod_view_scalar, init); Kokkos::parallel_reduce(Kokkos::RangePolicy(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 prod_view("View"); Kokkos::deep_copy(prod_view, Scalar(0)); Kokkos::Prod reducer_view( prod_view); Kokkos::parallel_reduce(Kokkos::RangePolicy(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(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 values("Values", N); auto h_values = Kokkos::create_mirror_view(values); Scalar reference_min = std::numeric_limits::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::max(); { Scalar min_scalar = init; Kokkos::Min reducer_scalar(min_scalar); Kokkos::parallel_reduce(Kokkos::RangePolicy(0, N), f, reducer_scalar); ASSERT_EQ(min_scalar, reference_min); min_scalar = init; Kokkos::parallel_reduce(Kokkos::RangePolicy(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 min_view("View"); min_view() = init; Kokkos::Min reducer_view(min_view); Kokkos::parallel_reduce(Kokkos::RangePolicy(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 values("Values", N); auto h_values = Kokkos::create_mirror_view(values); Scalar reference_max = std::numeric_limits::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::min(); { Scalar max_scalar = init; Kokkos::Max reducer_scalar(max_scalar); Kokkos::parallel_reduce(Kokkos::RangePolicy(0, N), f, reducer_scalar); ASSERT_EQ(max_scalar, reference_max); max_scalar = init; Kokkos::parallel_reduce(Kokkos::RangePolicy(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 max_view("View"); max_view() = init; Kokkos::Max reducer_view(max_view); Kokkos::parallel_reduce(Kokkos::RangePolicy(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::value_type; Kokkos::View values("Values", N); auto h_values = Kokkos::create_mirror_view(values); Scalar reference_min = std::numeric_limits::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 reducer_scalar(min_scalar); Kokkos::parallel_reduce(Kokkos::RangePolicy(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(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 min_view("View"); Kokkos::MinLoc reducer_view(min_view); Kokkos::parallel_reduce(Kokkos::RangePolicy(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::value_type; Kokkos::View values("Values", N); auto h_values = Kokkos::create_mirror_view(values); Scalar reference_max = std::numeric_limits::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 reducer_scalar(max_scalar); Kokkos::parallel_reduce(Kokkos::RangePolicy(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(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 max_view("View"); Kokkos::MaxLoc reducer_view(max_view); Kokkos::parallel_reduce(Kokkos::RangePolicy(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::value_type; Kokkos::View values("Values", N); auto h_values = Kokkos::create_mirror_view(values); Scalar reference_max = std::numeric_limits::min(); Scalar reference_min = std::numeric_limits::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 reducer_scalar(minmax_scalar); Kokkos::parallel_reduce(Kokkos::RangePolicy(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(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 minmax_view("View"); Kokkos::MinMaxLoc reducer_view(minmax_view); Kokkos::parallel_reduce(Kokkos::RangePolicy(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 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 reducer_scalar(band_scalar); Kokkos::parallel_reduce(Kokkos::RangePolicy(0, N), f, reducer_scalar); ASSERT_EQ(band_scalar, reference_band); band_scalar = init; Kokkos::parallel_reduce(Kokkos::RangePolicy(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 band_view("View"); band_view() = init; Kokkos::BAnd reducer_view(band_view); Kokkos::parallel_reduce(Kokkos::RangePolicy(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 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 reducer_scalar(bor_scalar); Kokkos::parallel_reduce(Kokkos::RangePolicy(0, N), f, reducer_scalar); ASSERT_EQ(bor_scalar, reference_bor); bor_scalar = init; Kokkos::parallel_reduce(Kokkos::RangePolicy(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 bor_view("View"); bor_view() = init; Kokkos::BOr reducer_view(bor_view); Kokkos::parallel_reduce(Kokkos::RangePolicy(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 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 reducer_scalar(land_scalar); Kokkos::parallel_reduce(Kokkos::RangePolicy(0, N), f, reducer_scalar); ASSERT_EQ(land_scalar, reference_land); land_scalar = init; Kokkos::parallel_reduce(Kokkos::RangePolicy(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 land_view("View"); land_view() = init; Kokkos::LAnd reducer_view(land_view); Kokkos::parallel_reduce(Kokkos::RangePolicy(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 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 reducer_scalar(lor_scalar); Kokkos::parallel_reduce(Kokkos::RangePolicy(0, N), f, reducer_scalar); ASSERT_EQ(lor_scalar, reference_lor); lor_scalar = init; Kokkos::parallel_reduce(Kokkos::RangePolicy(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 lor_view("View"); lor_view() = init; Kokkos::LOr reducer_view(lor_view); Kokkos::parallel_reduce(Kokkos::RangePolicy(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)/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