AWS上でPG-STROMにチャレンジ(失敗)

#前提条件確認　＆　環境構築
　
本確認は12/23にPG-STROMのページをもとに実施しました。

http://strom.kaigai.gr.jp/manual.html#overview

PG-Stromの実行にはGPUとCUDAが設定されていることが条件です。
一つ一つ設定するのは面倒なので、すでに設定済みのAMIを使います。今回は、

Deep Learning AMI (Ubuntu)

を選びました。色々選択後、仮想マシンが立ち上がったら、メインのPostgreSQLのバージョンを確認します。
PG-STROMのページによれば、PostgreSQLバージョン9.5以降が必要です


![SnapCrab_NoName_2017-12-23_23-15-10_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/121950/883f7612-7a08-1785-ad9f-81e4bf6d3da5.png)

ということで、リポジトリのPostgreSQLバージョン確認をしましょう。

```ruby:PostgreSQLバージョン確認
$ apt-cache search postgresql | grep server
postgresql-9.5 - object-relational SQL database, version 9.5 server
```

OK.クリアしていますね。インストールしましょう。

```ruby:PostgreSQLインストール
$ sudo apt-get install -y postgresql-9.5
$ sudo apt-get install -y postgresql-server-dev-9.5
```

その他、必要パッケージを確認したところ、最後の2つが足りていません。また、後続で実行するdracutも不足していましたので、この時点でインストールします。

- gcc
- make
- git
- bison
- flex

```ruby:不足パッケージのインストール
$ sudo apt-get install -y bison flex
$ sudo apt-get install -y dracut
```

#カーネル準備

すでにセットアップ済みのAMIを使ったので、不要だと思われますが念のためカーネルソースをダウンロードします。

```ruby:必要パッケージのインストール
$ sudo apt-get -y install libncurses-dev 
$ sudo apt-get -y install build-essential
$ sudo apt-get -y install fakeroot kernel-package
$ sudo apt-get -y install linux-source
```
最後のソースコードインストール時にメッセージが表示されるが、とりあえずデフォルトを選択しました。

![SnapCrab_NoName_2017-12-23_22-10-22_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/121950/add1361f-4387-53e5-19ee-58817580c0b8.png)

一応diffを取ったところ、”do_initrd”の設定はデフォルトが”no”のようなのでその差異が気になりますが、そのまま続けます。

```ruby:kernel-img.confの差分
$ diff /etc/kernel-img.conf /etc/kernel-img.conf.ucf-new
1c1
< # Kernel Image management overrides
---
> # This is a sample /etc/kernel-img.conf file
2a3,32
>
> # If you want the symbolic link (or image, if move_image is set) to be
> # stored elsewhere than / set this variable to the dir where you
> # want the symbolic link.  Please note that this is not a Boolean
> # variable.  This may be of help to loadlin users, who may set both
> # this and move_image. Defaults to /. This can be used in conjunction
> # with all above options except link_in_boot, which would not make
> # sense.  (If both image_dest and link_in_boot are set, link_in_boot
> # overrides).
> image_dest = /
>
> # This option manipulates the build link created by recent kernels. If
> # the link is a dangling link, and if a the corresponding kernel
> # headers appear to have been installed on the system, a new symlink
> # shall be created to point to them.
> #relink_build_link = YES
>
> # If set, the preinst shall silently try to move /lib/modules/version
> # out of the way if it is the same version as the image being
> # installed. Use at your own risk.
> #clobber_modules = NO
>
> # If set, does not prompt to continue after a depmod problem in the
> # postinstall script.  This facilitates automated installs, though it
> # may mask a problem with the kernel image. A diag? nostic is still
> # issued. This is unset be default.
> # ignore_depmod_err = NO
>
> # These setting are for legacy postinst scripts only. newer postinst
> # scripts from the kenrel-package do not use them
4a35,36
> do_initrd=yes
> link_in_boot=no
```

