MPI行列計算(圷・牧野・内藤班)

ポイント

通信の高速化

行列の分割方法

N台のマシンで計算をする場合、P*Q=Nで、差が最小となるような自然数PQでそれぞれの行列を分解する。たとえば、Nが8のときはP=4、Q=2となる。そして掛け合わせる行列をA、Bとすると、Aを4つに、Bを2つに分解する。分割されたそれぞれの行列を下の図のように組みあわせ、計算する。


行列ABの送信

行列A,Bを各プロセスに送信する。プロセスに0〜N−1の番号が振られている場合、分割されたAをA(0),A(1),A(2)・・・A(P-1)とすると、A(i)をプロセスi,i+P*1,i+P*2,・・・・i+P*(Q-1)に送信する。また、分割されたBをB(0),B(1),B(2)・・・・B(Q-1)とすると、B(i)をプロセスi*Q,i*Q+1,i*Q+2,・・・・,i*Q+(P-1)に送信する。

送信方法

サイズの等しいM種類のデータをM*RのプロセスにR個づつ送信する効率のよいと思われる方法は次のとおりである。

まず、1種類のデータをR個のプロセスに送信する方法(BroadCast)を考える。以下のような木を作り、送信すればroot(R)の手間で送信できる。


たとえばR=8のときは上のような木を作ればすべてのプロセスにおいて通信は手間3で終了する。 この木は再帰的に次のように定義できる。 次に、M種類のデータをM*RのプロセスにR個づつ送信する場合を考える。

開始プロセスは、R−1個の第二の親プロセスを決め、それぞれの親ごとに異なるR−1種類のデータを送る。そして送り終えたところで、開始プロセス自身が第二の親となり、すべての第二の親は自分の子プロセスにデータをbroadcastする。
この方法だと、root(R)+M-1の手間ですべてのデータを送信できる。

AとBの行列を両方送る場合、(root(P)+Q-1)+(root(Q)+P-1)の手間がかかる。

受信方法

すべての結果をプロセス0(開始プロセス)に一気に集めると、最終的な行列の形にするために、大規模なメモリのコピーが必要になる。このコピーによるオーバーヘッドは以外に大きいので、一度、各第2の親プロセスに結果を集め、そこで行列の整形を行ってから第1の親プロセスに送ることにした。これで、メモリコピーの手間を1/Pにできるが、無駄な送信が増えるため、通信速度の遅い環境だと、一気に第一の親プロセスに集めてしまったほうが早い場合もあるかもしれない。 また、メモリのコピーには、memcpy関数を使って高速化している。



行列演算の高速化

行列演算の高速化に対するアプローチは以下のとおりである。

行列のブロック化

二次キャッシュのヒット率を上げることができる。

ループのアンローリング

最も重視するべきなのはループの最も内側のオーバーヘッドを削減することである。for文による分岐命令を減らすことができる。しかしやりすぎると、コードが巨大になり、それ自身がキャッシュに納まらなくなるので、適度にする。

レジスタ変数の使用

ループの内側にあるような最も頻繁にアクセスされる変数にレジスタ変数を割り当てることで、よりきめ細かく動作を指示でき、コンパイラによる余計な最適化を避けることができる。

コンパイラ

Folon3のOSがRedHat7.1であったので、それに対応したIntel社から無償で公開されているコンパイラを使用した。プロセッサ用の特殊な命令コードを使うので、非常に高速化される。Edamは対応するバージョンがなかったため、gccでコンパイルした。

結果

Folon3

仕様
並列マシン(8台)
Intel PentiumIII 1Ghz
ネットワーク:myrinet2k
キャッシュ:512 Kbyte
OS : RedHatLinux7.1
通信・行列演算
サイズ・台数 1 2 4 6 8
1000×1000 3.160215 1.703865 0.966179 0.724819 0.595649
2000×2000 25.857840 13.368239 7.052869 5.050389 3.977846
3000×3000 - 44.617790 23.171409 16.196120 12.553940
4000×4000 - - - 37.963817 29.095459

通信のみ
サイズ・台数 2 4 6 8
1000×1000 0.126600 0.176368 0.2003109 0.199336
2000×2000 0.505231 0.697185 0.798988 0.606364
3000×3000 1.710484 1.531072 1.754059 1.741623
4000×4000 2.028043 2.721654 3.124276 3.106741

Edam

仕様
Ultra enterprise 4000 (Sun)
Ultra SPARC 167MHz * 10 個
メモリ:256 (= 8 * 32) MByte * 5 枚 = 1280 MByte
キャッシュ:512 Kbyte * 10
OS : Solaris2.5.1
通信・行列演算
サイズ・台数 1 2 4 6 8 10
1000×1000 33.983181 17.254878 8.750679 6.012076 4.619827 3.742117
2000×2000 - - - 47.364784 36.186154 29.127327

通信のみ
サイズ・台数 2 4 6 8 10
1000×1000 0.304640 0.337489 0.358953 0.385802 0.381394
2000×2000 1.049632 1.281590 1.416138 1.523557 1.533921

folon4new

仕様
並列マシン(16台)
Intel PentiumIII 1.2Ghz×2
ネットワーク:myrinet2k
キャッシュ:512 Kbyte
OS : RedHatLinux7.2
通信・行列演算
サイズ・台数 1 2 4 8 16 32
1000×1000 2.503601 1.441973 0.885680 0.551317 0.413384 0.315199
2000×2000 20.435509 11.202000 6.138873 3.512726 2.313990 1.614884
3000×3000 - 37.841344 20.363139 11.201318 6.758927 4.380207
4000×4000 - - 47.058436 25.297544 14.894702 9.321221
5000×5000 - - - 45.747425 26.283388 16.032726
6000×6000 - - - - 44.482365 26.259553
7000×7000 - - - - - 41.561834
8000×8000 - - - - - 61.100860

問題点

ソース