1 /*
2 //@HEADER
3 // ************************************************************************
4 //
5 //                        Kokkos v. 3.0
6 //       Copyright (2020) National Technology & Engineering
7 //               Solutions of Sandia, LLC (NTESS).
8 //
9 // Under the terms of Contract DE-NA0003525 with NTESS,
10 // the U.S. Government retains certain rights in this software.
11 //
12 // Redistribution and use in source and binary forms, with or without
13 // modification, are permitted provided that the following conditions are
14 // met:
15 //
16 // 1. Redistributions of source code must retain the above copyright
17 // notice, this list of conditions and the following disclaimer.
18 //
19 // 2. Redistributions in binary form must reproduce the above copyright
20 // notice, this list of conditions and the following disclaimer in the
21 // documentation and/or other materials provided with the distribution.
22 //
23 // 3. Neither the name of the Corporation nor the names of the
24 // contributors may be used to endorse or promote products derived from
25 // this software without specific prior written permission.
26 //
27 // THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
28 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
31 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 //
39 // Questions? Contact Christian R. Trott (crtrott@sandia.gov)
40 //
41 // ************************************************************************
42 //@HEADER
43 */
44 
45 #include <Kokkos_Core.hpp>
46 #include <gtest/gtest.h>
47 
48 /// @Kokkos_Feature_Level_Required:4
49 // parallel-for unit test.
50 // In this test, different elements of an array are updated by different
51 // threads.
52 
53 namespace Test {
54 
55 using value_type = double;
56 int num_elements = 10;
57 
58 struct ParallelForFunctor {
59   value_type *_data;
60   const value_type _value;
61 
ParallelForFunctorTest::ParallelForFunctor62   ParallelForFunctor(value_type *data, const value_type value)
63       : _data(data), _value(value) {}
64 
65   KOKKOS_INLINE_FUNCTION
operator ()Test::ParallelForFunctor66   void operator()(const int i) const { _data[i] = (i + 1) * _value; }
67 };
68 
69 template <class ExecSpace>
70 struct TestParallel_For {
71   // Memory space type for Device and Host data
72   using d_memspace_type = typename ExecSpace::memory_space;
73   using h_memspace_type = Kokkos::HostSpace;
74 
75   value_type *deviceData, *hostData;
76   const value_type value = 0.5;
77 
78   // Check if the array values are updated correctly.
correctness_checkTest::TestParallel_For79   void correctness_check(value_type *data) {
80     for (int i = 0; i < num_elements; ++i) {
81       ASSERT_EQ((i + 1) * value, data[i])
82           << "Values in index " << i << " are incorrect";
83     }
84   }
85 
86   // Routine to allocate memory in a specific memory space.
87   template <class MemSpace>
allocate_memTest::TestParallel_For88   value_type *allocate_mem(int N) {
89     return (static_cast<value_type *>(
90         Kokkos::kokkos_malloc<MemSpace>("deviceData", N * sizeof(value_type))));
91   }
92 
93   // Routine to free the memory from a specific memory space.
94   template <class MemSpace>
free_memTest::TestParallel_For95   void free_mem(value_type *data) {
96     Kokkos::kokkos_free<MemSpace>(data);
97   }
98 
initTest::TestParallel_For99   void init() {
100     // Allocate memory on Device space.
101     deviceData = allocate_mem<d_memspace_type>(num_elements);
102     ASSERT_NE(deviceData, nullptr);
103 
104     // Allocate memory on Host space.
105     hostData = allocate_mem<h_memspace_type>(num_elements);
106     ASSERT_NE(hostData, nullptr);
107   }
108 
check_correctness_and_cleanupTest::TestParallel_For109   void check_correctness_and_cleanup() {
110     // Copy the data back to Host memory space
111     Kokkos::Impl::DeepCopy<h_memspace_type, d_memspace_type>(
112         hostData, deviceData, num_elements * sizeof(value_type));
113 
114     // Check if all data has been update correctly
115     correctness_check(hostData);
116 
117     // free the allocated memory
118     free_mem<d_memspace_type>(deviceData);
119     free_mem<h_memspace_type>(hostData);
120   }
121 
122   // A simple parallel for test with functors
simple_testTest::TestParallel_For123   void simple_test() {
124     // Allocates memory for num_elements number of value_type elements in the
125     // host and device memory spaces.
126     init();
127 
128     // parallel-for functor called for num_elements number of iterations.
129     Kokkos::parallel_for("parallel_for",
130                          Kokkos::RangePolicy<ExecSpace>(0, num_elements),
131                          ParallelForFunctor(deviceData, value));
132 
133     Kokkos::fence();
134     // Checks if parallel_for gave the correct results.
135     // Frees the allocated memory in init().
136     check_correctness_and_cleanup();
137   }
138 
139   // A parallel_for test with user defined RangePolicy
range_policyTest::TestParallel_For140   void range_policy() {
141     // Allocates memory for num_elements number of value_type elements in the
142     // host and device memory spaces.
143     init();
144 
145     // Creates a range policy that uses dynamic scheduling.
146     using range_policy_t =
147         Kokkos::RangePolicy<ExecSpace, Kokkos::Schedule<Kokkos::Dynamic> >;
148 
149     // parallel-for functor with range-policy from 0 to num_elements iterations.
150     Kokkos::parallel_for("RangePolicy_ParallelFor",
151                          range_policy_t(0, num_elements),
152                          ParallelForFunctor(deviceData, value));
153 
154     // Checks if parallel_for gave the correct results.
155     // Free the allocated memory in init().
156     check_correctness_and_cleanup();
157   }
158 };
159 
TEST(TEST_CATEGORY,IncrTest_04_simple_parallelFor)160 TEST(TEST_CATEGORY, IncrTest_04_simple_parallelFor) {
161   if (std::is_same<Kokkos::DefaultExecutionSpace, TEST_EXECSPACE>::value) {
162     TestParallel_For<TEST_EXECSPACE> test;
163     test.simple_test();
164   }
165 }
166 
TEST(TEST_CATEGORY,IncrTest_04_RangePolicy_parallelFor)167 TEST(TEST_CATEGORY, IncrTest_04_RangePolicy_parallelFor) {
168   TestParallel_For<TEST_EXECSPACE> test;
169   test.range_policy();
170 }
171 
172 }  // namespace Test
173