ここのところ、HPC では x86 だけに対応すれば幸せになれる、という時代は
終わり、 GPGPU, arm (富岳)とかも考えないといけなくなっています。また、
x86 でももちろん AVX2, AVX512 あたりは考えないといけません。
素晴らしいコンパイラがあったとしても icc は arm のことは知らないし、富
士通の sve用コンパイラは 他のことは知らない、どうすれば性能がでるかの
書き方はマシンによって違う、ということになります。
FDPS では、このようなターゲットアーキテクチャによって別のコードが必要
になるのは、計算量がもっとも多い粒子間相互作用計算で、それ以外の
ユーザーコードはまあ普通に書いてあれば速度はなんとか、という感じに
なります。そこで、単一のソースから、
-
AVX2/512
-
Cuda
-
OpenCL
-
あとまあ色々
での、最適化された、あるいはコンパイラが最適化できる相互作用計算
コードを生成してくれるものがあれば FDPS を使う人、作る人全てが幸せに
なれるわけです。ここでのポイントは、ターゲットアーキテクチャ毎に
生成系を1つ書けばそれは FDPS (でなくても相互作用計算一般ですが)
の全てのものが複数プラットフォーム対応になる、ということです。
新しいアーキテクチャがでてきても、それぞれ用の
コード生成系だけつくればユーザープログラムは変更なしで
高い効率で動くようになる、というのが基本的な目標になります。
まあその、元々 KFCR で作っている Goose コンパイラや、そのもとになる
LSUMP、さらにその元にある PGR とかなわけですが、使うべきコンパイラやハー
ドウェアもだいぶ変わったのと、FDPS向けにコード生成したいところがだいぶ
あるので、新規に、かなあと。
基本的には、例えば
# C++ 型名対応
epj jparticle
epi iparticle
# i, j 粒子入出力
fi force
iin f64vec xi r
jin f64vec xj r
jin f64 mj m
iin f64 eps2
iout f64vec f
iout f64 phi
#計算本体
rij = xi-xj
r2 = rij*rij+eps2
rinv = rsqrtinv(r2)
mrinv = mj*rinv
phi = phi-mrinv
f = f-mrinv*rinv*rinv* rij
くらいのことを書くと、 FDPS が使う相互作用関数で、ちゃんとマシン対応
した並列化、場合によってはイントリンシックで書くとか、 SIMD ユニットの
中で i 並列、 j 並列を組合せる、さらにはアンロールするとかくらい、
さらに MN-Core 向けに直接アセンブラを吐く、といったことくらいを実現し
たい、ということになります。
まあその、こういうのはパースできればどうにでもなる、というところはあり
ます。Racc で
雑なパー サを作ってみました。まあ使えるためには FDPS の EPI, EPJ, FORCE
クラスやそれらと粒子クラスとの変換関数、内側コードだけでなくて関数全体
とかを生成する必要がありますが、この辺はぼちぼち(あるいは若者に、、、)
今どきならもうちょっと違うものがあるのかもという気もしますが、まあ
BNF というか Yacc の入力で、アクションのところに Ruby でなんでも
書けるのでまあいいかなと。Racc でインタプリタを、みたいな例は
あちこちに転がってますが、構文木相当のものを作る例は意外にないので
こういうのをやってみたい人には参考になるかもしれません。