AWS-GPUとスパコンを比較する方法-スパコン用ベンチマークソフトを動かしてみる

前に、[お手元のマシンとスパコンを比較する方法](http://qiita.com/shibacow/items/753e1d46882152e46757)と言うなんともアホっぽい記事を書いた。更に思った。最近は、GPUの性能が上がっており、GPUを使って演算することが流行っている。LINPACKベンチマークを、aws g2インスタンス(CUDA)で動かしてみたらどうだろう？
スパコンは、メモリもストレージもネットワーク性能も段違いに高性能なので、真に受けないように。

ベンチマークの内容を詳しく分かっているわけではないので、間違っているかも知れない。

# AWS g2.2xlargeでLINPACK ベンチマークを動かす。
という訳で、AWSで最もCPUが早そうなマシンを使って、スパコンと性能の比較をしてみる。

今回使用したマシンはこちら

g2.2xlarge

|モデル|vCPU|メモリ|GPU|
|:--:|:--:|:--:|:--:|
|g2.2xlarge|8core|15GB|1|

* 1,536 CUDA コアと 4GB のビデオメモリを搭載した高パフォーマンスの NVIDIA GPU

# LINPACKベンチマーク環境の構築

CUDA実行環境の構築は結構大変だ。

## linpackプログラムの準備

https://devtalk.nvidia.com/default/topic/819284/linpack-benchmark-for-cuda/
こちらを参考。CUDA Registered Developer Programというのに入って、上のリンク
https://developer.nvidia.com/rdp/assets/cuda-accelerated-linpack-linux64
こちらから、```hpl-2.0_FERMI_v15.tgz```を手に入れる。

## インスタンス立ち上げ

nvidiaが用意しているCUDAドライバーが事前に入っている環境を利用する。

AWS marketplaceで「grid」で検索すると出てくる

![gridenv](https://i.gyazo.com/6d42a5420687ccb6c4485d95c49e4960.png)

Amazon Linux AMI with NVIDIA GRID GPU Driverを利用する。

## 初期設定

次のものを入れる

```
sudo yum groupinstall -y "Development Tools"
sudo yum install -y emacs
sudo yum install -y tmux
sudo yum install -y openmpi openmpi-devel
sudo ln -s /opt/nvidia/cuda /usr/local/cuda

```

## INTEL MKLを利用する。

次のページからインテルのMath Libraryを取得する。ついでに利用するシリアルナンバーを用意する。
https://software.intel.com/en-us/qualify-for-free-software

登録すると、シリアルナンバーを送ってくれるのでそれを用意する。

```l_mkl_11.3.0.109.tgz```などが、手に入るので、展開して ```install.sh```を実行する。対話的なやり取りを(その際シリアルナンバーを打ち込む)する。シリアルナンバーを打ち込む以外は、エンターを押せばOK.展開時に、```silent.cfg```が展開されるのでそちらを設定してもよい。やり方は[こちら](http://qiita.com/unnonouno/items/8ab453a1868d77a93679)。

デフォルトで、```/opt/intel```以下にインストールされる。

## LINPACKベンチマークの作成

### 展開

どこでも良いが、```/home/ec2-user/prog```以下に展開する(以下、それを前提とする)。

```shell-session
[ec2-user@ip-10-125-132-16 hpl-2.0_FERMI_v15]$ ls
bin   COPYRIGHT                HISTORY  INSTALL  Make.CUDA   Makefile  Make.top  README  src      TODO    www
BUGS  CUDA_LINPACK_README.txt  include  lib      Make.CUDA~  makes     man       setup   testing  TUNING
```

### 環境設定の作成
~/.bashrcに以下を追加

```
# User specific aliases and functions
export LD_LIBRARY_PATH=/opt/intel/mkl/lib/intel64:/opt/intel/compilers_and_libraries/linux/lib/intel64:/home/ec2-user/prog/hpl-2.0_FERMI_v15/src/cuda:/usr/lib64/openmpi/lib
export PATH=/usr/lib64/openmpi/bin:$PATH
```


```
source ~/.bashrc
```

### Make.CUDAの編集

殆どはMake.CUDAの編集をすれば良い

サンプルは[こちら](https://gist.github.com/shibacow/038542c3ad7464f387da#file-make-cuda)

上を編集して
```
make
```
を実行すれば、```bin/CUDA```に```xhpl```が出来上がる.lddでsoへのパスが通っているか確認してください。```libdgemm.so.1```と```libmpi.so.1```のパスが通ってなかった。


### run_linpackの編集

bin/CUDA以下にあるrun_linpackの編集を行なう

```
#location of HPL
HPL_DIR=/home/ec2-user/prog/hpl-2.0_FERMI_v15
```
と
```
CPU_CORES_PER_GPU=8
```
にする。

## HPL.datの編集

ベンチマークはHPL.datの編集を行なう。そのままでは動かない。PsとQsを1に指定する。
サンプルは[こちら](https://gist.github.com/shibacow/038542c3ad7464f387da#file-hpl-dat)にある

```
2            # of problems sizes (N)
25000 30000 40000 50000 60000 39007 39000  20960 364160 359424 276480 138240 115200 23040 354432 236160 95040 9600 20737 16
129 16128 Ns
4             # of NBs
768 1024 1280 1536 640 768 896 960 1024 1152 1280 384 640 960 768 640 256  960 512 768 1152         NBs
```
上の2は、25000,30000までやるという意味っぽい
4は
768,1024,1280,1536
までやるという意味だ。
最適な場所を探すと、GFlopsの最適値がわかると思う。


# LINPACKベンチ実行

```
mpirun -np 1 -host localhost ./run_linpack
```

 と実行すれば、ベンチマークが走る



# 実行結果

```shell-session

================================================================================
T/V                N    NB     P     Q               Time                 Gflops
--------------------------------------------------------------------------------
WR10L2L2       25000  1024     1     1              70.41              1.480e+02
--------------------------------------------------------------------------------
||Ax-b||_oo/(eps*(||A||_oo*||x||_oo+||b||_oo)*N)=        0.0053278 ...... PASSED
================================================================================
T/V                N    NB     P     Q               Time                 Gflops
--------------------------------------------------------------------------------
WR10L2L2       30000  1024     1     1             117.29              1.535e+02
--------------------------------------------------------------------------------
||Ax-b||_oo/(eps*(||A||_oo*||x||_oo+||b||_oo)*N)=        0.0044912 ...... PASSED
================================================================================

```

長いので省略した。全部の結果は[こちらのgist](https://gist.github.com/shibacow/038542c3ad7464f387da#file-hpl_benchmark_result)にある .


結果を見ると、150GFlops位になりそうだ。

ちなみに、その時にGPUの使用率はこんなもん。nvidea-smiで状態を把握する。

```
$nvidia-smi -q  -d UTILIZATION -l
```


GPUを使っているようだ。

![GPU使用率](https://i.gyazo.com/98ff6124318c78ba4d5f71d90d8ea4c4.png)


## (倍精度の計算は)思ったより速くない

世の中はGPGPU花盛りだ。ドワンゴが、ディープラーニング用のGPUサーバファーム、[紅莉栖](http://dwango.co.jp/pi/ns/2015/0917/index2.html)を作るくらいだし、GPUで数TFlopsくらい行くのかなと思っていた。

しかし、linpackを実行してみると、 150GFlops位と、そこまで速くないという感触だ。理由は、今回使ったAWSのg2インスタンで採用しているGPUは単精度の演算は速いが、倍精度はそこまで速いわけではないと言うことだ。

例えば、wikipediaのFLOPSの項目から今回使用したGPU「kepler」を搭載している**GeForce GTX 680**の[項目](https://ja.wikipedia.org/wiki/FLOPS#NVIDIA)を見てみよう。1536CUDAコアを搭載してる。

理論値で比較すると、単精度では、**3090 GFLOPS** 倍精度で**129 GFLOPS**と大体24倍程度違う。
これは、NVIDAのGPU戦略で、GPUで主に使う3Dグラフィックでは、倍精度(double)ではなく単精度(float)が主に使われ、そのため倍精度にはあまり注力せずその代わり単精度での性能を上げる(数TFLOPS出る)選択をしたということだ。最近にわかに注目を集めているデープラーニングも単精度を使うようだ。

そのため、倍精度でベンチマークを取るLINPACKではそこまで性能が上がらなかったということのようだ。

## 追記、nbodyで計算してみる。


LinpackではGPUのハードウェアの実効性能が出せなかったので、違うプログラムをGPUの実効性能が出せないか調べてみた。

CUDAサンプルのnbodyがflopsを計測出来るそうなので試してみた。
nbodyのプログラムに、

```
NOTE: The CUDA Samples are not meant for performance measurements. Results may vary when GPU Boost is enabled.
```
と書いているように本当の所に計測には不適当であるのであまりまに受けないように。

NBodyはCUDAのサンプルに入っている。場所は
```
/usr/local/cuda-9.0/samples/5_Simulations/nbody
```
になる(うろ覚え)。

倍精度と単精度でFLopsを調べられるので、調査してみた。

理論値では、こちらのページにGRID K520の[スペック](https://qiita.com/yukoba/items/10d0ba3fb1d19a6ab6a5)が載っている。

|モデル|FP32(TFLOPS)|FP64(TFLOPS)|
|:----:|:---------:|:----------:|
|GRID K520|2.458 * 2 |0.096 * 2|

とのことだ。倍精度の演算性能は、大体単精度の24分の一位らしい。

実際に調査してみた。

### 単精度

```
ubuntu@********:/usr/local/cuda/samples/bin/x86_64/linux/release$ ./nbody -benchmark -numbodies=2048000 -device=0

> Single precision floating point simulation
> 1 Devices used for simulation
gpuDeviceInit() CUDA Device [0]: "GRID K520
> Compute 3.0 CUDA device: [GRID K520]
number of bodies = 2048000
2048000 bodies, total time for 10 iterations: 683818.250 ms
= 61.337 billion interactions per second
= 1226.731 single-precision GFLOP/s at 20 flops per interaction
```

単精度で、**1226.731 single-precision GFLOP/s** が出た。

### 倍精度

```
ubuntu@********:/usr/local/cuda/samples/bin/x86_64/linux/release$ ./nbody -fp64 -benchmark -numbodies=2048000 -device=0
gpuDeviceInit() CUDA Device [0]: "GRID K520
> Compute 3.0 CUDA device: [GRID K520]
number of bodies = 2048000
2048000 bodies, total time for 10 iterations: 15422665.000 ms
= 2.720 billion interactions per second
= 81.587 double-precision GFLOP/s at 30 flops per interaction
```

倍精度で、**81.587 double-precision GFLOP/s** が出た。

単精度で、1226GFlops 倍精度で、81GFlopsくらい出た。

単精度は、倍精度の大体15倍位の性能がある。81GFlopsの24倍は、1944GFlopsなので、もう少し性能は出せるのだろう。

## 関連エントリー

[AWSとスパコンを比較する方法-スパコン用ベンチマークソフトを動かしてみる](http://qiita.com/shibacow/items/08490ac51aeb0d131d2e)
[お手元のマシンとスパコンを比較する方法-スパコン用ベンチマークソフトを動かしてみる](http://qiita.com/shibacow/items/753e1d46882152e46757)