Kokkosインストールからhello worldコンパイルまで

Kokkosを仕事で使うかもしれないので一先ず入れてみたというメモ。

# Kokkosとは？

公式：https://github.com/kokkos/kokkos

CPU/GPU共存コードが書けると話題だったり話題だったりしないライブラリです。

1つのライブラリでCPUでもGPUでも速いコードが書けるというのが利点のようです。

そう聞くと有名どころのOpenMPとかOpenACCとかを思い浮かべますが、こちらはCPUだけ、もしくはGPUだけを高速化するものです。

Kokkosは『Performance Portability』を謳っており、ただコンパイルできるだけでなく計算性能も高いままという点で差別化を図っているのかなと理解しています。

# インストール

いわゆるgitでcloneしてmake installするやつですが、`./configure`系とは少し違うようなので、メモしておきます。

``` bash:console
# ディレクトリ構成。絶対パスで指定。
export KOKKOS_SRC=... # git cloneするディレクトリ
export KOKKOS_INSTALL_DIR=... # インストール先（./configure --prefix=...のようなもの）

# gitから持ってくる
git clone https://github.com/kokkos/kokkos $KOKKOS_SRC

# インストールディレクトリ作成
mkdir -p $KOKKOS_INSTALL_DIR
cd $KOKKOS_INSTALL_DIR
$KOKKOS_SRC/generate_makefile.bash --prefix=$KOKKOS_INSTALL_DIR
make kokkoslib
make install # ディレクトリ構成によってはsudo make installかも
```

# パスを通す

cmakeオススメされていますが、筆者はcmakeよくわからん人なので、moduleで対応します。

``` tcl:modulefiles/kokkos
#%Module1.0######################################################################
##
## kokkos modulefile
##
proc ModulesHelp { } {
    puts stderr "\tThis module adds kokkos lib to your environment."
}

module-whatis   "add KOKKOS_PATH environment variable"

set base /path/to/kokkos_install_dir

setenv KOKKOS_PATH $base
```

moduleといっても$KOKKOS_PATHを登録するだけですので、.bashrcにexport追記でも良いです。

``` bash:.bashrc
export KOKKOS_PATH=/path/to/kokkos_install_dir
```

# makefile

いつものように気合で`-I`とか`-L`とか`-l`とかを指定しようと思ったんですが、Kokkosのディレクトリ構造が追いきれなかったのでやめました。

公式 (https://github.com/kokkos/kokkos/wiki/Compiling ) を見ると、
`Makefile.kokkos`をincludeせよとあるので、これに従います。

``` makefile:makefile
SRC := $(wildcard *.cpp)
OBJ := $(SRC:.cpp=.o)

CXX := g++
CXXFLAGS :=

LD := $(CXX)

RUN := a.out

.PHONY: default clean

default: $(RUN)

# include kokkos
ifndef KOKKOS_PATH
	$(error fatal: environment variable KOKKOS_PATH is not defined)
else
include $(KOKKOS_PATH)/Makefile.kokkos
CXXFLAGS += $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS)
CXXDEPENDS += $(KOKKOS_CPP_DEPENDS)
LDFLAGS += $(KOKKOS_LDFLAGS) $(KOKKOS_LIBS)
LDDEPENDS += $(KOKKOS_LINK_DEPENDS)
endif

# make own
$(RUN): $(LDDEPENDS) $(OBJ)
	$(LD) -o $(RUN) $(OBJ) $(LDFLAGS)

.cpp.o: $(CXXDEPENDS)
	$(CXX) -c $< $(CXXFLAGS)

clean:
	$(RM) $(OBJ)
	$(RM) $(RUN)

```

# サンプルコードのコンパイル

サンプルコードはなんでもよいのですが、パス通ってるかのテストをするだけなら公式のtutorialから抜き出してくるのが手っ取り早いです。
hello_world.cpp：https://github.com/kokkos/kokkos/blob/master/example/tutorial/01_hello_world/hello_world.cpp

上記makefileとhello_world.cppを同じディレクトリにおいて、下記を実行します。

``` bash:console
module load kokkos
make
./a.out
```

以下のような表示が出ればOKです。よかったですね。

``` console
Hello World on Kokkos execution space N6Kokkos7ThreadsE
Hello from i = 0
Hello from i = 1
Hello from i = 2
Hello from i = 3
Hello from i = 4
Hello from i = 5
Hello from i = 6
Hello from i = 7
Hello from i = 8
Hello from i = 9
Hello from i = 10
Hello from i = 11
Hello from i = 12
Hello from i = 13
Hello from i = 14
```

# 2020/1/4追記：GPU版Kokkos

GPU版（CUDA enabled）にするには、`make install`のオプション変えてやり直しのようです。

``` bash:console
... # 中略
$KOKKOS_SRC/generate_makefile.bash --prefix=$KOKKOS_INSTALL_DIR --with-cuda --arch=Volta70 # --archは環境に応じて
make kokkoslib
make install
```

makefileは、`CXX := `のところだけ変えればOKです。

``` makefile:makefile
... # 中略
CXX := $(KOKKOS_PATH)/bin/nvcc_wrapper
...
```

`make`して`./a.out`で下記が出力されれば成功です。（nvidia-smiにも出てきてるのでたぶんこれで良いはず……）

``` console
Hello World on Kokkos execution space N6Kokkos4CudaE
... # 以下略
```

# TODO（自分用メモ）

- 拡散方程式かLBMでも書いてCPU/GPUそれぞれで性能取ってみたい