OpenFOAM Plugin for GPU (SpeedIT Classic) を使ってみる

2010年12月23日

使用バージョン

openSUSE 11.3 x86_64, OpenFOAM 1.7.1, CUDA Toolkit 3.2, SpeedIT Classic 1.0, OpenFOAM Plugin 1.1。

グラフィックカードは NVIDIA GeForce GTX 470。

必要なもの

ここ から以下を入手 (登録が必要)。

  • SpeedIT Classic (SpeedIT_Classic.zip)
  • OpenFOAM Plugin (OpenFOAM_Plugin_1_1.zip)

SpeedIT には "Classic" と "Extreme" があり、前者はオープンソース、後者は有料版である。Classic は単精度の CG 法のみ、Extreme は倍精度の BiCGStab 法が使える (らしい)。Plugin はどちらかの SpeedIT を使用して実装される。

あと、もちろん CUDA Toolkit をインストールしておく必要がある。

セットアップ

単精度版 OpenFOAM のセットアップ

SpeedIT Classic では単精度版 PCG しか使えないので、まず単精度版の OpenFOAM を用意する必要がある。~/.bashrc で以下のように設定して OpenFOAM をコンパイルする。

WM_PRECISION_OPTION=SP
. ~/OpenFOAM/OpenFOAM-1.7.1/etc/bashrc

プラグインのコンパイル

パッケージを展開。

$ unzip OpenFOAM_Plugin_1_1.zip
$ cd OF\ 1.1

ソースは SpeedIT Extreme を使うように書かれているので修正する。

PCG_accel.C で speedit_ex.h をインクルードしているところを si_classic.h をインクルードするように書き換える。

#include "si_classic.h"
//#inlucde "speedit_ex.h"

PCG_accel.C で si_gscsrcg() を呼び出すところを sicl_gscsrcg() を呼び出すように修正。

/*solver_result = si_gscsrcg( n_rows,
    ...
    &n_iter, &eps);*/

solver_result = sicl_gscsrcg( n_rows,
    ...
    &n_iter, &eps);

GPU Computing SDK のパスを設定。

~/.bashrc

export SDK_INSTALL_PATH=~/NVIDIA_GPU_Computing_SDK

~/.bashrc を読み込む。

$ . ~/.bashrc

コンパイル。

$ mkdir Make
$ mv files options Make
$ wmake libso

SpeedIT Classic のセットアップ

パッケージを展開してコンパイル。

$ unzip SpeedIT_Classic.zip
$ cd SpeedIT_Classic
$ make

ライブラリをコピー。

$ cp libSpeedIT_Classic.so $FOAM_USER_LIBBIN

CUDA のライブラリもコピー。

$ cd /usr/local/cuda/lib64
$ cp libcublas.so $FOAM_USER_LIBBIN
$ cp libcudart.so $FOAM_USER_LIBBIN

実行

icoFoam でテスト。

$ cp -r $FOAM_TUTORIALS/incompressible/icoFoam/cavity .
$ cd cavity
$ blockMesh

system/controlDict に以下を追加。

libs
(
    "libcudart.so"
    "libcublas.so"
    "libSpeedIT_Classic.so"
    "libexternalsolv.so"
);

system/fvSolution を以下のように編集。

solvers
(
    p
    {
        //solver          PCG;
        //preconditioner  DIC;
        solver          PCG_accel;
	preconditioner  diagonal;
	tolerance       1e-6;
	relTol          0;
    }
    ...

実行。

$ icoFoam

倍精度版の作成

SpeedIT Classic & OpenFOAM Plugin を倍精度版に書き換えてみた。

si_classic.cu, si_classic.h の float を double に置換。また cublasSnrm2 を cublasDnrm2 に、cublasSdot を cublasDdot に、gsc を gdc に置換する。si_classic.h はプラグインのほうにコピーする。

Makefile の nvcc にオプション "-arch sm_13" を挿入。

libSpeedIT_Classic.so: si_classic.cu
	nvcc -arch sm_13 ...

プラグインのほうは、PCG_accel.C の si_gdcsrcg を sicl_gdcsrcg に書き換える。

検証

simpleFoam で計算時間の評価を行ってみたが、PCG_accel を使うと PCG のときよりも時間がかかる…。調べてみると、PCG_accel の反復計算回数がかなり大きくなっている。どうやら PCG_accel は preconditioner に diagonal を受け付けるようになっていながら、SpeedIT Classic のほうで前処理を行っていないようだ。

以下に simpleFoam での計算時間を示す。小さなモデル (Case 1, 12,000 セル)、大きいモデル (Case 2, 160,000 セル) それぞれについて PCG + DIC, 前処理なし PCG, PCG_accel の計算時間を比較した。単精度版と倍精度版との比較も行った。収束判定値 (SIMPLE の convergence) は 1e-3、ソルバーの maxIter は 1000 (デフォルト) とした。並列なしで計算した。

マシンスペック

CPUCore i7 870 (4 コア, 定格 2.93 GHz)
グラフィックカードNVIDIA GeForce GTX470 1280 MB

単精度版

Case 1

SolverPreconditionerStepClock Time
PCGDIC283 s
PCGnone283 s
PCG_acceldiagonal (none)309 s

Case 2

SolverPreconditionerStepClock Time
PCGDIC4742 s
PCGnone47100 s
PCG_acceldiagonal (none)4762 s

倍精度版

Case 1

SolverPreconditionerStepClock Time
PCGDIC283 s
PCGnone284 s
PCG_acceldiagonal (none)2710 s

Case 2

SolverPreconditionerStepClock Time
PCGDIC4754 s
PCGnone47119 s
PCG_acceldiagonal (none)4790 s

以上の結果からつぎのことがわかる。

  • 現状の GPU では倍精度の計算速度は単精度のそれより遅いと言われるが、確かにそういう結果になっている。
  • 大きなモデルでは、PCG_accel は前処理なし PCG に比べると確かに速いが、前処理あり PCG のほうが速い。

おまけ

Case 2 (倍精度版)

SolverSmootherStepClock Time
GAMGGaussSeidel4731 s

Case 2 (4 パラレル, 倍精度版)

SolverPreconditioner/SmootherStepClock Time
PCGDIC4726 s
PCGnone4753 s
GAMGGaussSeidel4715 s

結論: GAMG + パラ。これ最強。