トラブルシューティング

問題の切り分け

特定のワークロードを実行した際に何がしかの問題が発生する場合には、それが何に起因するものであるのかを特定するのはトラブルシューティングの第一歩です。

残念ながら、PostgreSQL開発者コミュニティと比べPG-Stromの開発者コミュニティは非常に少ない数の開発者によって支えられています。そのため、ソフトウェアの品質や実績といった観点から、まずPG-Stromが悪さをしていないか疑うのは妥当な判断です。

PG-Stromの全機能を一度に有効化/無効化するにはpg_strom.enabledパラメータを使用する事ができます。 以下の設定を行う事でPG-Stromは無効化され、標準のPostgreSQLと全く同一の状態となります。 それでもなお問題が再現するかどうかは一つの判断材料となるでしょう。

# SET pg_strom.enabled = off;

この他にも、GpuScan、GpuJoin、GpuPreAggといった特定の実行計画のみを無効化するパラメータも定義されています。

これらの詳細はリファレンス/GPUパラメータを参照してください。

クラッシュダンプの採取

システムのクラッシュを引き起こすような重大なトラブルの解析にはクラッシュダンプの採取が欠かせません。 本節では、PostgreSQLとPG-Stromプロセスのクラッシュダンプ(CPU側)、およびPG-StromのGPUカーネルのクラッシュダンプ(GPU側)を取得し、障害発生時のバックトレースを採取するための手段を説明します。

PostgreSQL起動時設定の追加

プロセスのクラッシュ時にクラッシュダンプ(CPU側)を生成するには、PostgreSQLサーバプロセスが生成する事のできる core ファイルのサイズを無制限に変更する必要があります。これはPostgreSQLサーバプロセスを起動するシェル上でulimit -cコマンドを実行して変更する事ができます。

GPUカーネルのエラー時にクラッシュダンプ(GPU側)を生成するには、PostgreSQLサーバプロセスが環境変数CUDA_ENABLE_COREDUMP_ON_EXCEPTION1が設定されている必要があります。

systemdからPostgreSQLを起動する場合、/etc/systemd/system/postgresql-<version>.service.d/以下に設定ファイルを作成し、これらの設定を追加する事ができます。

RPMインストールの場合は、以下の内容のpg_strom.confというファイルが作成されています。

[Service]
LimitNOFILE=65536
LimitCORE=infinity
#Environment=CUDA_ENABLE_COREDUMP_ON_EXCEPTION=1

CUDA9.1においては、通常、GPUカーネルのクラッシュダンプの生成には数分以上の時間を要し、その間、エラーを発生したPostgreSQLセッションの応答は完全に停止してしまします。 そのため、は特定クエリの実行において発生するGPUカーネルに起因するエラーの原因調査を行う場合にだけ、CUDA_ENABLE_COREDUMP_ON_EXCEPTION環境変数を設定する事をお勧めします。 RPMインストールにおけるデフォルト設定は、CUDA_ENABLE_COREDUMP_ON_EXCEPTION環境変数の行をコメントアウトしています。

PostgreSQLサーバプロセスを再起動すると、Max core file sizeがunlimitedに設定されているはずです。

以下のように確認する事ができます。

# cat /proc/<PID of postmaster>/limits
Limit                     Soft Limit           Hard Limit           Units
    :                         :                    :                  :
Max core file size        unlimited            unlimited            bytes
    :                         :                    :                  :

debuginfoパッケージのインストール

クラッシュダンプから意味のある情報を読み取るにはシンボル情報が必要です。

これらは-debuginfoパッケージに格納されており、システムにインストールされているPostgreSQLおよびPG-Stromのパッケージに応じてそれぞれ追加インストールが必要です。

# yum install postgresql10-debuginfo pg_strom-PG10-debuginfo
            :
================================================================================
 Package                  Arch    Version             Repository           Size
================================================================================
Installing:
 pg_strom-PG10-debuginfo  x86_64  1.9-180301.el7      heterodb-debuginfo  766 k
 postgresql10-debuginfo   x86_64  10.3-1PGDG.rhel7    pgdg10              9.7 M

Transaction Summary
================================================================================
Install  2 Packages
            :
Installed:
  pg_strom-PG10-debuginfo.x86_64 0:1.9-180301.el7
  postgresql10-debuginfo.x86_64 0:10.3-1PGDG.rhel7

Complete!

CPU側バックトレースの確認

クラッシュダンプの作成されるパスは、カーネルパラメータkernel.core_patternおよびkernel.core_uses_pidの値によって決まります。 通常はプロセスのカレントディレクトリに作成されますので、systemdからPostgreSQLを起動した場合はデータベースクラスタが構築される/var/lib/pgdataを確認してください。

core.<PID>ファイルが生成されているのを確認したら、gdbを用いてクラッシュに至るバックトレースを確認します。

gdb-cオプションでコアファイルを、-fオプションでクラッシュしたプログラムを指定します。

# gdb -c /var/lib/pgdata/core.134680 -f /usr/pgsql-10/bin/postgres
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-100.el7_4.1
       :
(gdb) bt
#0  0x00007fb942af3903 in __epoll_wait_nocancel () from /lib64/libc.so.6
#1  0x00000000006f71ae in WaitEventSetWaitBlock (nevents=1,
    occurred_events=0x7ffee51e1d70, cur_timeout=-1, set=0x2833298)
    at latch.c:1048
#2  WaitEventSetWait (set=0x2833298, timeout=timeout@entry-1,
    occurred_events=occurred_events@entry0x7ffee51e1d70,
    nevents=nevents@entry1, wait_event_info=wait_event_info@entry100663296)
    at latch.c:1000
