heterodb/pg-strom

スレッド数が多い時、CPU使用率が非常に高くなる。

Closed this issue · 6 comments

PostgreSQLの並列クエリを有効にすると、iostatで見たスループットが、並列クエリ=disabled である場合と比べて顕著に低下する。

perfで調べてみたところ、CUDAの中から呼ばれている pthread_rwlock_rdlock でCPU時間を大量に消費している。
これが原因で、おそらくスループットの低下を招いている。

Samples: 6M of event 'cycles', Event count (approx.): 4941230366343, Thread: postgres
  Children      Self  Command   Shared Object          Symbol                                                                                     
+   92.17%     0.00%  postgres  libcuda.so.535.104.05  [.] 0x00007fe7feab100c                                                                    a
+   59.43%     0.00%  postgres  libpthread-2.28.so     [.] __GI___pthread_rwlock_rdlock (inlined)                                                a
+   59.42%     0.00%  postgres  libcuda.so.535.104.05  [.] 0x00007fe7fee3af37                                                                    a
-   59.34%    59.34%  postgres  libpthread-2.28.so     [.] __pthread_rwlock_rdlock                                                               a
     59.33% __GI___clone (inlined)                                                                                                               a
        start_thread                                                                                                                             a
        gpuservGpuWorkerMain                                                                                                                     a
      - gpuservHandleGpuTaskExec                                                                                                                 a
◆       - 58.61% 000000000000ce58                                                                                                               a
◆          - 58.61% 000000000000ce58                                                                                                            a
◆             - 58.61% 000000000000ce58                                                                                                         a
◆                  0x7fe7fee3af37                                                                                                               a
◆                - __GI___pthread_rwlock_rdlock (inlined)                                                                                       a
◆                     __pthread_rwlock_rdlock_full (inlined)                                                                                    a
◆       + 0.72% gpuservLoadKdsArrow (inlined)                                                                                                   a
◆  59.27%     0.00%  postgres  libpthread-2.28.so     [.] __pthread_rwlock_rdlock_full (inlined)                                                a
◆   __pthread_rwlock_rdlock_full (inlined)                                                                                                       
◆  20.49%     0.00%  postgres  libpthread-2.28.so     [.] __GI___pthread_rwlock_unlock (inlined)                                                a
-   20.48%     0.00%  postgres  libcuda.so.535.104.05  [.] 00007fe7fee3b12b                                                                      a
   - 00007fe7fee3b12b                                                                                                                            a
      + 20.48% __GI___pthread_rwlock_unlock (inlined)                                                                                            a
-   20.46%    20.46%  postgres  libpthread-2.28.so     [.] __pthread_rwlock_unlock                                                               a
     20.45% __GI___clone (inlined)                                                                                                               a
        start_thread                                                                                                                             a
        gpuservGpuWorkerMain                                                                                                                     a
◆    - gpuservHandleGpuTaskExec                                                                                                                 a
         - 20.21% 000000000000dc61                                                                                                               a
            - 20.21% 000000000000dc61                                                                                                            a
               - 20.21% 000000000000dc61                                                                                                         a
                    0x7fe7fee3b12b                                                                                                               a
                  + __GI___pthread_rwlock_unlock (inlined)                                                                                       a
+   20.35%     0.00%  postgres  libpthread-2.28.so     [.] __pthread_rwlock_rdunlock (inlined)                                                   a
+    4.06%     0.00%  postgres  libcufile.so.1.7.2     [.] 0x00007fe7fe0b95a6                                                                    a
+    4.06%     0.00%  postgres  libcuda.so.535.104.05  [.] 0x00007fe7fec65d6c                                                                    a
+    4.06%     0.00%  postgres  libcuda.so.535.104.05  [.] 0x00007fe7fee1b6e4

ひとまず、対処策としては
① ロック呼び出しの原因となっているCUDA APIを特定し、そこの同時並列実行数に上限を加える。
② 当該事象は v3.x 系列では発生していない。CUDA Contextあたりのスレッド数が関係するのかも。

ひとまず、流石にワーカー数が増えた時にスレッド数が100を越えるのはやりすぎと反省。

スレッドを増やして同期APIを使うより、CUDAのAsync APIで代用する事を検討。
GPU Direct StorageのAync APIは12.0の時点ではまだ不安定であったので、まず12.3で検証。

ひとまず、567001445c41a63447d7a70a012ac7bd926cc94b および 611889a43710d516eafa60bd5617a224a8a63bba での修正でこちらはペンディング。
ToDoはNVIDIAのcuFileチームへのエスカレーション。

nvidia-fsのドライバ、普通にOSSになってるし、ポーリングの部分(ユーザ空間)を自前で実装すればよくないか。

https://github.com/NVIDIA/gds-nvidia-fs

これも v5.2 に向けて、根本原因の調査や対策を打ち込んでいく。

cuFileライブラリの中ではDevice Primary Contextを使っているので、実はCUDA Contextを自分で作るとCUDA Contextのスイッチングが頻繁に発生してしまう。
代わりに cuDevicePrimaryCtxRetain を使うべき。

image

これは素晴らしい。