GPUが拓く地理情報分析の新たな地平
~GPU版PostGISの実装と検証~
HeteroDB,Inc
Chief Architect & CEO
海外 浩平 <kaigai@heterodb.com>
自己紹介/HeteroDB社について
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平2
会社概要
 商号 ヘテロDB株式会社
 創業 2017年7月4日
 拠点 品川区北品川5-5-15
大崎ブライトコア4F
 事業内容 高速データベース製品の販売
GPU&DB領域の技術コンサルティング
ヘテロジニアスコンピューティング技術を
データベース領域に適用し、
誰もが使いやすく、安価で高速なデータ解析基盤を提供する。
代表者プロフィール
 海外 浩平(KaiGai Kohei)
 OSS開発者コミュニティにおいて、PostgreSQLやLinux kernelの
開発に10年以上従事。主にセキュリティ・FDW等の分野でアッ
プストリームへの貢献。
 IPA未踏ソフト事業において“天才プログラマー”認定 (2006)
 GPU Technology Conference Japan 2017でInception Awardを受賞
PG-Stromとは?
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平3
【機能】
 集計/解析ワークロードの透過的なGPU高速化
 SSD-to-GPU Direct SQLによるPCIeバスレベルの最適化
 Apache Arrow対応によるデータ交換、インポート時間をほぼゼロに
 GPUメモリにデータを常駐。OLTPワークロードとの共存
 PostGIS関数のサポート(一部)。位置情報分析を高速化
PG-Strom: GPUとNVME/PMEMの能力を最大限に引き出し、
テラバイト級のデータを高速処理するPostgreSQL向け拡張モジュール
App
GPU
off-loading
for IoT/Big-Data
for ML/Analytics
➢ SSD-to-GPU Direct SQL
➢ Columnar Store (Arrow_Fdw)
➢ GPU Memory Store (Gstore_Fdw)
➢ Asymmetric Partition-wise
JOIN/GROUP BY
➢ BRIN-Index Support
➢ NVME-over-Fabric Support
➢ Inter-process Data Frame
for Python scripts
➢ Procedural Language for
GPU native code (w/ cuPy)
➢ PostGIS Support
NEW
NEW
GPUとはどんなプロセッサなのか?
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平4
主にHPC分野で実績があり、機械学習用途で爆発的に普及
NVIDIA A100
スーパーコンピュータ
(東京工業大学 TSUBAME3.0) CG(Computer Graphics) 機械学習
数千コアの並列処理ユニット、TB/sに達する広帯域メモリを
ワンチップに実装した半導体デバイス
➔ “同じ計算を大量のデータに並列実行” を最も得意とする
シミュレーション
ターゲット:移動体デバイスのデータ検索
▌移動体デバイス
 高頻度で位置(緯度、経度)の更新がかかる。
 (デバイスID、タイムスタンプ、位置、その他の属性)というデータ構造が多い
▌エリア定義情報
 比較的件数は少なく、ほぼ静的なデータだが、エリア定義情報(多角形)が
非常に複雑な構造を持ち、当たり判定が“重い”
▌用途
 商圏分析、物流分析、広告配信、アラート通知、etc…
位置情報
(緯度、経度)
エリア定義情報
(ポリゴン)
移動体デバイス
エリア内に存在する
移動体デバイスの抽出
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平5
GPU版PostGISについて
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平6
PostGISって?(1/2)
▌概要
 点(Point)、線(LineString)、多角形(Polygon)等のジオメトリ要素、
およびそれらの間の演算を PostgreSQL で実行するための拡張モジュール
 演算の例 … 包含(Contains)、交差(Crosses)、接合(Touch)など
 GiSTインデックスに対応して高速な検索を実現
 2005年に PostGIS 1.0 がリリース。以降、15年にわたって継続的開発。
▌PostGIS関数・演算子の例
 st_distance(geometry g1, geometry g2)
✓ ジオメトリ間の距離を計算する
 st_contains(geometry g1, geometry g2)
✓ ジオメトリ g2 が g1 に包含されていれば真
 st_crosses(geometry g1, geometry g2)
✓ ジオメトリ g2 が g1 を横切っていれば真
…など
© GAIA RESOURCES
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平7
PostGISって?(2/2)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平8
St_Distance(a,b)
ジオメトリ間の距離
St_Crosses(a,b)
ジオメトリの交差判定
St_Contains(a,b)
ジオメトリの包含判定
高速化手法(1/2)- Bounding Box
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平9
▌Bounding Boxとは
 複雑な形状のポリゴンを包摂する最も小さな矩形領域
 (x1,y1) - (x2,y2) で表現できるのでデータ量が少ない
 PostgreSQL / PostGISが geometry 型を保存する時に自動的に生成される。
▌Bounding Boxの効果
 空間関係演算を行う前に、『明らかに接していない』ものを識別できる。
➔ 重なりを含むジオメトリのみ判定を行う事で、計算リソースを節約。
明らかに接していない
共通部分を持つ可能性
高速化手法(2/2)- GiSTインデックス
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平10
▌GiSTインデックスとは
 PostgreSQLのGiST(Generalized Search Tree)は、ツリー構造を持つ
インデックスを一般化したフレームワーク。
 PostGISのGeometry型は、GiST上にR木を実装している。
▌GiSTのR木でできること
 包含(@演算子)や重なり(&&演算子)判定で、インデックスを用いた絞込み
 特に多数のポリゴン×ポイントの重なり判定で計算量が増大しやすい
➔ 事前の絞り込みで計算量を抑え込む
# 国土地理院の市町村形状データをインポート
$ shp2pgsql N03-20_200101.shp | psql gistest
gistest=# ¥d+
List of relations
Schema | Name | Type | Owner | Size |
--------+-------------+----------+--------+------------+
public | geo_japan | table | kaigai | 243 MB |
gistest=# ¥di+
List of relations
Schema | Name | Type | Owner | Table | Size |
--------+--------------------+-------+--------+-----------+---------+
public | geo_japan_pkey | index | kaigai | geo_japan | 2616 kB |
public | geo_japan_geom_idx | index | kaigai | geo_japan | 14 MB |
なぜGPUでSQLを高速化できるのか?
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平11
▌GPUの特徴
 数千演算コアを搭載する計算能力
 1.0TB/sに迫るメモリバンド
➔ 「同じ演算を多量のデータに対して実行する」ために作られたプロセッサ
(e.g 行列演算)
▌SQLワークロードの特性
 「同じ処理を大量の行に対して実行する」
