Skip to content

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