OpenMPが遅くなってしまう理由

並列計算を行うための代表的なフレームワークとしてMPIとOpenMPがある。両方ともスレッドを複数立ち上げて計算を行うのだが、何が違うのかと言うとメモリの扱いが違う。MPIでは各プロセスが占有のメモリ領域を扱うのに対し、OpenMPではメモリを共有してアクセスすることができる。


ノード内はOpenMP、ノード間はMPIのハイブリッド並列が推しらしい。というのは、MPIでは明示的にデータ通信を行わないと自分の担当外の情報にアクセスできないので、通信のコストで遅くなってしまうのだが、OpenMPは共有メモリなのでそんなことはないからだとか。

しかし多くの場合、OpenMPよりもMPIの方が計算性能が良くなる。MPIではちゃんと並列数分の性能が出るのに対し、OpenMPではそうならなかったりする。これはなぜか。

このページにいろいろな要因が書いてあり参考になる。

いろいろ理由があるのだが、最終的にこれが原因だと考えられるものに到達して、どうしようもなさそうなのでもう匙を投げることにした。
OpenMPではメモリを共有しているということであったが、近いメモリ領域への読み書きを複数スレッドで頻繁に繰り返す作業がある場合、バスの取り合いになってしまいメモリアクセスが律速になってしまうのだ。*1 MPIの場合は各スレッドのメモリ領域が離れているのでそういったことは起こらない。それじゃOpenMPで別々にメモリ確保すればいいのではということになってしまいそうだが、それじゃMPIと変わらないじゃんということになってしまう他のスレッドの担当メモリにもアクセスできるという利点はあるが、MPIの方が書きやすいし*2…メモリアクセスのボトルネックが見えないようにソフトウェアパイプライニングを試してみたが並列化効率の上ではあまり効果なし。なんかもうどうしようもない気がする。
というわけで、OpenMPは鬼門だということがよくわかった。


GPUはそんなこと無い気がするのだが、単純にメモリアクセスが速いのか、あるいはメモリコアレッシングのおかげなのだろか。コアレッシングのおかげだとしたら、コアレッシングできない計算は大丈夫なのかな…

*1:false sharingも効いているのかもしれないが、volatileでcacheを使わないように(嘘かもしれない)してもだめだった。

*2:OpenMPはpragmaつけるだけで簡単という印象を持たれがちだが、そのpragmaのせいで手続き的にプログラムを書かなくては行けなかったりして実は書きにくい。