diff --git a/Intro_Tutorial/lessons/09_raja_view/09_raja_view.cpp b/Intro_Tutorial/lessons/09_raja_view/09_raja_view.cpp index eb23bc9..61cb52d 100644 --- a/Intro_Tutorial/lessons/09_raja_view/09_raja_view.cpp +++ b/Intro_Tutorial/lessons/09_raja_view/09_raja_view.cpp @@ -4,53 +4,100 @@ #include "umpire/Umpire.hpp" #include "umpire/strategy/QuickPool.hpp" +// TODO: Uncomment this in order to build! //#define COMPILE +// Method to print arrays associated with the Views constructed above +void printArrayAsMatrix( double * array, int row, int col ) +{ + for ( int ii = 0; ii < row * col; ++ii ) + { + std::cout << array[ii] << " "; + if ( ((ii+1) % col == 0) ) + { + std::cout << std::endl; + } + } +} + int main() { #if defined(COMPILE) - - constexpr int N{1000}; + constexpr int M{3}; + constexpr int N{5}; double* a{nullptr}; - double* b{nullptr}; - double* c{nullptr}; + double* result_right{nullptr}; + double* result_left{nullptr}; auto& rm = umpire::ResourceManager::getInstance(); auto allocator = rm.getAllocator("HOST"); auto pool = rm.makeAllocator("POOL", allocator); - a = static_cast(pool.allocate(N*N*sizeof(double))); - b = static_cast(pool.allocate(N*N*sizeof(double))); - c = static_cast(pool.allocate(N*N*sizeof(double))); + a = static_cast(pool.allocate(M*N*sizeof(double))); + result_right = static_cast(pool.allocate(M*N*sizeof(double))); + result_left = static_cast(pool.allocate(M*N*sizeof(double))); - RAJA::TypedRangeSegment row_range(0, N); - RAJA::TypedRangeSegment col_range(0, N); - - // TODO: Create a view for A, B, and C constexpr int DIM = 2; - RAJA::forall( row_range, [=](int row) { - RAJA::forall( col_range, [=](int col) { - A(row, col) = row; - B(row, col) = col; - }); - }); - - RAJA::forall( row_range, [=](int row) { - RAJA::forall( col_range, [=](int col) { - double dot = 0.0; - for (int k = 0; k < N; ++k) { - dot += A(row, k) * B(k, col); - } - C(row, col) = dot; - }); - }); + // TODO: Create a standard MxN RAJA::View called "A", initialized with the + // "a" array. + RAJA::View> A(???, ???, ???); - pool.deallocate(a); - pool.deallocate(b); - pool.deallocate(c); + // A left-oriented layout view initialized with the "result_left" array + auto L = RAJA::make_permuted_view(result_left, M, N); + + // TODO: Create a permuted MxN view with a right-oriented layout called "R", + // initialized with the "result_right" array. + auto R = ???; + // Note that Views created by RAJA::make_permuted_view know the unit stride + // index at compile time, which prevents unnecessary index arithmetic. + + // TODO: Fill in loop bounds that are appropriate for right-oriented layout + // Views A and R. + for ( int row = 0; row < ???; ++row ) + { + for ( int col = 0; col < ???; ++col ) + { + // TODO: Initialize A and R views to their index values, e.g. index 0 + // should contain 0, index 1 should contain 1, . . ., index 14 should + // contain 14. + // + // Note that both A and R should print out the same sequence of values + // in the calls to 'printArrayAsMatrix' below. + A(row, col) = ???; + R(row, col) = ???; + } + } + + // The L view will receive the same values as A and R. To achieve this, + // the loop indexing is reversed from the previous initialization loops + // because L is a left-oriented layout. The values assigned to L also + // reflect left-oriented indexing arithmetic. + for ( int col = 0; col < N; ++col ) + { + for ( int row = 0; row < M; ++row ) + { + L(row, col) = col * M + row; + } + } + + // TODO: Run the code and review the output from the following method calls + // to make sure each array prints the same ordering of values. + // "a" and "result_right" should match "result_left". + std::cout << "a array under View A:" << std::endl; + printArrayAsMatrix( a, M, N ); + + std::cout << "result_right array under View R:" << std::endl; + printArrayAsMatrix( result_right, M, N ); + + std::cout << "result_left array under View L:" << std::endl; + printArrayAsMatrix( result_left, M, N ); + + pool.deallocate(a); + pool.deallocate(result_right); + pool.deallocate(result_left); #endif return 0; diff --git a/Intro_Tutorial/lessons/09_raja_view/09_raja_view_solution.cpp b/Intro_Tutorial/lessons/09_raja_view/09_raja_view_solution.cpp new file mode 100644 index 0000000..7c79388 --- /dev/null +++ b/Intro_Tutorial/lessons/09_raja_view/09_raja_view_solution.cpp @@ -0,0 +1,103 @@ +#include + +#include "RAJA/RAJA.hpp" +#include "umpire/Umpire.hpp" +#include "umpire/strategy/QuickPool.hpp" + +#define COMPILE + +// Method to print arrays associated with the Views constructed above +void printArrayAsMatrix( double * array, int row, int col ) +{ + for ( int ii = 0; ii < row * col; ++ii ) + { + std::cout << array[ii] << " "; + if ( ((ii+1) % col == 0) ) + { + std::cout << std::endl; + } + } +} + +int main() +{ +#if defined(COMPILE) + constexpr int M{3}; + constexpr int N{5}; + double* a{nullptr}; + double* result_right{nullptr}; + double* result_left{nullptr}; + + auto& rm = umpire::ResourceManager::getInstance(); + + auto allocator = rm.getAllocator("HOST"); + auto pool = rm.makeAllocator("POOL", allocator); + + a = static_cast(pool.allocate(M*N*sizeof(double))); + result_right = static_cast(pool.allocate(M*N*sizeof(double))); + result_left = static_cast(pool.allocate(M*N*sizeof(double))); + + constexpr int DIM = 2; + + // TODO: Create a standard MxN RAJA::View called "A", initialized with the + // "a" array. + RAJA::View> A(a, M, N); + + // A left-oriented layout view initialized with the "result_left" array + auto L = RAJA::make_permuted_view(result_left, M, N); + + // TODO: Create a permuted MxN view with a right-oriented layout called "R", + // initialized with the "result_right" array. + auto R = RAJA::make_permuted_view(result_right, M, N); + + // Note that Views created by RAJA::make_permuted_view know the unit stride + // index at compile time, which prevents unnecessary index arithmetic. + + // TODO: Fill in loop bounds that are appropriate for right-oriented layout + // Views A and R. + for ( int row = 0; row < M; ++row ) + { + for ( int col = 0; col < N; ++col ) + { + // TODO: Initialize A and R views to their index values, e.g. index 0 + // should contain 0, index 1 should contain 1, . . ., index 14 should + // contain 14. + // + // Note that both A and R should print out the same sequence of values + // in the calls to 'printArrayAsMatrix' below. + A(row, col) = row * N + col; + R(row, col) = row * N + col; + } + } + + // The L view will receive the same values as A and R. To achieve this, + // the loop indexing is reversed from the previous initialization loops + // because L is a left-oriented layout. The values assigned to L also + // reflect left-oriented indexing arithmetic. + for ( int col = 0; col < N; ++col ) + { + for ( int row = 0; row < M; ++row ) + { + L(row, col) = col * M + row; + } + } + + // TODO: Run the code and review the output from the following method calls + // to make sure each array prints the same ordering of values. + // "a" and "result_right" should match "result_left". + std::cout << "a array under View A:" << std::endl; + printArrayAsMatrix( a, M, N ); + + std::cout << "result_right array under View R:" << std::endl; + printArrayAsMatrix( result_right, M, N ); + + std::cout << "result_left array under View L:" << std::endl; + printArrayAsMatrix( result_left, M, N ); + + pool.deallocate(a); + pool.deallocate(result_right); + pool.deallocate(result_left); +#endif + + return 0; +} diff --git a/Intro_Tutorial/lessons/09_raja_view/CMakeLists.txt b/Intro_Tutorial/lessons/09_raja_view/CMakeLists.txt index 734f5dd..d81d8e1 100644 --- a/Intro_Tutorial/lessons/09_raja_view/CMakeLists.txt +++ b/Intro_Tutorial/lessons/09_raja_view/CMakeLists.txt @@ -2,3 +2,8 @@ blt_add_executable( NAME 09_raja_view SOURCES 09_raja_view.cpp DEPENDS_ON cuda RAJA umpire) + +blt_add_executable( + NAME 09_raja_view_solution + SOURCES 09_raja_view_solution.cpp + DEPENDS_ON cuda RAJA umpire) diff --git a/Intro_Tutorial/lessons/09_raja_view/README.md b/Intro_Tutorial/lessons/09_raja_view/README.md index 00a49f5..124abd5 100644 --- a/Intro_Tutorial/lessons/09_raja_view/README.md +++ b/Intro_Tutorial/lessons/09_raja_view/README.md @@ -33,11 +33,14 @@ RAJA::View> view(data, N, N); where `data` is a `double*`, and `N` is the size of each dimension. The size of `data` should be at least `N*N`. -In the file `09_raja_view.cpp`, there is a `TODO` comment where you should create three -views, A, B, and C. You will notice that we are doing the same dot product -calculation, but this time for matrices. Thus, we are now doing a matrix -multiplication. When you are ready, uncomment the COMPILE define on line 7; -then you can compile and run the code: +In the file `09_raja_view.cpp`, there are two `TODO` comments where you should create two +views, A, and R. R will be created via a permuted view with the same right-oriented layout +as A. Knowledge of `RAJA::make_permuted_view` is not required to complete this task, but +more information can be found here: +https://raja.readthedocs.io/en/develop/sphinx/user_guide/feature/view.html#make-permuted-view. +There are two `TODO` comments where you should complete the loop bounds, and fill +in A and R with their respective index values. +When you are ready, uncomment the COMPILE define on line 8; then you can compile and run the code: ``` $ make 09_raja_view diff --git a/Intro_Tutorial/lessons/09_raja_view/solution/09_raja_view.cpp b/Intro_Tutorial/lessons/09_raja_view/solution/09_raja_view.cpp deleted file mode 100644 index 24f0a46..0000000 --- a/Intro_Tutorial/lessons/09_raja_view/solution/09_raja_view.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include - -#include "RAJA/RAJA.hpp" -#include "umpire/Umpire.hpp" -#include "umpire/strategy/QuickPool.hpp" - -int main() -{ - constexpr int N{10000}; - double* a{nullptr}; - double* b{nullptr}; - double* c{nullptr}; - - auto& rm = umpire::ResourceManager::getInstance(); - - auto allocator = rm.getAllocator("HOST"); - auto pool = rm.makeAllocator("POOL", allocator); - - a = static_cast(pool.allocate(N*N*sizeof(double))); - b = static_cast(pool.allocate(N*N*sizeof(double))); - c = static_cast(pool.allocate(N*N*sizeof(double))); - - RAJA::TypedRangeSegment row_range(0, N); - RAJA::TypedRangeSegment col_range(0, N); - - // TODO: Create a view for A, B, and C - constexpr int DIM = 2; - RAJA::View> A(a, N, N); - RAJA::View> B(b, N, N); - RAJA::View> C(c, N, N); - - RAJA::forall( row_range, [=](int row) { - RAJA::forall( col_range, [=](int col) { - A(row, col) = row; - B(row, col) = col; - }); - }); - - RAJA::forall( row_range, [=](int row) { - RAJA::forall( col_range, [=](int col) { - double dot = 0.0; - for (int k = 0; k < N; ++k) { - dot += A(row, k) * B(k, col); - } - C(row, col) = dot; - }); - }); - - pool.deallocate(a); - pool.deallocate(b); - pool.deallocate(c); - - return 0; -}