(例:WHERE句の評価、JOINやGROUP BY処理)
SQL処理の中でも、全件スキャンを伴うようなワークロードに強い
GPUに実装された数千コアの
実行ユニットが、個々の行を
並列に評価する。
GPUでPostGIS関数を実行する(1/2)
postgres=# ¥d _gistest
Table "public._gistest"
Column | Type | Collation | Nullable | Default
--------+----------+-----------+----------+--------------------------------------
id | integer | | not null | nextval('_gistest_id_seq'::regclass)
a | geometry | | |
b | geometry | | |
postgres=# explain verbose select * from _gistest where st_contains(a,b);
QUERY PLAN
------------------------------------------------------------------------------------
Custom Scan (GpuScan) on public._gistest (cost=4251.50..4251.50 rows=1 width=196)
Output: id, a, b
GPU Filter: st_contains(_gistest.a, _gistest.b)
GPU Preference: None
Kernel Source: /var/lib/pgdata/pgsql_tmp/pgsql_tmp_strom_21028.4.gpu
Kernel Binary: /var/lib/pgdata/pgsql_tmp/pgsql_tmp_strom_21028.5.ptx
(6 rows)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平12
GPUでPostGIS関数を実行する(2/2)
$ less /var/lib/pgdata/pgsql_tmp/pgsql_tmp_strom_21028.4.gpu
:
#include "cuda_postgis.h"
#include "cuda_gpuscan.h"
DEVICE_FUNCTION(cl_bool)
gpuscan_quals_eval(kern_context *kcxt,
kern_data_store *kds,
ItemPointerData *t_self,
HeapTupleHeaderData *htup)
{
void *addr __attribute__((unused));
pg_geometry_t KVAR_2;
pg_geometry_t KVAR_3;
assert(htup != NULL);
EXTRACT_HEAP_TUPLE_BEGIN(addr, kds, htup);
EXTRACT_HEAP_TUPLE_NEXT(addr);
pg_datum_ref(kcxt,KVAR_2,addr); // pg_geometry_t
EXTRACT_HEAP_TUPLE_NEXT(addr);
pg_datum_ref(kcxt,KVAR_3,addr); // pg_geometry_t
EXTRACT_HEAP_TUPLE_END();
return EVAL(pgfn_st_contains(kcxt, KVAR_2, KVAR_3));
}
:
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平13
列A、列Bから
ジオメトリ型の
データをロード
ロードしたデータで
GPU版 st_contains() 関数を
呼出し
SQLのWHERE句を
評価するために
自動生成された関数
検索処理のパフォーマンス(1/2)
--- GpuScan (GPU版PostGIS) + Gstore_Fdw
=# SELECT count(*) FROM ft
WHERE st_contains('polygon ((10 10,90 10,90 12,12 12,12 88,90 88,90 90,¥
10 90,10 10))’, st_makepoint(x,y));
count
--------
236610
(1 row)
Time: 44.680 ms
--- 通常版PostGIS + PostgreSQLテーブル
=# SET pg_strom.enabled = off;
SET
=# SELECT count(*) FROM tt
WHERE st_contains('polygon ((10 10,90 10,90 12,12 12,12 88,90 88,90 90,¥
10 90,10 10))', st_makepoint(x,y));
count
--------
236610
(1 row)
Time: 622.314 ms
500万個のPointから、
指定領域内の数をカウント
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平14
検索処理のパフォーマンス(2/2)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平15
(100,100)
(0,0)
(90,90)
(90,10)
(90,12)(12,12)
(12,88) (90,88)
(10,90)
(10,10)
この領域内に含まれる
点(Point)を抽出した
テーブル ft および tt には
(0,0)~(100,100)の範囲内に
ランダムに 500万個の点を格納
ポリゴン × 座標の突合
▌ナイーブなポリゴン×座標の突合を行おうとすると、
数万×数千万 = 数兆通りの組合せ、で計算量が爆発。
➔ GPUが数千コアを搭載していても、
計算量が多すぎて焼け石に水。
位置情報
(緯度、経度)
エリア定義情報
(ポリゴン)
移動体デバイス
数百万~数千万件数百~数万件
焼け石(GPU)に ➔
水冷モジュール
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平16
GPUでGiSTインデックス
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平17
GiSTインデックス(R木)の仕組み
▌GiSTインデックス(R木)の仕組み
✓ R1は(R3,R4,R5)を全て包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と、下位ノードへのポインタ
✓ R4は(R11,R12)を全て包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と、下位ノードへのポインタ
✓ R12は対象ジオメトリを包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と ItemPointer を含む。
✓ 各ノード(BLCKSZ)内のエントリを順に評価。マッチしたものを次の階層へすすめる。
✓ 階層ごとに繰り返し評価が発生するので、B-tree並みに速くはできない。
(xmin,ymin)
(xmax,ymax)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平18
検索キー(経度, 緯度)
〇 〇
GiSTインデックス(R木)の仕組み
▌GiSTインデックス(R木)の仕組み
✓ R1は(R3,R4,R5)を全て包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と、下位ノードへのポインタ
✓ R4は(R11,R12)を全て包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と、下位ノードへのポインタ
✓ R12は対象ジオメトリを包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と ItemPointer を含む。
✓ 各ノード(BLCKSZ)内のエントリを順に評価。マッチしたものを次の階層へすすめる。
✓ 階層ごとに繰り返し評価が発生するので、B-tree並みに速くはできない。
(xmin,ymin)
(xmax,ymax)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平19
検索キー(経度, 緯度)
〇 〇
× 〇 ×
GiSTインデックス(R木)の仕組み
▌GiSTインデックス(R木)の仕組み
✓ R1は(R3,R4,R5)を全て包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と、下位ノードへのポインタ
✓ R4は(R11,R12)を全て包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と、下位ノードへのポインタ
✓ R12は対象ジオメトリを包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と ItemPointer を含む。
✓ 各ノード(BLCKSZ)内のエントリを順に評価。マッチしたものを次の階層へすすめる。
✓ 階層ごとに繰り返し評価が発生するので、B-tree並みに速くはできない。
(xmin,ymin)
(xmax,ymax)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平20
検索キー(経度, 緯度)
〇 〇
× 〇 ×
〇×
GiSTインデックス(R木)の仕組み
▌GiSTインデックス(R木)の仕組み
✓ R1は(R3,R4,R5)を全て包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と、下位ノードへのポインタ
✓ R4は(R11,R12)を全て包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と、下位ノードへのポインタ
✓ R12は対象ジオメトリを包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と ItemPointer を含む。
✓ 各ノード(BLCKSZ)内のエントリを順に評価。マッチしたものを次の階層へすすめる。
✓ 階層ごとに繰り返し評価が発生するので、B-tree並みに速くはできない。
(xmin,ymin)
(xmax,ymax)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平21
検索キー(経度, 緯度)
〇 〇
× 〇 ×
〇×
× ×
GPU版GiSTインデックス
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平22
▌仕組み
 多角形(エリア定義情報)を保持するテーブルと、位置情報(緯度経度)を
保持するテーブルとの JOIN にGiSTインデックスを使用できる。
 JOIN処理時、テーブルとインデックスの双方をGPUにロード。
先ずGiSTインデックス上のBounding-Box(矩形領域)を使って荒く絞り込み、
次にテーブル上の多角形(ポリゴン)と「当たり判定」を行う。
 GPUの数千コアをフル稼働してGiSTインデックスを探索する。
単純に並列度が高い分、検索速度も速くなるはず。
➔ が、そうは問屋が卸さなかった。。。
多角形 × 点の重なり判定などを、GpuJoinの一要素として実装
GiST(R木)インデックス
ポリゴン定義
位置データを含む
テーブル
数千スレッドが
並列に
インデックスを
探索
簡易テスト:ランダムな点とSt_Contains(9月末ごろ)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平23
(123.0, 20.0)
(154.2, 46.2)
SELECT n03_001,n03_004,count(*)
FROM geo_japan j, geopoint p
WHERE st_contains(j.geom, st_makepoint(x,y))
AND j.n03_001 like '東京都’
GROUP BY n03_001,n03_004;
ランダムに
生成した座標
1000万個
n03_001 | n03_004 | count
---------+------------+-------
東京都 | あきる野市 | 105
東京都 | 三宅村 | 76
東京都 | 三鷹市 | 17
東京都 | 世田谷区 | 67
東京都 | 中央区 | 12
東京都 | 中野区 | 18
東京都 | 八丈町 | 105
: : :
東京都 | 豊島区 | 14
東京都 | 足立区 | 55
東京都 | 青ヶ島村 | 7
東京都 | 青梅市 | 117
(63 rows)
CPU版:24.892s
GPU版:33.841s(遅い!)
国土地理院からDLした
全国市町村形状データ
前提)GPUスレッドのスケジューリングについて
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平24
 GPUはStreaming Multiprocessor(SM)と呼ばれる単位でコアがグループ化されている。
✓ レジスタやL1キャッシュ(共有メモリ)はSM単位のリソース
 同じSM上で実行されるスレッドの組を Thread Group と呼び、リソースが許せば
最大で 1024 スレッドまで並行で実行する事ができる。
✓ スレッドの切り替えはH/W的に実現され、例えばDRAMアクセス待ちのタイミングで切り替わったり。
 スレッドはWarp (32threads) 単位でスケジューリングされる。同一Warp内のス
