Views
1. What is Kokkos View ?
Kokkos Views are a fundamental abstraction in the Kokkos programming model, designed to provide a portable and efficient way to manage multidimensional arrays across diverse computing architectures. These Views serve as the primary data structure in Kokkos, offering a powerful mechanism for handling data in high-performance computing applications.
Views can have up to eight dimensions, and these dimensions can be specified at either compile-time or run-time. The flexibility in dimension specification allows for efficient memory management and optimization across different hardware architectures.
The motivation behind the View abstraction stems from the evolving landscape of high-performance computing. The memory space, which can be explicitly specified as an additional template parameter, determines where the data resides and which execution units can access it.
The View life cycle is an essential aspect of using Kokkos effectively. When a View is constructed, it allocates memory in the specified memory space. Kokkos employs a reference-counting mechanism to manage the lifetime of this allocation. As Views are copied or assigned, the reference count is adjusted accordingly. The View abstraction is part of Kokkos' broader machine model, which assumes a hierarchy of execution spaces and memory spaces. This model anticipates future shared-memory computing architectures, where nodes might contain multiple types of compute engines and memory systems. By abstracting these details through Views, Kokkos allows developers to write code that can adapt to evolving hardware landscapes without significant rewrites.
In the context of high-performance computing, Kokkos Views shine in their ability to handle large, multidimensional data structures efficiently. They are particularly useful in scientific simulations, linear algebra operations, and other computationally intensive tasks.
2. View key concepts and template parameters
A view is a lightweight object that provides a way to access data in a multi-dimensional array. They behave like pointers, so they can be used in the same way as pointers in (C++).
View<double*, ...> x(...), y(...);
...
parallel_for("DAXPY", N, [=] const int64_t i {
// Views x and y are captured by value (copy)
y(i) = a * x(i) + y(i);
});
Some general aspects of views:
-
They are multi-diemensional arrays of dimension 0 (scalar), 1 (vector), 2 (matrix), etc (to 8). Their number of dimension (named rank) is fixed at compilation.
-
They are rectangular arrays, i.e., all dimensions are fixed at construction, and
-
the sizes of dimensions are set either at compile-time or runtime.
-
The elements can easily be accessed via the operator
()
.
View<double***> data("label", N, M, K); // 3 at runtime, 0 at compilation
View<double**[K]> data("label", N, M); // 2 at runtime, 1 at compilation
View<double[N][M][K]> data("label"); // 3 at compilation
data(i, j, k) = 3.14;
The label of the view is not mandatory, but it is useful for debugging and profiling.
|
3. Usage
First example: build and fill-up a view
- 1D example
-
#include <Kokkos_Core.hpp> #include <iostream> int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); { const size_t N = 100000; // Create a 1D View of doubles Kokkos::View<int*> myView("MyView", N); // Fill the View with data Kokkos::parallel_for(N, KOKKOS_LAMBDA(const int i) { myView(i) = i; }); // Compute the sum of all elements int sum = 0.0; Kokkos::parallel_reduce(N, KOKKOS_LAMBDA(const int i, int& partial_sum) { partial_sum += myView(i); }, sum); std::cout << "Sum: " << sum << std::endl; } Kokkos::finalize(); return 0; }
- 2D example
-
#include <Kokkos_Core.hpp> int main(int argc, char* argv[]) { Kokkos::initialize(argc, argv); { // Define a 2D view of doubles with 10 elements Kokkos::View<double**> view("view", 10, 2); // Initialize the view using parallel_for Kokkos::parallel_for("InitView", 10, KOKKOS_LAMBDA(const int i) { view(i, 0) = i * 1.0; view(i, 1) = i * 2.0; }); // Print the view elements Kokkos::parallel_for("PrintView", 10, KOKKOS_LAMBDA(const int i) { printf("view(%d) = %f\n", i, view(i, 0)); printf("view(%d) = %f\n", i, view(i, 1)); }); } Kokkos::finalize(); return 0; }
Views behave like std::shared_ptr
in the sense that they are reference-counted objects. They are automatically deleted when the last reference to them is removed:
#include <Kokkos_Core.hpp>
#include <iostream>
int main(int argc, char* argv[]) {
int N = 5, K = 10;
Kokkos::initialize(argc, argv);
{
Kokkos::View<double*[5]> a("a", N), b("b", K);
a = b; // a gets deallocated and both a and b are points to the same thing
Kokkos::View<double**> c(b); // copy constructor
std::cout << "Label of c: " << c.label() << std::endl; // The label of c is the same as the label of b
a(0, 2) = 1;
b(0, 2) = 2;
c(0, 2) = 3;
std::cout << "a(0, 2) = " << a(0, 2) << std::endl;
}
Kokkos::finalize();
return 0;
}
Label of c: b
a(0, 2) = 3
4. Properties
Views have several properties that can be queried at runtime:
-
label()
: the label of the view -
rank()
: the number of dimensions of the view -
extent(i)
: the size of thei
-th dimension -
span()
: the total number of elements in the view -
data()
: a pointer to the data -
operator()
: access to the data
5. Exercice
Exercice taken from the Kokkos tutorial: Inner Product, Flat Parallelism an the CPU, with Views.
References
-
Kokkos documentation API kokkos.org/kokkos-core-wiki/API/core/view/view.html
-
Kokkos package description docs.trilinos.org/dev/packages/kokkos/doc/html/classKokkos_1_1View.html