A Simple Program Using Kokkos
The following is a simple program that uses Kokkos and incorporates the ideas from the previous page.
/* kokkos_example.cpp */
#include <Kokkos_Core.hpp> // Main Kokkos header file
#include <iostream>
int main(int argc, char* argv[])
{
// Like MPI, Kokkos must be initialized before first use.
// Kokkos::initialize should come after MPI_Init.
Kokkos::initialize(argc, argv);
{ // Scope guard on Kokkos::initialize
// Define the memory space and execution space. This program assumes there is a
// NVIDIA GPU on the system.
using memory_space = Kokkos::CudaSpace;
using execution_space = Kokkos::Cuda;
// Create a View in device memory.
// In native C++, this is similar to:
// std::vector<std::array<int, 2>> myVector(10);
Kokkos::View<int*[2], memory_space> myView("myView", 10);
// Fill the View with a parallel for loop. Because the View resides in device
// memory, it must be accessed in a parallel for loop whose execution space can
// access the memory space the View resides in. Here, a multi-dimensional
// range policy is used to iterate over both the first and second dimensions
// in one parallel loop. myView.extent(0) must be cast to an integer because
// the MDRangePolicy only accepts integer ranges.
Kokkos::parallel_for(
"example_parallel_for",
Kokkos::MDRangePolicy<execution_space, Kokkos::Rank<2>>(
{{0, 0}, {static_cast<int>(myView.extent(0)), 2}}),
KOKKOS_LAMBDA(const int i, const int j) {
myView(i, j) = i + (-1 * (j % 2));
});
// Ensure all parallel operations have completed before continuing.
Kokkos::fence();
// Print the View to standard out using a serial loop in host execution space.
// Do do this, the View must first be copied from device memory to host memory.
// Note: myView_h is a shallow copy of myView. If the values in myView are
// modified, the values in myView_h will also change.
auto myView_h = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), myView);
// Now we can print the View serially outside of a parallel for loop.
for (std::size_t i = 0; i < myView_h.extent(0); ++i)
for (int j = 0; j < 2; ++j)
std::cout << "myView(" << i << ", " << j << "): " << myView_h(i, j)
<< std::endl;
} // end scope guard
// Finalize Kokkos. Place before any point the program exits and before MPI_Finalize.
Kokkos::finalize();
return 0;
}
To compile this program, build and install Kokkos manually (not recommended) or with Spack (recommended) and create a CMakeLists.txt file with the contents:
cmake_minimum_required(VERSION 3.16)
project(kokkos_example CXX)
find_package(Kokkos REQUIRED)
add_executable(kokkos_example kokkos_example.cpp)
target_link_libraries(kokkos_example Kokkos::kokkos)
And run the following commands (If Kokkos is installed via a Spack environment, CMake will automatically find Kokkos):
mkdir build && cd build
cmake .. # If Kokkos is installed manually, must include -DCMAKE_PREFIX_PATH=$HOME/kokkos/install/path
make
./kokkos_example
The program will print the following output:
myView(0, 0): 0
myView(0, 1): -1
myView(1, 0): 1
myView(1, 1): 0
myView(2, 0): 2
myView(2, 1): 1
myView(3, 0): 3
myView(3, 1): 2
myView(4, 0): 4
myView(4, 1): 3
myView(5, 0): 5
myView(5, 1): 4
myView(6, 0): 6
myView(6, 1): 5
myView(7, 0): 7
myView(7, 1): 6
myView(8, 0): 8
myView(8, 1): 7
myView(9, 0): 9
myView(9, 1): 8