レッドは、同時には同じ命令しか実行できない。
✓ 行列計算のように、各コアの負荷が均等になるタイプの処理であればGPUの使用効率は最大化。
✓ スレッド毎に処理時間がバラバラだと、一部のコアが遊んでしまい、処理効率の低下を招く。
GPU Block Diagram
(Tesla V100; 80SMs)
Streaming Multiprocessors
(64CUDA cores/SM)
●●●…●●●
●●●…●●●
●●●…●●●
●●●…●●●
●●●…●●●
●●●…●●●
Thread Group
(1~1024 Threads)
Warp (32 threads)
前提)GpuJoinの並列処理デザイン
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平25
SELECT * FROM A, B
WHERE A.id = B.id;
Table-A
512スレッドが
512行を一度に
取り出し
Table-B
● ● ● ● ● ●
〇 × 〇 × 〇 ×
GpuHashJoin / GpuNestLoop 処理
N = __syncthreads_count(...)
JOIN結果の書き出し
atomic演算を用いて、thread_id=0が
結果バッファにN個分の領域を確保
次のフレームを
取り出して、
以降繰り返し
GpuHashJoin処理
• Hash値の計算
• Hash表の探索
• JOIN条件の評価
GpuNestLoop処理
• JOIN条件の評価
➔スレッド間で大きな
処理時間の差が
つきにくい。
参照
GPUでのインデックス探索の課題
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平26
スレッド間の処理時間の差が大きく、同期待ちを招く
Table-A
● ● ● ● ● ●
参照
Index-A
× × × ×
×
〇
N = __syncthreads_count(...)
参照
R木のLeafノード
まで探索したが
ヒットせず
R木のRootノードを
見ただけで、即、
マッチする要素なし
R木を最後まで
探索し、かつ、
JOINの結合条件を評価
スレッドグループに属する
他のスレッドの完了待ちで
GPUコアが遊んでしまう。
ナイーブなGPU版GiSTインデックス実装(9月末)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平27
GPUの利用効率が上がらず、しばしばCPUより低速だった
● ● ● ● ● ● ●●
各スレッドが1行分のデータをロード
GiST-Index探索用のキー値を抽出する。
GiST-Indexにヒットした?
キー値を用いてGiST-Indexを探索する
JOIN結合条件は真?
JOIN結合条件を評価する
nitems個分のJOIN結果を書き出し
nitems = __syncthreads_count(found);
繰り返し
found=true
found=false
No
No
スレッドグループ(512スレッド)内に、
1個でもGiST-IndexのLeafまで降下して
探索したり、JOIN結合条件の評価まで
行うスレッドがいると、他の511スレッ
ドはその完了を待たされてしまう。
結果として、GPUコアの使用率が全く
向上しないという事になる。
GPUのスレッドスケジューリングを意識した実装(11月頭)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平28
できる限りコアが遊ばないよう、同期ポイントを最小化
● ● ● ● ● ● ●●
各Warp(32スレッド)毎に1行分のデータをロード
GiST-Index探索用のキー値を抽出する。
キー値を用いてGiST-Indexを探索する
GiST-Indexにヒットした?
Atomic演算を用いて中間バッファの領域を確保
GiST-Indexにヒットした行のポインタを記録
中間バッファの使用量が
512個を越えた
__syncthreads()
中間バッファを元に、JOIN結合条件を評価する
JOIN結合条件は真?
No
No
nitems = __syncthreads_count(found)
nitems個分のJOIN結果を書き出し
繰り返し
found=false
found=true
中間バッファの使用量に余裕がある限り、
同期ポイントに達する前にどんどん
Readポインタを進めて GiST-Index の
探索を進める。
➔ 一部のWarp(スレッド)で探索に
時間を要しても、他のWarpは先に
次の行を処理できるため、
GPUコアの使用率を高くできる。
簡易テスト:ランダムな点とSt_Contains(11月初頭)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平29
(123.0, 20.0)
(154.2, 46.2)
SELECT n03_001,n03_004,count(*)
FROM geo_japan j, geopoint p
WHERE st_contains(j.geom, st_makepoint(x,y))
AND j.n03_001 like '東京都’
GROUP BY n03_001,n03_004;
ランダムに
生成した座標
1000万個
n03_001 | n03_004 | count
---------+------------+-------
東京都 | あきる野市 | 105
東京都 | 三宅村 | 76
東京都 | 三鷹市 | 17
東京都 | 世田谷区 | 67
東京都 | 中央区 | 12
東京都 | 中野区 | 18
東京都 | 八丈町 | 105
: : :
東京都 | 豊島区 | 14
東京都 | 足立区 | 55
東京都 | 青ヶ島村 | 7
東京都 | 青梅市 | 117
(63 rows)
CPU版:24.892s
GPU版: 3.733s
国土地理院からDLした
全国市町村形状データ
6倍強の
高速化
つい先日、マヌケな事に気が付く。。。
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平30
GPUコンパイラにデバッグオプションを付けたままコミットしていた…。
なんじゃこりゃー!!
ナンじゃこりゃー!!
$ nvcc --help
:
--device-debug (-G)
Generate debug information for device code.
Turns off all optimizations. Don't use for
profiling; use -lineinfo instead.
:
簡易テスト:ランダムな点とSt_Contains(現在)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平31
(123.0, 20.0)
(154.2, 46.2)
SELECT n03_001,n03_004,count(*)
FROM geo_japan j, geopoint p
WHERE st_contains(j.geom, st_makepoint(x,y))
AND j.n03_001 like '東京都’
GROUP BY n03_001,n03_004;
ランダムに
生成した座標
1000万個
n03_001 | n03_004 | count
---------+------------+-------
東京都 | あきる野市 | 105
東京都 | 三宅村 | 76
東京都 | 三鷹市 | 17
東京都 | 世田谷区 | 67
東京都 | 中央区 | 12
東京都 | 中野区 | 18
東京都 | 八丈町 | 105
: : :
東京都 | 豊島区 | 14
東京都 | 足立区 | 55
東京都 | 青ヶ島村 | 7
東京都 | 青梅市 | 117
(63 rows)
CPU版:24.892s
GPU版: 1.154s
国土地理院からDLした
全国市町村形状データ
21.5倍の
高速化
GPUコードの最適化 ”あり” で再測定
簡易テストの実行計画(CPU版)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平32
postgres=# EXPLAIN (analyze, costs off)
SELECT n03_001,n03_004,count(*)
FROM geo_japan j, geopoint p
WHERE st_contains(j.geom, st_makepoint(x,y))
AND j.n03_001 like '東京都’
GROUP BY n03_001,n03_004;
QUERY PLAN
----------------------------------------------------------------------------------------
Finalize GroupAggregate (actual time=24880.443..24880.682 rows=63 loops=1)
Group Key: j.n03_001, j.n03_004
-> Gather Merge (actual time=24880.430..24892.342 rows=299 loops=1)
Workers Planned: 4
Workers Launched: 4
-> Partial GroupAggregate (actual time=24855.860..24855.949 rows=60 loops=5)
Group Key: j.n03_001, j.n03_004
-> Sort (actual time=24855.846..24855.865 rows=529 loops=5)
Sort Key: j.n03_001, j.n03_004
Sort Method: quicksort Memory: 64kB
-> Nested Loop (actual time=50.124..24854.788 rows=529 loops=5)
-> Parallel Seq Scan on geopoint p (actual time=0.120..258.900
rows=2000000 loops=5)
-> Index Scan using geo_japan_geom_idx on geo_japan j
(actual time=0.012..0.012 rows=0 loops=10000000)
Index Cond: (geom ~ st_makepoint(p.x, p.y))
Filter: (((n03_001)::text ~~ '東京都'::text) AND
st_contains(geom, st_makepoint(p.x, p.y)))
Rows Removed by Filter: 0
Planning Time: 0.160 ms
Execution Time: 24892.586 ms
(22 rows)
簡易テストの実行計画(GPU版)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平33
postgres=# EXPLAIN (analyze, costs off)
SELECT n03_001,n03_004,count(*)
FROM geo_japan j, fgeopoint p
WHERE st_contains(j.geom, st_makepoint(x,y))
AND j.n03_001 like '東京都’
GROUP BY n03_001,n03_004;
QUERY PLAN
-----------------------------------------------------------------------------------------------
GroupAggregate (actual time=1146.188..1146.212 rows=63 loops=1)
Group Key: j.n03_001, j.n03_004
-> Sort (actual time=1146.178..1146.181 rows=63 loops=1)
Sort Key: j.n03_001, j.n03_004
Sort Method: quicksort Memory: 29kB
-> Custom Scan (GpuPreAgg) (actual time=1146.004..1146.013 rows=63 loops=1)
Reduction: Local
Combined GpuJoin: enabled
-> Custom Scan (GpuJoin) on fgeopoint p (never executed)
Outer Scan: fgeopoint p (never executed)
Depth 1: GpuGiSTJoin
HeapSize: 7841.91KB (estimated: 3113.70KB), IndexSize: 13.28MB
IndexFilter: (j.geom ~ st_makepoint(p.x, p.y)) on geo_japan_geom_idx
Rows Fetched by Index: 5065
JoinQuals: st_contains(j.geom, st_makepoint(p.x, p.y))
-> Seq Scan on geo_japan j (actual time=0.136..16.067 rows=6173 loops=1)
Filter: ((n03_001)::text ~~ '東京都'::text)
Rows Removed by Filter: 112726
Planning Time: 0.307 ms
Execution Time: 1154.838 ms
GPU版に固有の最適化
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平34
▌ PostgreSQLの場合、Indexに付随する条件句の評価は、Indexを用いて候補となる行を取り出し
た後にしか行えない。つまり、結果的に無駄となる行フェッチが発生する。
▌ GPU版GiSTインデックスでは、予め「明らかに条件に該当しないエントリ」のLeaf要素を無効
化するため、何度も何度も自明な条件句の評価を行う必要はない。
➔ 『1週間分のデータから直近30分のイベントだけを取り出す』といった特性がある場合に、
通常のGiSTインデックス探索よりも有利に働く。
GiST Rootブロック
IndexTupleData
IndexTupleData
IndexTupleData
IndexTupleData
IndexTupleData
IndexTupleData
IndexTupleData
notinuse
EXPLAIN
SELECT n03_001,n03_004,count(*)
FROM geo_japan j, geopoint p
WHERE st_contains(j.geom, st_makepoint(x,y))
AND j.n03_001 like '東京都’
GROUP BY n03_001,n03_004;
QUERY PLAN
------------------------------------------------------
GroupAggregate
Group Key: j.n03_001, j.n03_004
-> Sort
Sort Key: j.n03_001, j.n03_004
-> Nested Loop
-> Seq Scan on geopoint p
-> Index Scan using geo_japan_geom_idx on geo_japan j
Index Cond: (geom ~ st_makepoint(p.x, p.y))
Filter: (((n03_001)::text ~~ '東京都') AND
st_contains(geom, st_makepoint(p.x, p.y)))
(9 rows)あらかじめ、明らかに条件に該当しないエントリ
(この場合は ‘東京都’ 以外)を無効化
小噺)ちょっと感動した話
postgres=# EXPLAIN SELECT n03_001,n03_004,count(*)
FROM geo_japan j, geopoint p
WHERE st_dwithin(j.geom, st_makepoint(x,y), 0.004)
AND j.n03_001 like '東京都’
GROUP BY n03_001,n03_004;
QUERY PLAN
-----------------------------------------------------------------------------------------------------
HashAggregate (cost=1936845.15..1936893.73 rows=4858 width=29)
Group Key: j.n03_001, j.n03_004
-> Custom Scan (GpuJoin) on geopoint p (cost=159401.97..1480539.90 rows=60840700 width=21)
Outer Scan: geopoint p (cost=0.00..163696.15 rows=10000115 width=16)
Depth 1: GpuGiSTJoin(nrows 10000115...60840700)
HeapSize: 3113.70KB
IndexFilter: (j.geom && st_expand(st_makepoint(p.x, p.y),
'0.004'::double precision)) on geo_japan_geom_idx
JoinQuals: st_dwithin(j.geom, st_makepoint(p.x, p.y), '0.004'::double precision)
GPU Preference: GPU0 (Tesla V100-PCIE-16GB)
-> Seq Scan on geo_japan j (cost=0.00..8928.24 rows=6084 width=1868)
Filter: ((n03_001)::text ~~ '東京都'::text)
(11 rows)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平35
st_makepoint(p.x, p.y)
st_expand()
✓ 引数1(点)を上下左右に引数2(実数)だけ拡張
した矩形領域を返す。
➔ これとGiSTインデックスのBounding-Boxが
共通領域を持てば、st_dwithin()が真となる
可能性がある。
0.004
0.004
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平36
GPU版PostGIS(GiSTインデックス)を用いた
実ワークロードの性能評価
位置データアプリケーションを用いた評価
ユーザ毎・都道府県ごとに、訪問した
(近傍のチェックイン履歴のある)駅の
割合を導出し、都道府県ごとの
駅制覇マップを作成する。
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平37
検索における工夫
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平38
近傍に位置する駅は両方訪問した事にする。
大阪梅田
東京メトロ銀座線京橋駅と、
都営浅草線宝町駅
西武鉄道 西武秩父駅と、
秩父鉄道 御花畑駅
JR武蔵野線 北朝霞駅と、
東武東上線 朝霞台駅
集計クエリの構造
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平39
TRUNCATE train_visit_summary;
INSERT INTO train_visit_summary (
-- 集計結果を集計テーブルに保持しておき、Web画面の表示時に
-- 未訪問の都道府県も含めて出力する。
WITH cte_station_visit AS (
SELECT DISTINCT s.pref_cd, s.station_cd, u.uid
-- “訪問”した駅コード、その都道府県コード、ユーザIDを
-- 重複なしで取り出す
FROM train_station_list s, train_user_station u
-- 駅の位置と、ユーザのチェックイン情報を突合する
WHERE st_dwithin(st_makepoint(s.lon, s.lat),
st_makepoint(u.lon, u.lat), 0.004)
-- 駅の位置とユーザのチェックイン情報の位置が一定範囲内に存在すれば、
-- その駅を訪問したものとみなす。
AND s.station_cd = s.station_g_cd
)
SELECT v.pref_cd, v.uid, count(*)
FROM cte_station_visit v
GROUP BY 1, 2
);
(ユーザ, 都道府県)ごとに、訪問した駅の数を集計
実行結果(CPU)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平40
QUERY PLAN
------------------------------------------------------------------------------------------
Insert on train_visit_summary (actual time=564337.937..564337.937 rows=0 loops=1)
-> Subquery Scan on "*SELECT*" (actual time=561347.255..564263.657 rows=222985 loops=1)
-> GroupAggregate (actual time=561347.253..564245.853 rows=222985 loops=1)
Group Key: v.pref_cd, v.uid
-> Sort (actual time=561347.227..562318.377 rows=18041063 loops=1)
Sort Key: v.pref_cd, v.uid
Sort Method: quicksort Memory: 1632107kB
-> Subquery Scan on v (actual time=534684.752..543837.130 rows=18041063 loops=1)
-> Group (actual time=534684.748..542789.954 rows=18041063 loops=1)
Group Key: s.pref_cd, s.station_cd, u.uid
-> Sort (actual time=534684.737..538315.419 rows=31188357 loops=1)
Sort Key: s.pref_cd, s.station_cd, u.uid
Sort Method: quicksort Memory: 2248387kB
-> Nested Loop (actual time=0.072..485222.366 rows=31188357 loops=1)
-> Seq Scan on train_user_station u
(actual time=0.010..2436.186 rows=23969240 loops=1)
-> Index Scan using train_station_list_st_makepoint_idx on train_station_list s
(actual time=0.018..0.019 rows=1 loops=23969240)
Index Cond: (st_makepoint(lon, lat) &&
st_expand(st_makepoint(u.lon, u.lat), 0.004))
Filter: ((station_cd = station_g_cd) AND
st_dwithin(st_makepoint(lon, lat),
st_makepoint(u.lon, u.lat), 0.004))
Rows Removed by Filter: 1
Planning Time: 0.241 ms
Execution Time: 564369.525 ms
(21 rows)
近傍探索に概ね485秒を要している。
実行結果(GPU)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平41
QUERY PLAN
------------------------------------------------------------------------------------------
Insert on train_visit_summary (actual time=20520.911..20520.911 rows=0 loops=1)
-> Subquery Scan on "*SELECT*" (actual time=19860.629..19919.661 rows=222985 loops=1)
-> HashAggregate (actual time=19860.624..19904.020 rows=222985 loops=1)
Group Key: s.pref_cd, u.uid
-> HashAggregate (actual time=12452.580..16119.425 rows=18041063 loops=1)
Group Key: s.pref_cd, s.station_cd, u.uid
-> Custom Scan (GpuJoin) on train_user_station u
(actual time=366.592..4580.699 rows=31188357 loops=1)
Outer Scan: train_user_station u
(actual time=44.375..1964.682 rows=23969240 loops=1)
Depth 1: GpuGiSTJoin
HeapSize: 992.73KB (estimated: 13.12KB), IndexSize: 928.62KB
IndexFilter: (st_makepoint(s.lon, s.lat) &&
st_expand(st_makepoint(u.lon, u.lat), 0.004))
on train_station_list_st_makepoint_idx
Rows Fetched by Index: 33137684
JoinQuals: st_dwithin(st_makepoint(s.lon, s.lat),
st_makepoint(u.lon, u.lat), 0.004)
-> Seq Scan on train_station_list s (actual time=0.023..2.489
rows=12542 loops=1)
Filter: (station_cd = station_g_cd)
Rows Removed by Filter: 2534
Planning Time: 0.327 ms
Execution Time: 20578.966 ms
(18 rows)
同じ箇所の実行時間は 4.580 秒
後工程の重複排除処理で時間を要している。
実行結果
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平42
まとめ(1/2)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平43
▌GPU版PostGIS
 PostGIS関数をGPU上で並列実行するための機能拡張。
 GiSTインデックスにも対応し、H/Wの特性を活かしたインデックス探索を実装。
 位置ゲームの実データを用いた評価で、近傍探索ワークロードを(実質的に)
