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:6
49 // Unit Test for MDRangePolicy without Views uptil 4 ranks.
50 // For each of the MDRangePolicy test from 2-to-4 ranks, we create an equivalent
51 // dimensional array implemented in 1D. In each of these arrays we update the
52 // elements as a product of iterator indexes and a constant. At the end, we
53 // check for correctness.
54 
55 namespace Test06 {
56 
57 using value_type = double;
58 
59 struct MDFunctor {
60   value_type *_data;
61   const value_type _delta;
62   const int N = 10;
63   const int M = 10;
64 
MDFunctorTest06::MDFunctor65   MDFunctor(value_type *data, const value_type delta)
66       : _data(data), _delta(delta) {}
67 
68   // 2D
69   KOKKOS_INLINE_FUNCTION
operator ()Test06::MDFunctor70   void operator()(const int i, const int j) const {
71     _data[i * M + j] = i * j * _delta;
72   }
73 
74   // 3D
75   KOKKOS_INLINE_FUNCTION
operator ()Test06::MDFunctor76   void operator()(const int i, const int j, const int k) const {
77     _data[i * M * N + j * M + k] = i * j * k * _delta;
78   }
79 
80   // 4D
81   KOKKOS_INLINE_FUNCTION
operator ()Test06::MDFunctor82   void operator()(const int i, const int j, const int k, const int l) const {
83     _data[i * M * N * M + j * M * N + k * M + l] = i * j * k * l * _delta;
84   }
85 };
86 
87 template <class ExecSpace>
88 struct TestMDRangePolicy {
89   // Memory space type for Device and Host data
90   using d_memspace_type = typename ExecSpace::memory_space;
91   using h_memspace_type = Kokkos::HostSpace;
92 
93   // Index Type for the iterator
94   using int_index = Kokkos::IndexType<int>;
95 
96   // An MDRangePolicy for 2 nested loops
97   using MDPolicyType_2D = typename Kokkos::Experimental::MDRangePolicy<
98       ExecSpace, Kokkos::Experimental::Rank<2>, int_index>;
99 
100   // An MDRangePolicy for 3 nested loops
101   using MDPolicyType_3D = typename Kokkos::Experimental::MDRangePolicy<
102       ExecSpace, Kokkos::Experimental::Rank<3>, int_index>;
103 
104   // An MDRangePolicy for 4 nested loops
105   using MDPolicyType_4D = typename Kokkos::Experimental::MDRangePolicy<
106       ExecSpace, Kokkos::Experimental::Rank<4>, int_index>;
107 
108   // Device and Host Data structure pointer
109   value_type *deviceData, *hostData;
110   const value_type delta = 0.5;
111   const int N            = 10;
112   const int M            = 10;
113 
114   // Routine to allocate memory in a specific memory space.
115   template <class MemSpace>
allocate_memTest06::TestMDRangePolicy116   value_type *allocate_mem(int N_) {
117     return (static_cast<value_type *>(
118         Kokkos::kokkos_malloc<MemSpace>("Data", N_ * sizeof(value_type))));
119   }
120 
121   // Routine to free the memory from a specific memory space.
122   template <class MemSpace>
free_memTest06::TestMDRangePolicy123   void free_mem(value_type *data) {
124     Kokkos::kokkos_free<MemSpace>(data);
125   }
126 
127   // compare and equal
compare_equal_2DTest06::TestMDRangePolicy128   void compare_equal_2D() {
129     for (int i = 0; i < N; ++i)
130       for (int j = 0; j < M; ++j) ASSERT_EQ(hostData[i * M + j], i * j * delta);
131   }
132 
133   // compare and equal
compare_equal_3DTest06::TestMDRangePolicy134   void compare_equal_3D() {
135     for (int i = 0; i < N; ++i)
136       for (int j = 0; j < M; ++j)
137         for (int k = 0; k < N; ++k)
138           ASSERT_EQ(hostData[i * M * N + j * M + k], i * j * k * delta);
139   }
140 
141   // compare and equal
compare_equal_4DTest06::TestMDRangePolicy142   void compare_equal_4D() {
143     for (int i = 0; i < N; ++i)
144       for (int j = 0; j < M; ++j)
145         for (int k = 0; k < N; ++k)
146           for (int l = 0; l < M; ++l)
147             ASSERT_EQ(hostData[i * M * N * M + j * M * N + k * M + l],
148                       i * j * k * l * delta);
149   }
150 
151   // A 2-D MDRangePolicy
mdRange2DTest06::TestMDRangePolicy152   void mdRange2D() {
153     MDPolicyType_2D mdPolicy_2D({0, 0}, {N, M});
154 
155     // Total number of elements
156     int num_elements = N * M;
157 
158     // Allocate Memory for both device and host memory spaces
159     // Data[M*N]
160     deviceData = allocate_mem<d_memspace_type>(num_elements);
161     ASSERT_NE(deviceData, nullptr);
162 
163     hostData = allocate_mem<h_memspace_type>(num_elements);
164     ASSERT_NE(hostData, nullptr);
165 
166     // parallel_for call
167     MDFunctor Functor_2D(deviceData, delta);
168     Kokkos::parallel_for("MDRange2D", mdPolicy_2D, Functor_2D);
169 
170     // Copy the data back to Host memory space
171     Kokkos::Impl::DeepCopy<h_memspace_type, d_memspace_type>(
172         hostData, deviceData, num_elements * sizeof(value_type));
173 
174     // Check if all data has been update correctly
175     compare_equal_2D();
176 
177     // free the allocated memory
178     free_mem<d_memspace_type>(deviceData);
179     free_mem<h_memspace_type>(hostData);
180   }
181 
182   // A 3-D MDRangePolicy
mdRange3DTest06::TestMDRangePolicy183   void mdRange3D() {
184     MDPolicyType_3D mdPolicy_3D({0, 0, 0}, {N, M, N});
185 
186     // Total number of elements
187     int num_elements = N * M * N;
188 
189     // Allocate Memory for both device and host memory spaces
190     // Data[M*N*N]
191     deviceData = allocate_mem<d_memspace_type>(num_elements);
192     ASSERT_NE(deviceData, nullptr);
193 
194     hostData = allocate_mem<h_memspace_type>(num_elements);
195     ASSERT_NE(hostData, nullptr);
196 
197     // parallel_for call
198     MDFunctor Functor_3D(deviceData, delta);
199     Kokkos::parallel_for("MDRange3D", mdPolicy_3D, Functor_3D);
200 
201     // Copy the data back to Host memory space
202     Kokkos::Impl::DeepCopy<h_memspace_type, d_memspace_type>(
203         hostData, deviceData, num_elements * sizeof(value_type));
204 
205     // Check if all data has been update correctly
206     compare_equal_3D();
207 
208     // free the allocated memory
209     free_mem<d_memspace_type>(deviceData);
210     free_mem<h_memspace_type>(hostData);
211   }
212 
213   // A 4-D MDRangePolicy
mdRange4DTest06::TestMDRangePolicy214   void mdRange4D() {
215     MDPolicyType_4D mdPolicy_4D({0, 0, 0, 0}, {N, M, N, M});
216 
217     // Total number of elements
218     int num_elements = N * M * N * M;
219 
220     // Allocate Memory for both device and host memory spaces
221     // Data[M*N*N*M]
222     deviceData = allocate_mem<d_memspace_type>(num_elements);
223     ASSERT_NE(deviceData, nullptr);
224 
225     hostData = allocate_mem<h_memspace_type>(num_elements);
226     ASSERT_NE(hostData, nullptr);
227 
228     // parallel_for call
229     MDFunctor Functor_4D(deviceData, delta);
230     Kokkos::parallel_for("MDRange4D", mdPolicy_4D, Functor_4D);
231 
232     // Copy the data back to Host memory space
233     Kokkos::Impl::DeepCopy<h_memspace_type, d_memspace_type>(
234         hostData, deviceData, num_elements * sizeof(value_type));
235 
236     // Check if all data has been update correctly
237     compare_equal_4D();
238 
239     // free the allocated memory
240     free_mem<d_memspace_type>(deviceData);
241     free_mem<h_memspace_type>(hostData);
242   }
243 };
244 
245 }  // namespace Test06
246 
247 namespace Test {
248 
249 // 2D MDRangePolicy
TEST(TEST_CATEGORY,IncrTest_06_mdrange2D)250 TEST(TEST_CATEGORY, IncrTest_06_mdrange2D) {
251   Test06::TestMDRangePolicy<TEST_EXECSPACE> test;
252   test.mdRange2D();
253 }
254 
255 // 3D MDRangePolicy
TEST(TEST_CATEGORY,IncrTest_06_mdrange3D)256 TEST(TEST_CATEGORY, IncrTest_06_mdrange3D) {
257   Test06::TestMDRangePolicy<TEST_EXECSPACE> test;
258   test.mdRange3D();
259 }
260 
261 // 4D MDRangePolicy
TEST(TEST_CATEGORY,IncrTest_06_mdrange4D)262 TEST(TEST_CATEGORY, IncrTest_06_mdrange4D) {
263   Test06::TestMDRangePolicy<TEST_EXECSPACE> test;
264   test.mdRange4D();
265 }
266 
267 }  // namespace Test
268