ドライバの衝突を避けるために、nouveauドライバがロードされないようにモジュールのブラックリストに追加します。

```ruby:ドライバのブラックリスト追加
$ sudo vi /etc/modprobe.d/blacklist-nouveau.conf
以下を追加
blacklist nouveau
options nouveau modeset=0
```

カーネルブートイメージを更新するために dracutコマンドを実行するとのこと。
知りませんでしたが、「Red Hat系のディストリビューションで使われているinitrdをカスタマイズするためのツール」とのこと。
initrdは起動時に使用されるルートファイルシステムですね。

```ruby:initrd更新、並びに再起動
$ dracut -f /boot/initramfs-$(uname -r).img $(uname -r)
$ sudo shutdown -r now
```
#PG-stromコンパイル

あとは、PG-STROMをダウンロードしてコンパイルするだけです。

```ruby:PG-STROMダウンロード＆コンパイル
$ git clone https://github.com/pg-strom/devel.git pg_strom
$ cd pg_strom
$ make
```

おっと、エラーメッセージが出ますね。

```ruby:コンパイル失敗
$ make
gcc -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -g -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -I/usr/include/mit-krb5 -fPIC -pie -fno-omit-frame-pointer -fPIC -O0 -g -DPGSTROM_VERSION=\"2.0devel\" -DPGSTROM_VERSION_NUM=20000 -DPG_MIN_VERSION_NUM=90600  -DPGSHAREDIR=\"/usr/share/postgresql/9.5\" -DCUDA_INCLUDE_PATH=\"/usr/local/cuda/include\" -DCUDA_BINARY_PATH=\"/usr/local/cuda/bin\" -DCUDA_LIBRARY_PATH=\"/usr/local/cuda/lib64\" -DCMD_GPUINFO_PATH=\"/usr/lib/postgresql/9.5/bin/gpuinfo\" -I /usr/local/cuda/include -I. -I./ -I/usr/include/postgresql/9.5/server -I/usr/include/postgresql/internal -Wdate-time -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include/tcl8.6  -c -o src/main.o src/main.c
In file included from src/main.c:18:0:
src/pg_strom.h:63:30: fatal error: nodes/extensible.h: No such file or directory
compilation terminated.
<builtin>: recipe for target 'src/main.o' failed
make: *** [src/main.o] Error 1
```

色々調べたところ、PostgreSQL 9.5には、"nodes/extensible.h"が含まれていないようです。PG-STROMのページには9.5以降って書いてあるのになぁ。

ということで、より新しいVersionを取得する方法を調べると、以下に参考になる情報があったのでそのまま実行し、Version 10をインストールしました。

https://qiita.com/eighty8/items/82063beab09ab9e41692


インストール後、再コンパイル。

```ruby:再度コンパイル
$ make
　~中略~
src/ccache.c:944:9: error: too few arguments to function ?WaitLatch?
    ev = WaitLatch(MyLatch,
         ^
In file included from /usr/include/postgresql/10/server/storage/proc.h:19:0,
                 from /usr/include/postgresql/10/server/storage/shm_mq.h:18,
                 from /usr/include/postgresql/10/server/access/parallel.h:20,
                 from /usr/include/postgresql/10/server/executor/nodeCustom.h:15,
                 from src/pg_strom.h:55,
                 from src/ccache.c:18:
/usr/include/postgresql/10/server/storage/latch.h:174:12: note: declared here
 extern int WaitLatch(volatile Latch *latch, int wakeEvents, long timeout,
            ^
src/ccache.c: In function ?ccache_builder_main?:
src/ccache.c:1765:9: error: too few arguments to function ?WaitLatch?
    ev = WaitLatch(MyLatch,
         ^
In file included from /usr/include/postgresql/10/server/storage/proc.h:19:0,
                 from /usr/include/postgresql/10/server/storage/shm_mq.h:18,
                 from /usr/include/postgresql/10/server/access/parallel.h:20,
                 from /usr/include/postgresql/10/server/executor/nodeCustom.h:15,
                 from src/pg_strom.h:55,
                 from src/ccache.c:18:
/usr/include/postgresql/10/server/storage/latch.h:174:12: note: declared here
 extern int WaitLatch(volatile Latch *latch, int wakeEvents, long timeout,
            ^
　~中略~
```