100倍以上高速化 ➔ ハマれば非常に効果的。
▌想定用途
 携帯電話や自動車の“位置情報“と、エリア定義情報との突合。
 リアルタイムの広告配信やプッシュ型イベント通知など。
 これら位置情報分析を含む “計算ヘビー“ なワークロードを
手元のワークステーションやクラウドで手軽に実行できるように。
▌リソース
 GitHub: https://github.com/heterodb/pg-strom
 Document: http://heterodb.github.io/pg-strom/ja/
 Contact: Tw: @kkaigai / ✉ kaigai@heterodb.com
まとめ(2/2)
OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平44
▌リソース
 GitHub: https://github.com/heterodb/pg-strom
 Document: http://heterodb.github.io/pg-strom/ja/
 Contact: Tw: @kkaigai / ✉ kaigai@heterodb.com
PG-Stromプロジェクトは皆さんのご参加を歓迎します
20201128_OSC_Fukuoka_Online_GPUPostGIS

20201128_OSC_Fukuoka_Online_GPUPostGIS

  • 1.
  • 2.
    自己紹介/HeteroDB社について OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平2 会社概要  商号 ヘテロDB株式会社  創業 2017年7月4日  拠点 品川区北品川5-5-15 大崎ブライトコア4F  事業内容 高速データベース製品の販売 GPU&DB領域の技術コンサルティング ヘテロジニアスコンピューティング技術を データベース領域に適用し、 誰もが使いやすく、安価で高速なデータ解析基盤を提供する。 代表者プロフィール  海外 浩平(KaiGai Kohei)  OSS開発者コミュニティにおいて、PostgreSQLやLinux kernelの 開発に10年以上従事。主にセキュリティ・FDW等の分野でアッ プストリームへの貢献。  IPA未踏ソフト事業において“天才プログラマー”認定 (2006)  GPU Technology Conference Japan 2017でInception Awardを受賞
  • 3.
    PG-Stromとは? OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平3 【機能】  集計/解析ワークロードの透過的なGPU高速化  SSD-to-GPU Direct SQLによるPCIeバスレベルの最適化  Apache Arrow対応によるデータ交換、インポート時間をほぼゼロに  GPUメモリにデータを常駐。OLTPワークロードとの共存  PostGIS関数のサポート(一部)。位置情報分析を高速化 PG-Strom: GPUとNVME/PMEMの能力を最大限に引き出し、 テラバイト級のデータを高速処理するPostgreSQL向け拡張モジュール App GPU off-loading for IoT/Big-Data for ML/Analytics ➢ SSD-to-GPU Direct SQL ➢ Columnar Store (Arrow_Fdw) ➢ GPU Memory Store (Gstore_Fdw) ➢ Asymmetric Partition-wise JOIN/GROUP BY ➢ BRIN-Index Support ➢ NVME-over-Fabric Support ➢ Inter-process Data Frame for Python scripts ➢ Procedural Language for GPU native code (w/ cuPy) ➢ PostGIS Support NEW NEW
  • 4.
    GPUとはどんなプロセッサなのか? OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平4 主にHPC分野で実績があり、機械学習用途で爆発的に普及 NVIDIA A100 スーパーコンピュータ (東京工業大学 TSUBAME3.0) CG(Computer Graphics) 機械学習 数千コアの並列処理ユニット、TB/sに達する広帯域メモリを ワンチップに実装した半導体デバイス ➔ “同じ計算を大量のデータに並列実行” を最も得意とする シミュレーション
  • 5.
    ターゲット:移動体デバイスのデータ検索 ▌移動体デバイス  高頻度で位置(緯度、経度)の更新がかかる。  (デバイスID、タイムスタンプ、位置、その他の属性)というデータ構造が多い ▌エリア定義情報 比較的件数は少なく、ほぼ静的なデータだが、エリア定義情報(多角形)が 非常に複雑な構造を持ち、当たり判定が“重い” ▌用途  商圏分析、物流分析、広告配信、アラート通知、etc… 位置情報 (緯度、経度) エリア定義情報 (ポリゴン) 移動体デバイス エリア内に存在する 移動体デバイスの抽出 OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平5
  • 6.
    GPU版PostGISについて OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平6
  • 7.
    PostGISって?(1/2) ▌概要  点(Point)、線(LineString)、多角形(Polygon)等のジオメトリ要素、 およびそれらの間の演算を PostgreSQLで実行するための拡張モジュール  演算の例 … 包含(Contains)、交差(Crosses)、接合(Touch)など  GiSTインデックスに対応して高速な検索を実現  2005年に PostGIS 1.0 がリリース。以降、15年にわたって継続的開発。 ▌PostGIS関数・演算子の例  st_distance(geometry g1, geometry g2) ✓ ジオメトリ間の距離を計算する  st_contains(geometry g1, geometry g2) ✓ ジオメトリ g2 が g1 に包含されていれば真  st_crosses(geometry g1, geometry g2) ✓ ジオメトリ g2 が g1 を横切っていれば真 …など © GAIA RESOURCES OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平7
  • 8.
    PostGISって?(2/2) OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平8 St_Distance(a,b) ジオメトリ間の距離 St_Crosses(a,b) ジオメトリの交差判定 St_Contains(a,b) ジオメトリの包含判定
  • 9.
    高速化手法(1/2)- Bounding Box OSCFukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平9 ▌Bounding Boxとは  複雑な形状のポリゴンを包摂する最も小さな矩形領域  (x1,y1) - (x2,y2) で表現できるのでデータ量が少ない  PostgreSQL / PostGISが geometry 型を保存する時に自動的に生成される。 ▌Bounding Boxの効果  空間関係演算を行う前に、『明らかに接していない』ものを識別できる。 ➔ 重なりを含むジオメトリのみ判定を行う事で、計算リソースを節約。 明らかに接していない 共通部分を持つ可能性
  • 10.
    高速化手法(2/2)- GiSTインデックス OSC Fukuoka/Online2020 - GPUが拓く地理情報分析の新たな地平10 ▌GiSTインデックスとは  PostgreSQLのGiST(Generalized Search Tree)は、ツリー構造を持つ インデックスを一般化したフレームワーク。  PostGISのGeometry型は、GiST上にR木を実装している。 ▌GiSTのR木でできること  包含(@演算子)や重なり(&&演算子)判定で、インデックスを用いた絞込み  特に多数のポリゴン×ポイントの重なり判定で計算量が増大しやすい ➔ 事前の絞り込みで計算量を抑え込む # 国土地理院の市町村形状データをインポート $ shp2pgsql N03-20_200101.shp | psql gistest gistest=# ¥d+ List of relations Schema | Name | Type | Owner | Size | --------+-------------+----------+--------+------------+ public | geo_japan | table | kaigai | 243 MB | gistest=# ¥di+ List of relations Schema | Name | Type | Owner | Table | Size | --------+--------------------+-------+--------+-----------+---------+ public | geo_japan_pkey | index | kaigai | geo_japan | 2616 kB | public | geo_japan_geom_idx | index | kaigai | geo_japan | 14 MB |
  • 11.
    なぜGPUでSQLを高速化できるのか? OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平11 ▌GPUの特徴  数千演算コアを搭載する計算能力  1.0TB/sに迫るメモリバンド ➔ 「同じ演算を多量のデータに対して実行する」ために作られたプロセッサ (e.g 行列演算) ▌SQLワークロードの特性  「同じ処理を大量の行に対して実行する」 (例:WHERE句の評価、JOINやGROUP BY処理) SQL処理の中でも、全件スキャンを伴うようなワークロードに強い GPUに実装された数千コアの 実行ユニットが、個々の行を 並列に評価する。
  • 12.
    GPUでPostGIS関数を実行する(1/2) postgres=# ¥d _gistest Table"public._gistest" Column | Type | Collation | Nullable | Default --------+----------+-----------+----------+-------------------------------------- id | integer | | not null | nextval('_gistest_id_seq'::regclass) a | geometry | | | b | geometry | | | postgres=# explain verbose select * from _gistest where st_contains(a,b); QUERY PLAN ------------------------------------------------------------------------------------ Custom Scan (GpuScan) on public._gistest (cost=4251.50..4251.50 rows=1 width=196) Output: id, a, b GPU Filter: st_contains(_gistest.a, _gistest.b) GPU Preference: None Kernel Source: /var/lib/pgdata/pgsql_tmp/pgsql_tmp_strom_21028.4.gpu Kernel Binary: /var/lib/pgdata/pgsql_tmp/pgsql_tmp_strom_21028.5.ptx (6 rows) OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平12
  • 13.
    GPUでPostGIS関数を実行する(2/2) $ less /var/lib/pgdata/pgsql_tmp/pgsql_tmp_strom_21028.4.gpu : #include"cuda_postgis.h" #include "cuda_gpuscan.h" DEVICE_FUNCTION(cl_bool) gpuscan_quals_eval(kern_context *kcxt, kern_data_store *kds, ItemPointerData *t_self, HeapTupleHeaderData *htup) { void *addr __attribute__((unused)); pg_geometry_t KVAR_2; pg_geometry_t KVAR_3; assert(htup != NULL); EXTRACT_HEAP_TUPLE_BEGIN(addr, kds, htup); EXTRACT_HEAP_TUPLE_NEXT(addr); pg_datum_ref(kcxt,KVAR_2,addr); // pg_geometry_t EXTRACT_HEAP_TUPLE_NEXT(addr); pg_datum_ref(kcxt,KVAR_3,addr); // pg_geometry_t EXTRACT_HEAP_TUPLE_END(); return EVAL(pgfn_st_contains(kcxt, KVAR_2, KVAR_3)); } : OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平13 列A、列Bから ジオメトリ型の データをロード ロードしたデータで GPU版 st_contains() 関数を 呼出し SQLのWHERE句を 評価するために 自動生成された関数
  • 14.
    検索処理のパフォーマンス(1/2) --- GpuScan (GPU版PostGIS)+ Gstore_Fdw =# SELECT count(*) FROM ft WHERE st_contains('polygon ((10 10,90 10,90 12,12 12,12 88,90 88,90 90,¥ 10 90,10 10))’, st_makepoint(x,y)); count -------- 236610 (1 row) Time: 44.680 ms --- 通常版PostGIS + PostgreSQLテーブル =# SET pg_strom.enabled = off; SET =# SELECT count(*) FROM tt WHERE st_contains('polygon ((10 10,90 10,90 12,12 12,12 88,90 88,90 90,¥ 10 90,10 10))', st_makepoint(x,y)); count -------- 236610 (1 row) Time: 622.314 ms 500万個のPointから、 指定領域内の数をカウント OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平14
  • 15.
    検索処理のパフォーマンス(2/2) OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平15 (100,100) (0,0) (90,90) (90,10) (90,12)(12,12) (12,88) (90,88) (10,90) (10,10) この領域内に含まれる 点(Point)を抽出した テーブル ft および tt には (0,0)~(100,100)の範囲内に ランダムに 500万個の点を格納
  • 16.
    ポリゴン × 座標の突合 ▌ナイーブなポリゴン×座標の突合を行おうとすると、 数万×数千万= 数兆通りの組合せ、で計算量が爆発。 ➔ GPUが数千コアを搭載していても、 計算量が多すぎて焼け石に水。 位置情報 (緯度、経度) エリア定義情報 (ポリゴン) 移動体デバイス 数百万~数千万件数百~数万件 焼け石(GPU)に ➔ 水冷モジュール OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平16
  • 17.
    GPUでGiSTインデックス OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平17
  • 18.
    GiSTインデックス(R木)の仕組み ▌GiSTインデックス(R木)の仕組み ✓ R1は(R3,R4,R5)を全て包含する矩形領域の(Xmin,Ymin) –(Xmax,Ymax)と、下位ノードへのポインタ ✓ R4は(R11,R12)を全て包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と、下位ノードへのポインタ ✓ R12は対象ジオメトリを包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と ItemPointer を含む。 ✓ 各ノード(BLCKSZ)内のエントリを順に評価。マッチしたものを次の階層へすすめる。 ✓ 階層ごとに繰り返し評価が発生するので、B-tree並みに速くはできない。 (xmin,ymin) (xmax,ymax) OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平18 検索キー(経度, 緯度) 〇 〇
  • 19.
    GiSTインデックス(R木)の仕組み ▌GiSTインデックス(R木)の仕組み ✓ R1は(R3,R4,R5)を全て包含する矩形領域の(Xmin,Ymin) –(Xmax,Ymax)と、下位ノードへのポインタ ✓ R4は(R11,R12)を全て包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と、下位ノードへのポインタ ✓ R12は対象ジオメトリを包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と ItemPointer を含む。 ✓ 各ノード(BLCKSZ)内のエントリを順に評価。マッチしたものを次の階層へすすめる。 ✓ 階層ごとに繰り返し評価が発生するので、B-tree並みに速くはできない。 (xmin,ymin) (xmax,ymax) OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平19 検索キー(経度, 緯度) 〇 〇 × 〇 ×
  • 20.
    GiSTインデックス(R木)の仕組み ▌GiSTインデックス(R木)の仕組み ✓ R1は(R3,R4,R5)を全て包含する矩形領域の(Xmin,Ymin) –(Xmax,Ymax)と、下位ノードへのポインタ ✓ R4は(R11,R12)を全て包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と、下位ノードへのポインタ ✓ R12は対象ジオメトリを包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と ItemPointer を含む。 ✓ 各ノード(BLCKSZ)内のエントリを順に評価。マッチしたものを次の階層へすすめる。 ✓ 階層ごとに繰り返し評価が発生するので、B-tree並みに速くはできない。 (xmin,ymin) (xmax,ymax) OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平20 検索キー(経度, 緯度) 〇 〇 × 〇 × 〇×
  • 21.
    GiSTインデックス(R木)の仕組み ▌GiSTインデックス(R木)の仕組み ✓ R1は(R3,R4,R5)を全て包含する矩形領域の(Xmin,Ymin) –(Xmax,Ymax)と、下位ノードへのポインタ ✓ R4は(R11,R12)を全て包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と、下位ノードへのポインタ ✓ R12は対象ジオメトリを包含する矩形領域の(Xmin,Ymin) – (Xmax,Ymax)と ItemPointer を含む。 ✓ 各ノード(BLCKSZ)内のエントリを順に評価。マッチしたものを次の階層へすすめる。 ✓ 階層ごとに繰り返し評価が発生するので、B-tree並みに速くはできない。 (xmin,ymin) (xmax,ymax) OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平21 検索キー(経度, 緯度) 〇 〇 × 〇 × 〇× × ×
  • 22.
    GPU版GiSTインデックス OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平22 ▌仕組み  多角形(エリア定義情報)を保持するテーブルと、位置情報(緯度経度)を 保持するテーブルとの JOIN にGiSTインデックスを使用できる。  JOIN処理時、テーブルとインデックスの双方をGPUにロード。 先ずGiSTインデックス上のBounding-Box(矩形領域)を使って荒く絞り込み、 次にテーブル上の多角形(ポリゴン)と「当たり判定」を行う。  GPUの数千コアをフル稼働してGiSTインデックスを探索する。 単純に並列度が高い分、検索速度も速くなるはず。 ➔ が、そうは問屋が卸さなかった。。。 多角形 × 点の重なり判定などを、GpuJoinの一要素として実装 GiST(R木)インデックス ポリゴン定義 位置データを含む テーブル 数千スレッドが 並列に インデックスを 探索
  • 23.
    簡易テスト:ランダムな点とSt_Contains(9月末ごろ) OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平23 (123.0, 20.0) (154.2, 46.2) SELECT n03_001,n03_004,count(*) FROM geo_japan j, geopoint p WHERE st_contains(j.geom, st_makepoint(x,y)) AND j.n03_001 like '東京都’ GROUP BY n03_001,n03_004; ランダムに 生成した座標 1000万個 n03_001 | n03_004 | count ---------+------------+------- 東京都 | あきる野市 | 105 東京都 | 三宅村 | 76 東京都 | 三鷹市 | 17 東京都 | 世田谷区 | 67 東京都 | 中央区 | 12 東京都 | 中野区 | 18 東京都 | 八丈町 | 105 : : : 東京都 | 豊島区 | 14 東京都 | 足立区 | 55 東京都 | 青ヶ島村 | 7 東京都 | 青梅市 | 117 (63 rows) CPU版:24.892s GPU版:33.841s(遅い!) 国土地理院からDLした 全国市町村形状データ
  • 24.
    前提)GPUスレッドのスケジューリングについて OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平24  GPUはStreaming Multiprocessor(SM)と呼ばれる単位でコアがグループ化されている。 ✓ レジスタやL1キャッシュ(共有メモリ)はSM単位のリソース  同じSM上で実行されるスレッドの組を Thread Group と呼び、リソースが許せば 最大で 1024 スレッドまで並行で実行する事ができる。 ✓ スレッドの切り替えはH/W的に実現され、例えばDRAMアクセス待ちのタイミングで切り替わったり。  スレッドはWarp (32threads) 単位でスケジューリングされる。同一Warp内のス レッドは、同時には同じ命令しか実行できない。 ✓ 行列計算のように、各コアの負荷が均等になるタイプの処理であればGPUの使用効率は最大化。 ✓ スレッド毎に処理時間がバラバラだと、一部のコアが遊んでしまい、処理効率の低下を招く。 GPU Block Diagram (Tesla V100; 80SMs) Streaming Multiprocessors (64CUDA cores/SM) ●●●…●●● ●●●…●●● ●●●…●●● ●●●…●●● ●●●…●●● ●●●…●●● Thread Group (1~1024 Threads) Warp (32 threads)
  • 25.
    前提)GpuJoinの並列処理デザイン OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平25 SELECT * FROM A, B WHERE A.id = B.id; Table-A 512スレッドが 512行を一度に 取り出し Table-B ● ● ● ● ● ● 〇 × 〇 × 〇 × GpuHashJoin / GpuNestLoop 処理 N = __syncthreads_count(...) JOIN結果の書き出し atomic演算を用いて、thread_id=0が 結果バッファにN個分の領域を確保 次のフレームを 取り出して、 以降繰り返し GpuHashJoin処理 • Hash値の計算 • Hash表の探索 • JOIN条件の評価 GpuNestLoop処理 • JOIN条件の評価 ➔スレッド間で大きな 処理時間の差が つきにくい。 参照
  • 26.
    GPUでのインデックス探索の課題 OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平26 スレッド間の処理時間の差が大きく、同期待ちを招く Table-A ● ● ● ● ● ● 参照 Index-A × × × × × 〇 N = __syncthreads_count(...) 参照 R木のLeafノード まで探索したが ヒットせず R木のRootノードを 見ただけで、即、 マッチする要素なし R木を最後まで 探索し、かつ、 JOINの結合条件を評価 スレッドグループに属する 他のスレッドの完了待ちで GPUコアが遊んでしまう。
  • 27.
    ナイーブなGPU版GiSTインデックス実装(9月末) OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平27 GPUの利用効率が上がらず、しばしばCPUより低速だった ● ● ● ● ● ● ●● 各スレッドが1行分のデータをロード GiST-Index探索用のキー値を抽出する。 GiST-Indexにヒットした? キー値を用いてGiST-Indexを探索する JOIN結合条件は真? JOIN結合条件を評価する nitems個分のJOIN結果を書き出し nitems = __syncthreads_count(found); 繰り返し found=true found=false No No スレッドグループ(512スレッド)内に、 1個でもGiST-IndexのLeafまで降下して 探索したり、JOIN結合条件の評価まで 行うスレッドがいると、他の511スレッ ドはその完了を待たされてしまう。 結果として、GPUコアの使用率が全く 向上しないという事になる。
  • 28.
    GPUのスレッドスケジューリングを意識した実装(11月頭) OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平28 できる限りコアが遊ばないよう、同期ポイントを最小化 ● ● ● ● ● ● ●● 各Warp(32スレッド)毎に1行分のデータをロード GiST-Index探索用のキー値を抽出する。 キー値を用いてGiST-Indexを探索する GiST-Indexにヒットした? Atomic演算を用いて中間バッファの領域を確保 GiST-Indexにヒットした行のポインタを記録 中間バッファの使用量が 512個を越えた __syncthreads() 中間バッファを元に、JOIN結合条件を評価する JOIN結合条件は真? No No nitems = __syncthreads_count(found) nitems個分のJOIN結果を書き出し 繰り返し found=false found=true 中間バッファの使用量に余裕がある限り、 同期ポイントに達する前にどんどん Readポインタを進めて GiST-Index の 探索を進める。 ➔ 一部のWarp(スレッド)で探索に 時間を要しても、他のWarpは先に 次の行を処理できるため、 GPUコアの使用率を高くできる。
  • 29.
    簡易テスト:ランダムな点とSt_Contains(11月初頭) OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平29 (123.0, 20.0) (154.2, 46.2) SELECT n03_001,n03_004,count(*) FROM geo_japan j, geopoint p WHERE st_contains(j.geom, st_makepoint(x,y)) AND j.n03_001 like '東京都’ GROUP BY n03_001,n03_004; ランダムに 生成した座標 1000万個 n03_001 | n03_004 | count ---------+------------+------- 東京都 | あきる野市 | 105 東京都 | 三宅村 | 76 東京都 | 三鷹市 | 17 東京都 | 世田谷区 | 67 東京都 | 中央区 | 12 東京都 | 中野区 | 18 東京都 | 八丈町 | 105 : : : 東京都 | 豊島区 | 14 東京都 | 足立区 | 55 東京都 | 青ヶ島村 | 7 東京都 | 青梅市 | 117 (63 rows) CPU版:24.892s GPU版: 3.733s 国土地理院からDLした 全国市町村形状データ 6倍強の 高速化
  • 30.
    つい先日、マヌケな事に気が付く。。。 OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平30 GPUコンパイラにデバッグオプションを付けたままコミットしていた…。 なんじゃこりゃー!! ナンじゃこりゃー!! $ nvcc --help : --device-debug (-G) Generate debug information for device code. Turns off all optimizations. Don't use for profiling; use -lineinfo instead. :
  • 31.
    簡易テスト:ランダムな点とSt_Contains(現在) OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平31 (123.0, 20.0) (154.2, 46.2) SELECT n03_001,n03_004,count(*) FROM geo_japan j, geopoint p WHERE st_contains(j.geom, st_makepoint(x,y)) AND j.n03_001 like '東京都’ GROUP BY n03_001,n03_004; ランダムに 生成した座標 1000万個 n03_001 | n03_004 | count ---------+------------+------- 東京都 | あきる野市 | 105 東京都 | 三宅村 | 76 東京都 | 三鷹市 | 17 東京都 | 世田谷区 | 67 東京都 | 中央区 | 12 東京都 | 中野区 | 18 東京都 | 八丈町 | 105 : : : 東京都 | 豊島区 | 14 東京都 | 足立区 | 55 東京都 | 青ヶ島村 | 7 東京都 | 青梅市 | 117 (63 rows) CPU版:24.892s GPU版: 1.154s 国土地理院からDLした 全国市町村形状データ 21.5倍の 高速化 GPUコードの最適化 ”あり” で再測定
  • 32.
    簡易テストの実行計画(CPU版) OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平32 postgres=# EXPLAIN (analyze, costs off) SELECT n03_001,n03_004,count(*) FROM geo_japan j, geopoint p WHERE st_contains(j.geom, st_makepoint(x,y)) AND j.n03_001 like '東京都’ GROUP BY n03_001,n03_004; QUERY PLAN ---------------------------------------------------------------------------------------- Finalize GroupAggregate (actual time=24880.443..24880.682 rows=63 loops=1) Group Key: j.n03_001, j.n03_004 -> Gather Merge (actual time=24880.430..24892.342 rows=299 loops=1) Workers Planned: 4 Workers Launched: 4 -> Partial GroupAggregate (actual time=24855.860..24855.949 rows=60 loops=5) Group Key: j.n03_001, j.n03_004 -> Sort (actual time=24855.846..24855.865 rows=529 loops=5) Sort Key: j.n03_001, j.n03_004 Sort Method: quicksort Memory: 64kB -> Nested Loop (actual time=50.124..24854.788 rows=529 loops=5) -> Parallel Seq Scan on geopoint p (actual time=0.120..258.900 rows=2000000 loops=5) -> Index Scan using geo_japan_geom_idx on geo_japan j (actual time=0.012..0.012 rows=0 loops=10000000) Index Cond: (geom ~ st_makepoint(p.x, p.y)) Filter: (((n03_001)::text ~~ '東京都'::text) AND st_contains(geom, st_makepoint(p.x, p.y))) Rows Removed by Filter: 0 Planning Time: 0.160 ms Execution Time: 24892.586 ms (22 rows)
  • 33.
    簡易テストの実行計画(GPU版) OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平33 postgres=# EXPLAIN (analyze, costs off) SELECT n03_001,n03_004,count(*) FROM geo_japan j, fgeopoint p WHERE st_contains(j.geom, st_makepoint(x,y)) AND j.n03_001 like '東京都’ GROUP BY n03_001,n03_004; QUERY PLAN ----------------------------------------------------------------------------------------------- GroupAggregate (actual time=1146.188..1146.212 rows=63 loops=1) Group Key: j.n03_001, j.n03_004 -> Sort (actual time=1146.178..1146.181 rows=63 loops=1) Sort Key: j.n03_001, j.n03_004 Sort Method: quicksort Memory: 29kB -> Custom Scan (GpuPreAgg) (actual time=1146.004..1146.013 rows=63 loops=1) Reduction: Local Combined GpuJoin: enabled -> Custom Scan (GpuJoin) on fgeopoint p (never executed) Outer Scan: fgeopoint p (never executed) Depth 1: GpuGiSTJoin HeapSize: 7841.91KB (estimated: 3113.70KB), IndexSize: 13.28MB IndexFilter: (j.geom ~ st_makepoint(p.x, p.y)) on geo_japan_geom_idx Rows Fetched by Index: 5065 JoinQuals: st_contains(j.geom, st_makepoint(p.x, p.y)) -> Seq Scan on geo_japan j (actual time=0.136..16.067 rows=6173 loops=1) Filter: ((n03_001)::text ~~ '東京都'::text) Rows Removed by Filter: 112726 Planning Time: 0.307 ms Execution Time: 1154.838 ms
  • 34.
    GPU版に固有の最適化 OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平34 ▌ PostgreSQLの場合、Indexに付随する条件句の評価は、Indexを用いて候補となる行を取り出し た後にしか行えない。つまり、結果的に無駄となる行フェッチが発生する。 ▌ GPU版GiSTインデックスでは、予め「明らかに条件に該当しないエントリ」のLeaf要素を無効 化するため、何度も何度も自明な条件句の評価を行う必要はない。 ➔ 『1週間分のデータから直近30分のイベントだけを取り出す』といった特性がある場合に、 通常のGiSTインデックス探索よりも有利に働く。 GiST Rootブロック IndexTupleData IndexTupleData IndexTupleData IndexTupleData IndexTupleData IndexTupleData IndexTupleData notinuse EXPLAIN SELECT n03_001,n03_004,count(*) FROM geo_japan j, geopoint p WHERE st_contains(j.geom, st_makepoint(x,y)) AND j.n03_001 like '東京都’ GROUP BY n03_001,n03_004; QUERY PLAN ------------------------------------------------------ GroupAggregate Group Key: j.n03_001, j.n03_004 -> Sort Sort Key: j.n03_001, j.n03_004 -> Nested Loop -> Seq Scan on geopoint p -> Index Scan using geo_japan_geom_idx on geo_japan j Index Cond: (geom ~ st_makepoint(p.x, p.y)) Filter: (((n03_001)::text ~~ '東京都') AND st_contains(geom, st_makepoint(p.x, p.y))) (9 rows)あらかじめ、明らかに条件に該当しないエントリ (この場合は ‘東京都’ 以外)を無効化
  • 35.
    小噺)ちょっと感動した話 postgres=# EXPLAIN SELECTn03_001,n03_004,count(*) FROM geo_japan j, geopoint p WHERE st_dwithin(j.geom, st_makepoint(x,y), 0.004) AND j.n03_001 like '東京都’ GROUP BY n03_001,n03_004; QUERY PLAN ----------------------------------------------------------------------------------------------------- HashAggregate (cost=1936845.15..1936893.73 rows=4858 width=29) Group Key: j.n03_001, j.n03_004 -> Custom Scan (GpuJoin) on geopoint p (cost=159401.97..1480539.90 rows=60840700 width=21) Outer Scan: geopoint p (cost=0.00..163696.15 rows=10000115 width=16) Depth 1: GpuGiSTJoin(nrows 10000115...60840700) HeapSize: 3113.70KB IndexFilter: (j.geom && st_expand(st_makepoint(p.x, p.y), '0.004'::double precision)) on geo_japan_geom_idx JoinQuals: st_dwithin(j.geom, st_makepoint(p.x, p.y), '0.004'::double precision) GPU Preference: GPU0 (Tesla V100-PCIE-16GB) -> Seq Scan on geo_japan j (cost=0.00..8928.24 rows=6084 width=1868) Filter: ((n03_001)::text ~~ '東京都'::text) (11 rows) OSC Fukuoka/Online 2020 - GPUが拓く地理情報分析の新たな地平35 st_makepoint(p.x, p.y) st_expand() ✓ 引数1(点)を上下左右に引数2(実数)だけ拡張 した矩形領域を返す。 ➔ これとGiSTインデックスのBounding-Boxが 共通領域を持てば、st_dwithin()が真となる 可能性がある。 0.004 0.004
  • 36.
    OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平36 GPU版PostGIS(GiSTインデックス)を用いた 実ワークロードの性能評価
  • 37.
  • 38.
    検索における工夫 OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平38 近傍に位置する駅は両方訪問した事にする。 大阪梅田 東京メトロ銀座線京橋駅と、 都営浅草線宝町駅 西武鉄道 西武秩父駅と、 秩父鉄道 御花畑駅 JR武蔵野線 北朝霞駅と、 東武東上線 朝霞台駅
  • 39.
    集計クエリの構造 OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平39 TRUNCATE train_visit_summary; INSERT INTO train_visit_summary ( -- 集計結果を集計テーブルに保持しておき、Web画面の表示時に -- 未訪問の都道府県も含めて出力する。 WITH cte_station_visit AS ( SELECT DISTINCT s.pref_cd, s.station_cd, u.uid -- “訪問”した駅コード、その都道府県コード、ユーザIDを -- 重複なしで取り出す FROM train_station_list s, train_user_station u -- 駅の位置と、ユーザのチェックイン情報を突合する WHERE st_dwithin(st_makepoint(s.lon, s.lat), st_makepoint(u.lon, u.lat), 0.004) -- 駅の位置とユーザのチェックイン情報の位置が一定範囲内に存在すれば、 -- その駅を訪問したものとみなす。 AND s.station_cd = s.station_g_cd ) SELECT v.pref_cd, v.uid, count(*) FROM cte_station_visit v GROUP BY 1, 2 ); (ユーザ, 都道府県)ごとに、訪問した駅の数を集計
  • 40.
    実行結果(CPU) OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平40 QUERY PLAN ------------------------------------------------------------------------------------------ Insert on train_visit_summary (actual time=564337.937..564337.937 rows=0 loops=1) -> Subquery Scan on "*SELECT*" (actual time=561347.255..564263.657 rows=222985 loops=1) -> GroupAggregate (actual time=561347.253..564245.853 rows=222985 loops=1) Group Key: v.pref_cd, v.uid -> Sort (actual time=561347.227..562318.377 rows=18041063 loops=1) Sort Key: v.pref_cd, v.uid Sort Method: quicksort Memory: 1632107kB -> Subquery Scan on v (actual time=534684.752..543837.130 rows=18041063 loops=1) -> Group (actual time=534684.748..542789.954 rows=18041063 loops=1) Group Key: s.pref_cd, s.station_cd, u.uid -> Sort (actual time=534684.737..538315.419 rows=31188357 loops=1) Sort Key: s.pref_cd, s.station_cd, u.uid Sort Method: quicksort Memory: 2248387kB -> Nested Loop (actual time=0.072..485222.366 rows=31188357 loops=1) -> Seq Scan on train_user_station u (actual time=0.010..2436.186 rows=23969240 loops=1) -> Index Scan using train_station_list_st_makepoint_idx on train_station_list s (actual time=0.018..0.019 rows=1 loops=23969240) Index Cond: (st_makepoint(lon, lat) && st_expand(st_makepoint(u.lon, u.lat), 0.004)) Filter: ((station_cd = station_g_cd) AND st_dwithin(st_makepoint(lon, lat), st_makepoint(u.lon, u.lat), 0.004)) Rows Removed by Filter: 1 Planning Time: 0.241 ms Execution Time: 564369.525 ms (21 rows) 近傍探索に概ね485秒を要している。
  • 41.
    実行結果(GPU) OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平41 QUERY PLAN ------------------------------------------------------------------------------------------ Insert on train_visit_summary (actual time=20520.911..20520.911 rows=0 loops=1) -> Subquery Scan on "*SELECT*" (actual time=19860.629..19919.661 rows=222985 loops=1) -> HashAggregate (actual time=19860.624..19904.020 rows=222985 loops=1) Group Key: s.pref_cd, u.uid -> HashAggregate (actual time=12452.580..16119.425 rows=18041063 loops=1) Group Key: s.pref_cd, s.station_cd, u.uid -> Custom Scan (GpuJoin) on train_user_station u (actual time=366.592..4580.699 rows=31188357 loops=1) Outer Scan: train_user_station u (actual time=44.375..1964.682 rows=23969240 loops=1) Depth 1: GpuGiSTJoin HeapSize: 992.73KB (estimated: 13.12KB), IndexSize: 928.62KB IndexFilter: (st_makepoint(s.lon, s.lat) && st_expand(st_makepoint(u.lon, u.lat), 0.004)) on train_station_list_st_makepoint_idx Rows Fetched by Index: 33137684 JoinQuals: st_dwithin(st_makepoint(s.lon, s.lat), st_makepoint(u.lon, u.lat), 0.004) -> Seq Scan on train_station_list s (actual time=0.023..2.489 rows=12542 loops=1) Filter: (station_cd = station_g_cd) Rows Removed by Filter: 2534 Planning Time: 0.327 ms Execution Time: 20578.966 ms (18 rows) 同じ箇所の実行時間は 4.580 秒 後工程の重複排除処理で時間を要している。
  • 42.
    実行結果 OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平42
  • 43.
    まとめ(1/2) OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平43 ▌GPU版PostGIS  PostGIS関数をGPU上で並列実行するための機能拡張。  GiSTインデックスにも対応し、H/Wの特性を活かしたインデックス探索を実装。  位置ゲームの実データを用いた評価で、近傍探索ワークロードを(実質的に) 100倍以上高速化 ➔ ハマれば非常に効果的。 ▌想定用途  携帯電話や自動車の“位置情報“と、エリア定義情報との突合。  リアルタイムの広告配信やプッシュ型イベント通知など。  これら位置情報分析を含む “計算ヘビー“ なワークロードを 手元のワークステーションやクラウドで手軽に実行できるように。 ▌リソース  GitHub: https://github.com/heterodb/pg-strom  Document: http://heterodb.github.io/pg-strom/ja/  Contact: Tw: @kkaigai / ✉ [email protected]
  • 44.
    まとめ(2/2) OSC Fukuoka/Online 2020- GPUが拓く地理情報分析の新たな地平44 ▌リソース  GitHub: https://github.com/heterodb/pg-strom  Document: http://heterodb.github.io/pg-strom/ja/  Contact: Tw: @kkaigai / ✉ [email protected] PG-Stromプロジェクトは皆さんのご参加を歓迎します