This repository was archived by the owner on Apr 15, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathKokkos_PG_Subviews.tex
More file actions
144 lines (126 loc) · 7.03 KB
/
Kokkos_PG_Subviews.tex
File metadata and controls
144 lines (126 loc) · 7.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
\chapter{Subviews}\label{C:Subviews}
After reading this chapter, you should understand the following:
\begin{itemize}
\item A \emph{slice} of a multidimensional array behaves as an array,
and is a view of a structured subset of that array
\item A \emph{subview} is a slice of an existing Kokkos View
\item A subview has the same reference count as its parent View
\item Use C++11 type inference (\lstinline!auto!) to let Kokkos pick the subview's type
\end{itemize}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{A subview is a slice of a View}\label{S:Subviews:Slice}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
In Kokkos, a \emph{subview} is a slice of a View. A \emph{slice} of a
multidimensional array behaves as an array, and is a view of a
structured subset of the original array. ``Behaves as an array''
means that the slice has the same syntax as an array should; one can
access its entries using array indexing notation. ``View'' means that
the slice and the original array point to the same data. That is, the
slice sees changes to the original array, and vice versa.
``Structured subset'' means a cross product of indices along each
dimension, as for example a plane or face of a cube. If the original
array has dimensions $(N_0, N_1, \dots, N_{k-1})$, then a slice views
all entries whose indices are $(\alpha_0, \alpha_1, \dots,
\alpha_{k-1})$, where $\alpha_j$ is an ordered subset of $\{0, 1,
\dots, N_j-1\}$.
Array slices are handy for encapsulation. A slice looks and acts like
an array, so you can pass it into functions that expect an array. For
example, you can write a function for processing boundaries (as
slices) of a structured grid, without needing to tell that function
properties of the entire grid.
Programming languages like Fortran 90, Matlab, and Python have a
special ``colon'' notation for representing slices. For example, if
\texttt{A} is an $M \times N$ array, then
\begin{itemize}
\item \texttt{A(:, :)} represents the whole array,
\item \texttt{A(:, 3)} represents the fourth column (if the language
has zero-based indices, or the third column, if the language has
one-based indices),
\item \texttt{A(4, :)} represents the fifth row,
\item \texttt{A(2:4, 3:7)} represent the sub-array of rows 3-4 and
columns 4--7 (different languages differ on whether the ranges are
inclusive or exclusive of the last index -- Kokkos, like Python, is
exclusive), and
\item \texttt{A(3, 4)} represents a ``zero-dimensional'' slice which
views the entry in the fourth row and fifth column of the matrix.
\end{itemize}
These languages may have more elaborate notation for expressing sets
of indices other than contiguous ranges. These may include
``strided'' subsets of indices, like \texttt{3:2:9} = $\{ 3, 5, 7, 9
\}$, or even arbitrary sets of indices.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{How to take a subview}\label{S:Subviews:How}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
To take a subview of a View, you can use the \texttt{Kokkos::subview}
function. This function is overloaded for all different kinds of
Views and index ranges. For example, the following code is equivalent
to the above example \texttt{A(2:4, 3:7)}:
%%
\begin{lstlisting}
const size_t N0 = ...;
const size_t N1 = ...;
View<double**> A ("A", N0, N1);
auto A_sub = subview (A, make_pair (2, 4), make_pair (3, 7));
\end{lstlisting}
%
In the above example and those that follow in this chapter,
we assume that \lstinline!Kokkos::View!, \lstinline!Kokkos::subview!,
\lstinline!Kokkos::ALL!, \lstinline!std::make_pair!, and \lstinline!std::pair!
have been imported into the working C++ namespace.
The Kokkos equivalent of a contiguous index range \texttt{3:7} is \\
\lstinline!pair<size_t, size_t>(3, 7)!. The Kokkos equivalent of
\texttt{:} (a colon by itself; the whole index range for that
dimension) is \texttt{ALL()} (an instance of the \texttt{ALL} class,
which Kokkos uses only for this purpose). Kokkos does not currently
have equivalents of the strided or arbitrary index sets.
A subview has the same reference count as its parent \lstinline!View!, so the
parent \lstinline!View! won't be deallocated before all subviews go away. Every
subview is also a \lstinline!View!. This means that you may take a subview of a
subview.
Another way of getting a subview is throught the appropriate \lstinline{View} constructor.
\begin{lstlisting}
const size_t N0 = ...;
const size_t N1 = ...;
View<double**> A ("A", N0, N1);
View<double**,LayoutStride> A_sub(A,make_pair(2,4),make_pair(3,7));
\end{lstlisting}
For this usage you must know the layouttype of the subview.
On the positive side, such a direct construction is generally a bit cheaper than
through the \lstinline!Kokkos::subview! function.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{C++11 type deduction}\label{SS:Subviews:How:auto}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Note the use of the C++11 keyword \texttt{auto} in the above example.
A subview may have a different type than its parent View. For
instance, if \lstinline!A! has \lstinline!LayoutRight!,
\lstinline!A_sub! has \lstinline!LayoutStride!. A subview of an
entire row of \lstinline!A! has \lstinline!LayoutRight! as well, but a
subview of an entire column of \lstinline!A! has
\lstinline!LayoutStride!. If you assign the result of the
\texttt{subview} function to the wrong type, Kokkos will emit a
compile-time error. The easiest way to avoid this is to use the C++11
\texttt{auto} keyword to let the compiler deduce the correct type for
you. That said \lstinline!auto! comes with its own cost.
It generally is more expansive for compilers to deal with \lstinline!auto! than with
explicitly known types.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Dimension of a subview}\label{SS:Subviews:How:dim}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Suppose that a View has $k$ dimensions. Then, when calling
\texttt{subview} on that View, you must pass in $k$ arguments. Every
argument that is a single index -- that is, not a pair or
\lstinline!ALL()! -- reduces the dimension of the resulting View by 1.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Degenerate Views}\label{SS:Subviews:How:degen}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Given a View with $k$ dimensions, we call that View \emph{degenerate}
if any of those dimensions is zero. Degenerate Views are useful for
keeping code simple, by avoiding special cases. For example, consider
a MPI (Message-Passing Interface) distributed-memory parallel code
that uses Kokkos to represent local (per-process) data structures.
Suppose that the code distributes a dense matrix (2-D array) in block
row fashion over the MPI processes in a communicator. It could be
that some processes own zero rows of the matrix. This may not be
efficient, since those processes do no work yet participate in
collectives, but it might be possible. In this case, allowing Views
with zero rows would reduce the number of special cases in the code.