うーん。これは困った。何の処理か、さっぱりわからないけどほかのソースと見比べると確かに引数の数が違う。

定義を探してみる。

```ruby:/usr/include/postgresql/10/server/storage/latch.h
extern int WaitLatch(volatile Latch *latch, int wakeEvents, long timeout,
                  uint32 wait_event_info);
```

どういうタイプ(wait_event_info)が設定できるかというと、どうも以下が選択可能なようだ。

```ruby:/usr/include/postgresql/10/server/pgstat.h
* ----------
 * Wait Classes
 * ----------
 */
#define PG_WAIT_LWLOCK                          0x01000000U
#define PG_WAIT_LOCK                            0x03000000U
#define PG_WAIT_BUFFER_PIN                      0x04000000U
#define PG_WAIT_ACTIVITY                        0x05000000U
#define PG_WAIT_CLIENT                          0x06000000U
#define PG_WAIT_EXTENSION                       0x07000000U
#define PG_WAIT_IPC                                     0x08000000U
#define PG_WAIT_TIMEOUT                         0x09000000U
#define PG_WAIT_IO                                      0x0A000000U
```

もう、ドツボにはまっている感じしかしないが、EXTENSIONだし、PG_WAIT_EXTENSIONだろうとあたりを付けてコードをいじる。

以下、該当箇所

```ruby:src/ccache.c
                        ev = WaitLatch(MyLatch,
                                                   WL_LATCH_SET |
                                                   WL_TIMEOUT |
                                                   WL_POSTMASTER_DEATH,
                                                   60000L
#if PG_VERSION_NUM >= 100000
                                                   ,PG_WAIT_EXTENSION
#endif
                                        );

                        ev = WaitLatch(MyLatch,
                                                   WL_LATCH_SET |
                                                   WL_TIMEOUT |
                                                   WL_POSTMASTER_DEATH,
                                                   timeout
#if PG_VERSION_NUM >= 100000
                                                   ,PG_WAIT_EXTENSION
#endif
                                        );
```

もう一度、makeすると、通った！！

よしよし、インストールしましょう。

```ruby:インストール
$ sudo make install
```

デフォルトで起動しているPostgreSQLのDBインスタンスを停止して、PostgreSQLの初期化をする。

```ruby:DB初期化
$ sudo systemctl stop postgresql
$ sudo mkdir -p /data/postgresql
$ sudo chown postgres /data/postgresql
$ sudo su - postgres
$ export PATH=/usr/lib/postgresql/10/bin:$PATH
$ initdb -D /data/postgresql
```

PG-STROMのマニュアルに従って、Configを変更します。ただし、AWS代をケチったので、メモリサイズに合わせて設定します。

```ruby:/data/postgresql
shared_preload_libraries = '$libdir/pg_strom'
shared_buffers = 2GB
work_mem = 2GB
```

DBを起動する。


