研究日誌。

大規模なグラフ処理に対してメモリ階層構造を考慮した高性能なソフトウェアを開発。

DMA転送と処理のバランス2。

2007-10-18 22:49:04 | Weblog
前回に続いて、SPE においてのデータ転送、処理サイズのバランスについて。

DGEMM(Double)では、2行ずつ処理していくのが効率的であると述べたが、
今回は SGEMM(Float)について、プロファイルをしてその結果から考察していく。


まずは、サイズ、使用 SPE ごとの実行時間である。

SPENUM 512x512 1024x1024 2048x2048 [msec]
  1   360    2600   22000
  2   200    1500   12000
  3   150    1060    8200
  4   125    830     6400
  5   113    710     5400
  6   105    630     4700


倍精度演算と比べれば確かに早くなってはいるが、あまり期待どおりとはいえない。
今回も前回同様、処理とデータ転送のバランスを見ていく。


[データ転送 / 積和演算]
SPENUM    512x512  1024x1024  2048x2048 [msec]
  1  0.17 / 0.4  0.3 / 0.8  0.6 / 1.7
  ~ 
  6  0.2 / 0.4  0.4 / 0.8  0.8 / 1.7

結果からは、思ったよりも積和演算が足を引っ張っているのかもしれないと考えられる。



[データ転送数]
512x512 では、512 x 4(2行、2行) x 4(float) = 8Kbyte
1024 x 1024 では 16Kbyte、2048 x 2048 では 32Kbyte となる。

[積和演算数]
512x512 では、2 x 2 x 512 = 2048 回の積和演算、
1024 x 1024 では 4096 回、2048 x 2048 では 8192回の積和演算することになる。

8Kbyte の2倍と 2048 回の積和演算、16Kbyte の2倍と 4096 回の積和演算、
32Kbyte の2倍と 8192 回の積和演算がそれぞれ同じくらいとすると、
やはり「データ:積和演算=8:1」であるようだ。

処理を早くすることは難しいので、
それに見合うように「4行ずつ DMA 転送する」などの改良してみようと思う。
もう少し調べてみよう。

DMA転送と処理のバランス。

2007-10-18 17:18:26 | Weblog
Cell プログラミングは SPE を上手に使うことがキーとなっている。
基本的に、PPEプログラムが SPE プログラムを立ち上げ、
必要なデータを SPE へ DMA 転送し、処理した後、DMA 転送によって PPE に返す。

SPE スレッドの立ち上げや、前処理、後処理にはある程度オーバーヘッドがかかってしまうが、
SPE はそのオーバーヘッド以上を取り戻すほどの性能を持っている。
特にSPE 内で1度に扱うデータサイズをうまく決めてあげればかなりの速度向上をすることができる。

DGEMM に関してだが、最適なデータサイズというのがあまり決まらず、DMA 転送が足を引っ張ると誤認識していた。
そのため、一度に多くのデータを持ってきてしまい、演算を繰り返すというスタイルでの処理にしようかと考えていた。
具体的には 1度に DMA 転送できる最大サイズである 16Kbyte 分、DMA 転送し行数分演算する。
512 x 512 では、4行ずつ、1024 x 1024 では、2行ずつ、2048 x 2048 では1行ずついった感じだ。
512 x 512 では、4 x 4 x 512 = 8192 回の積和演算、1024 x 1024 では、2 x 2 x 1024 = 4096 回、
2048 x 2048 では 2048 回というように、DMA 転送はできるだけしない、するならたくさんとってくる。


しかし、プロファイルをとってみると予想とは違う結果になった。
なかなか良さそうなのは今までのやりかたである、「2行ずつの処理」である。
Double Buffer を用いて高速化したいのであれば、
DMA 転送と、積和演算の割合を均等にした方がより効果を得られやすい。


「2行ずつの処理」について見ていくと、簡単な流れは以下のようになっている。

STEP1 行列Aと行列Cを2行ずつ DMA 転送してくる
STEP2 行列A、行列Cにそれぞれα、βを乗じる
STEP3 行列Bを2行ずつ DMA 転送してくる
STEP4 行列Aの一部と行列Bの一部で演算を行い、結果を行列Cに書き込む
STEP5 STEP3~STEP4 を行列B分繰り返す
STEP6 STEP1~STEP5 をその SPE に割りふられた分だけ繰り返す

実際に実行時間の割合が大きそうな、STEP1 と STEP4 についてプロファイルしてみた。



[DMA 転送]
512 x 512 であれば、512 x 4(行列A、行列C、それぞれ2行ずつ) x 8(倍精度) = 16Kbyte
1024 x 1024 であれば 32Kbyte、2048 x 2048 であれば 64Kbyte となる。

DMA 転送に要した時間の1ループ分 (STEP1)
使用SPE数  512  1024  2048 [msec]
    1  0.3  0.6  1.2
    2  0.3  0.6  1.2
    3  0.4  0.6  1.3
    4  0.4  0.7  1.4
    5  0.4  0.8  1.5
    6  0.4  0.8  1.5



[積和演算]
積和演算は1ループで4回行うことになる
(行列Aの1行目 x 行列Bの1行目、行列Aの1行目 x 行列CB2行目、……)ので、
512 x 512 では 2(行列A2行分) x 2(行列B2行分) x 512 で、2048 回積和演算することになる。
1024 x 1024 では 4096 回、 2048 x 2048 では 8096 回積和演算を行うことになる。
実際には SIMD 演算(倍精度なら1度に2個ずつ)してしまうので、実際にはその半数になる。

内積に要した時間の1ループ分(STEP4)
使用SPE数  512  1024  2048 [msec]
  1~6  0.3  0.6  1.3



この結果より、16Kbyte の DMA 転送 と 2048 回の積和演算、32Kbyte の DMA 転送 と 4096 回の積和演算、
64Kbyte の DMA 転送 と 8192 回の積和演算が同じくらいといえる。

数字だけみれば、「DMA 転送:積和演算=8:1」のようである。

今回は倍精度でのみ考えているが、単精度ではまた違った組み合わせになるだろう。