#3  0x00000000006210fb in secure_read (port=0x2876120,
    ptr=0xcaa7e0 <PqRecvBuffer>, len=8192) at be-secure.c:166
#4  0x000000000062b6e8 in pq_recvbuf () at pqcomm.c:963
#5  0x000000000062c345 in pq_getbyte () at pqcomm.c:1006
#6  0x0000000000718682 in SocketBackend (inBuf=0x7ffee51e1ef0)
    at postgres.c:328
#7  ReadCommand (inBuf=0x7ffee51e1ef0) at postgres.c:501
#8  PostgresMain (argc=<optimized out>, argv=argv@entry0x287bb68,
    dbname=0x28333f8 "postgres", username=<optimized out>) at postgres.c:4030
#9  0x000000000047adbc in BackendRun (port=0x2876120) at postmaster.c:4405
#10 BackendStartup (port=0x2876120) at postmaster.c:4077
#11 ServerLoop () at postmaster.c:1755
#12 0x00000000006afb7f in PostmasterMain (argc=argc@entry3,
    argv=argv@entry0x2831280) at postmaster.c:1363
#13 0x000000000047bbef in main (argc=3, argv=0x2831280) at main.c:228

gdbのbtコマンドでバックトレースを確認します。 このケースでは、クライアントからのクエリを待っている状態のPostgreSQLバックエンドにSIGSEGVシグナルを送出してクラッシュを引き起こしたため、WaitEventSetWait延長上の__epoll_wait_nocancelでプロセスがクラッシュしている事がわかります。

GPU側バックトレースの確認

GPUカーネルのクラッシュダンプは、(CUDA_COREDUMP_FILE環境変数を用いて明示的に指定しなければ)PostgreSQLサーバプロセスのカレントディレクトリに生成されます。 systemdからPostgreSQLを起動した場合はデータベースクラスタが構築される/var/lib/pgdataを確認してください。以下の名前でGPUカーネルのクラッシュダンプが生成されています。

core_<timestamp>_<hostname>_<PID>.nvcudmp

なお、デフォルト設定ではGPUカーネルのクラッシュダンプにはシンボル情報などのデバッグ情報が含まれていません。この状態では障害解析を行う事はほとんど不可能ですので、以下の設定を行ってPG-Stromが生成するGPUプログラムにデバッグ情報を含めるようにしてください。

ただし、この設定は実行時のパフォーマンスを低下させるため、恒常的な使用は非推奨です。 トラブル解析時にだけ使用するようにしてください。

nvme=# set pg_strom.debug_jit_compile_options = on;
SET

生成されたGPUカーネルのクラッシュダンプを確認するにはcuda-gdbコマンドを使用します。

# /usr/local/cuda/bin/cuda-gdb
NVIDIA (R) CUDA Debugger
9.1 release
Portions Copyright (C) 2007-2017 NVIDIA Corporation
        :
For help, type "help".
Type "apropos word" to search for commands related to "word".
(cuda-gdb)

引数なしでcuda-gdbコマンドを実行し、プロンプト上でtargetコマンドを使用して先ほどのクラッシュダンプを読み込みます。

(cuda-gdb) target cudacore /var/lib/pgdata/core_1521131828_magro.heterodb.com_216238.nvcudmp
Opening GPU coredump: /var/lib/pgdata/core_1521131828_magro.heterodb.com_216238.nvcudmp
[New Thread 216240]

CUDA Exception: Warp Illegal Address
The exception was triggered at PC 0x7ff4dc82f930 (cuda_gpujoin.h:1159)
[Current focus set to CUDA kernel 0, grid 1, block (0,0,0), thread (0,0,0), device 0, sm 0, warp 0, lane 0]
#0  0x00007ff4dc82f938 in _INTERNAL_8_pg_strom_0124cb94::gpujoin_exec_hashjoin (kcxt=0x7ff4f7fffbf8, kgjoin=0x7fe9f4800078,
    kmrels=0x7fe9f8800000, kds_src=0x7fe9f0800030, depth=3, rd_stack=0x7fe9f4806118, wr_stack=0x7fe9f480c118, l_state=0x7ff4f7fffc48,
    matched=0x7ff4f7fffc7c "") at /usr/pgsql-10/share/extension/cuda_gpujoin.h:1159
1159            while (khitem && khitem->hash != hash_value)

この状態でbtコマンドを使用し、問題発生個所へのバックトレースを採取する事ができます。

(cuda-gdb) bt
#0  0x00007ff4dc82f938 in _INTERNAL_8_pg_strom_0124cb94::gpujoin_exec_hashjoin (kcxt=0x7ff4f7fffbf8, kgjoin=0x7fe9f4800078,
    kmrels=0x7fe9f8800000, kds_src=0x7fe9f0800030, depth=3, rd_stack=0x7fe9f4806118, wr_stack=0x7fe9f480c118, l_state=0x7ff4f7fffc48,
    matched=0x7ff4f7fffc7c "") at /usr/pgsql-10/share/extension/cuda_gpujoin.h:1159
#1  0x00007ff4dc9428f0 in gpujoin_main<<<(30,1,1),(256,1,1)>>> (kgjoin=0x7fe9f4800078, kmrels=0x7fe9f8800000, kds_src=0x7fe9f0800030,
    kds_dst=0x7fe9e8800030, kparams_gpreagg=0x0) at /usr/pgsql-10/share/extension/cuda_gpujoin.h:1347

より詳細なcuda-gdbコマンドの利用法はCUDA Toolkit Documentation - CUDA-GDBを参照してください。