```ruby:DB起動とログ
$ sudo su -
$ nvidia-cuda-mps-control -d
$ echo start_server -uid 113 | nvidia-cuda-mps-control
$ su - postgres
$ export PATH=/usr/lib/postgresql/10/bin:$PATH
$ postgres -D /data/postgresql
2017-12-23 15:15:29.897 UTC [23467] LOG:  PG-Strom version 2.0devel built for PostgreSQL 10
2017-12-23 15:15:29.904 UTC [23467] LOG:  PG-Strom: GPU0 Tesla K80 - CC 3.7 is not recommended
2017-12-23 15:15:29.904 UTC [23467] WARNING:  Hint: Kepler/Maxwell architecture does not support demand paging on device's virtual address space, thus, memory allocation overcommit tends to consume very large physical memory immediately. We strongly recommend to upgrade your GPU to Pascal or later.
2017-12-23 15:15:29.904 UTC [23467] LOG:  PG-Strom: GPU0 Tesla K80 (2496 CUDA cores; 823MHz, L2 1536kB), RAM 11.17GB (384bits, 2.39GHz), CC 3.7
2017-12-23 15:15:29.904 UTC [23467] LOG:  NVRTC - CUDA Runtime Compilation vertion 9.0

2017-12-23 15:15:32.642 UTC [23467] LOG:  listening on IPv4 address "127.0.0.1", port 5432
2017-12-23 15:15:32.645 UTC [23467] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2017-12-23 15:15:32.688 UTC [23500] LOG:  database system was shut down at 2017-12-23 15:13:45 UTC
2017-12-23 15:15:32.694 UTC [23467] LOG:  database system is ready to accept connections
2017-12-23 15:15:32.694 UTC [23510] LOG:  ccache-builder0: not assigned to a particular database
2017-12-23 15:15:32.695 UTC [23509] LOG:  ccache-builder1: not assigned to a particular database
```

うぉぉ！！ たちあがったぞーーーー！
引き続き

```ruby:PG-Strom関連のデータベースオブジェクト作成
# psql
postgres=# create database test;
CREATE DATABASE
postgres=# \c test
postgres=#  CREATE EXTENSION pg_strom;
2017-12-23 15:24:11.228 UTC [23558] ERROR:  could not find function "pgstrom_cast_tid_to_int8" in file "/usr/lib/postgresql/10/lib/pg_strom.so"
2017-12-23 15:24:11.228 UTC [23558] STATEMENT:  CREATE EXTENSION pg_strom;
ERROR:  could not find function "pgstrom_cast_tid_to_int8" in file "/usr/lib/postgresql/10/lib/pg_strom.so"
```
oh...

src/gpuscan.cの3108行のif文以下に定義されているのを発見したので、とりあえず有効化

```ruby:有効化した部分

#if 1
/*
 * SQL functions to support reference ctid system column.
 *
 * MEMO: TID type is declared as !typbyval type, although it has 6-bytes
```


再度、PG-STROMをコンパイルしたところ、通った！！（2回目）

```ruby:PG-Strom関連のデータベースオブジェクト作成再チャレンジ
$ su - postgres
$ export PATH=/usr/lib/postgresql/10/bin:$PATH
$ postgres -D /data/postgresql
$ psql
postgres=# \c test
postgres=# CREATE EXTENSION pg_strom;
CREATE EXTENSION
```

今度はエラーが出ない。

早速ベンチマークを走らせてみよう。

```ruby:テスト用DB作成
$ psql
postgres-# create database test;
CREATE DATABASE
```

ベンチマークを実行してみよう

```ruby:ベンチマークの準備実行
$ pgbench -i test
NOTICE:  table "pgbench_history" does not exist, skipping
NOTICE:  table "pgbench_tellers" does not exist, skipping
NOTICE:  table "pgbench_accounts" does not exist, skipping
NOTICE:  table "pgbench_branches" does not exist, skipping
creating tables...
100000 of 100000 tuples (100%) done (elapsed 0.09 s, remaining 0.00 s)
vacuum...
set primary keys...
done.
```

```ruby:ベンチマークの準備実行(PS-STROM無効時)
$ pgbench -c 10 -t 10000 test
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 1
query mode: simple
number of clients: 10
number of threads: 1
number of transactions per client: 10000
number of transactions actually processed: 100000/100000
latency average = 12.016 ms
tps = 832.247832 (including connections establishing)
tps = 832.258200 (excluding connections establishing)
```

