MPI行列積演算 永田・矢島班

問題

folon3及びedamにおいて、MPIを用いて行列積演算を高速に 行うプログラムを作成する。条件は、

a. サイズは 1000, 2000, 3000, (可能ならば 4000)
b. 台数は 1,2,4(,6),8(,10:edamのみ) 台(括弧内はオプション)
c. 実行時間が1分以上のものは測定不要
d. 特定のプロセッサ上にデータが読み込まれて(または生成されて)から そのプロセッサ上に結果が集まるまでの時間

とする。

プログラム

ソースファイルをここに載せました。

工夫した点

・MPI、データ転送部分

特に凝ったことは何も行わず、MPIのScatterv(), Bcast(), Gatherv()を そのまま用いた。下手に自分で実装するよりも既存の関数を使ったほうが 高速であり、また全体における実行時間比率が少ないため最適化 の必要性があまり無いと思われたためである。

A*B=Cの行列演算を行うにあたり、Aを行方向に分割する。その分割したA とBをかけることにより、Cの一部を得ることが出来る。各PEにAの一部とBを 送り、Cの一部を計算させた結果をPE0に集めることによりCを得る。 概念図を以下に示す。

Scatterv, GathervはScatter, Gatherの拡張版で、各PEに送るデータの サイズを指定することが出来る。まず、行列のサイズを全PEに Bcastする。そして、自分が行列のどの部分を計算するのか (Scatterv, Gathervの引数となる、どのPEにどのデータを送るのかを 表す配列)を計算する。それを用いてAをScattervし、BをBcastし、 行列積を計算した後、結果をGathervで集めている。この方法により、 1以上の任意の大きさの行列、任意の数のPEにおいて実行することができる。

行列は、ランダムで値を作成する方法とファイルから読み込む方法 の2つを選ぶことが出来る。コマンドラインに数を指定すればその大きさの ランダムな行列を生成し、ファイル名を指定すればそのファイルから読み込む。 また、プリコンパイル時のdefineをかえることにより、値の正当性検証も 行うことが出来る。

・行列積演算部分

前期の大石先生の数値計算の、行列積高速化のレポートを元にして 作成した。
行列を高速化するための方法として、
・ループ交換
・ループアンローリング
・ブロック化
等がある。

この中で最も効果があるのは行列のブロック化である。 色々なサイズを試してみたところ、120*120の大きさが 最も結果がよかった。
ループアンローリングは行列サイズの約数であると 効果が高いため、それにあわせたところ、 アンローリング数が40の場合が最も高速となった。
また、ブロック化した場合には、ループの順番を交換しても 速くはならなかった。

また、ブロック化では、A*B=Cの計算のときに、元の配列から A,Bを一部分コピー(tA,tB)して計算した結果(tC=tA*tB)を 再びCにコピーするのがいいはずであるが、直接Cに入れた 場合のほうが速かった。

また、コンパイルオプションとして、
・-O3 … 最適化オプション
・-march=i686 … i686に特化したコードをはく
・-funroll-loops … ループを展開する(らしい)
を指定したが、-O3以外はほとんど動作速度は速くならない。
ちょっと速くなる気がする程度である。

その他の工夫として、ブロック化した部分を別関数としているが、 呼び出しのオーバーヘッドを少なくするために、インライン展開 を用いている。これにより少しだけ速度が向上した気がする。

実行結果

folon3実行結果
edam実行結果