```ruby:ベンチマークの準備実行(PS-STROM有効時)
$ pgbench -c 10 -t 10000 test
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 1
query mode: simple
number of clients: 10
number of threads: 1
number of transactions per client: 10000
number of transactions actually processed: 100000/100000
latency average = 12.100 ms
tps = 826.456621 (including connections establishing)
tps = 826.467145 (excluding connections establishing)
```

デフォルトでデータレコードが10万件程度しかないから、コスト計算でpgstromが選択されていないようだ。
ということで、テーブルのレコードを増やして再度試してみる。

```ruby:データ量を増やして再実行
# pgbench -i -s30
# psql
postgres=# explain SELECT sum(bid) from public.pgbench_accounts;
                                                  QUERY PLAN
--------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=52703.40..52703.41 rows=1 width=8)
   ->  Gather  (cost=52656.48..52700.34 rows=408 width=8)
         Workers Planned: 2
         ->  Parallel Custom Scan (GpuPreAgg) on pgbench_accounts  (cost=51656.48..51659.54 rows=204 width=8)
               Reduction: NoGroup
               GPU Projection: pgstrom.psum((bid)::bigint)
               Outer Scan: pgbench_accounts  (cost=1666.67..50875.23 rows=1250000 width=4)
(7 rows)

postgres=# SELECT sum(bid) from public.pgbench_accounts;
2017-12-23 17:10:27.653 UTC [26456] ERROR:  out of managed memory
2017-12-23 17:10:27.653 UTC [26456] STATEMENT:  SELECT sum(bid) from public.pgbench_accounts;
pid=26456: cuCtxDestroy ptr=0x55618b256830
2017-12-23 17:10:27.743 UTC [26351] LOG:  worker process: parallel worker for PID 26443 (PID 26456) exited with exit code 1
server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.
The connection to the server was lost. Attempting reset: 2017-12-23 17:10:27.794 UTC [26351] LOG:  server process (PID 26443) was terminated by signal 7: Bus error
2017-12-23 17:10:27.794 UTC [26351] DETAIL:  Failed process was running: SELECT sum(bid) from public.pgbench_accounts;
2017-12-23 17:10:27.795 UTC [26351] LOG:  terminating any other active server processes
2017-12-23 17:10:27.795 UTC [26391] WARNING:  terminating connection because of crash of another server process
2017-12-23 17:10:27.795 UTC [26391] DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
2017-12-23 17:10:27.795 UTC [26391] HINT:  In a moment you should be able to reconnect to the database and repeat your command.
2017-12-23 17:10:27.799 UTC [26482] FATAL:  the database system is in recovery mode
Failed.
!> 2017-12-23 17:10:28.279 UTC [26351] LOG:  all server processes terminated; reinitializing
2017-12-23 17:10:28.370 UTC [26483] LOG:  database system was interrupted; last known up at 2017-12-23 17:07:16 UTC
2017-12-23 17:10:31.708 UTC [26483] LOG:  database system was not properly shut down; automatic recovery in progress
2017-12-23 17:10:31.712 UTC [26483] LOG:  redo starts at 6/4658C578
2017-12-23 17:10:32.404 UTC [26483] LOG:  invalid record length at 6/5E2DD2C8: wanted 24, got 0
2017-12-23 17:10:32.404 UTC [26483] LOG:  redo done at 6/5E2DD270
2017-12-23 17:10:32.404 UTC [26483] LOG:  last completed transaction was at log time 2017-12-23 17:10:11.652743+00
2017-12-23 17:10:36.721 UTC [26489] LOG:  ccache-builder1: not assigned to a particular database
2017-12-23 17:10:36.722 UTC [26351] LOG:  database system is ready to accept connections
2017-12-23 17:10:36.725 UTC [26490] LOG:  ccache-builder0: not assigned to a particular database

!>
```

うーむ。
色々な設定パターンでためしてみたけど、「out of managed memory」が出て異常終了する。

今回はここまでかなぁ。