非同期デリゲートを用いた並列計算の結果に関する考察(2)

最初に

非同期デリゲートを用いた並列計算の結果に関する考察(1)
http://d.hatena.ne.jp/kaminarioyaji/20081227/1230404072
の続き。前回載せた結果に対する考察部分。

考察

この計算で計っているCPU性能

今回計測した計算は、1000x5000回の繰り返し計算なのですが、ループ内の1回の計算で使っているC#の命令は

  • 倍精度(double型)の+,-,*,/
  • Math.Sqrt(double), Math.Exp(double)
  • Math.Sin(double), Math.Cos(double)

になっています。実行環境は.NET Framework(Windowsは32bit)なので、これらの演算にはFPUが使われている、、と思うのですが、Core2>K8となっている図3の結果を見る限りそうでもないのかなぁと。というのも、純粋なFPU性能であれば、

Phenomで探る、AMD新世代プロセッサの真実 - アーキテクチャ研究編 (12)
http://journal.mycom.co.jp/special/2008/phenom01/011.html

のグラフ53、DGEMMのAssembly x87、Compiledの結果にあるようにK8(&K10)アーキテクチャの方がCore2よりも高いようなので。
Sin,Cosはx87命令に存在しているので、FPUを使っていると思われますが・・・。平方根や、エクスポーネンシャルをALUを使って計算してるのかなぁ。。。ちょっと詳しいことはわからないですが、ともかくFPU以外も含んだCPUの性能を見てる感じです。
実際、図2に示したように、Pentium4 640(HT)でかなり高速化できたことを考えると、単純なFPUの繰り返しではなく、他にコストがかかる処理を同時進行で行っていると推測できます。

なお、計算に用いるデータは単純計算ですべて合わせても400KB程度*1であり、L2キャッシュ($)に全て収まっていると思われます。仮に$から溢れるとしても、演算コストがかなり高いはずなので、キャッシュした分のデータを使って計算している間に、メインメモリから次に必要なデータをとって来れてるかなぁと*2
実際、図3に示すように、DDRメモリを使っているMancehsterと、DDR2メモリを使っているBrisbaneで有意な差が見られなかったので*3、メインメモリの速度・帯域による影響はほとんどないと考えています。

唯一、L2$ 512KBのCeleronDとL2$ 2MBのPentium4,Dの性能差が気になるのですが・・・、前回書いたように、CeleronDのPCにUSB-VGAアダプタを付けているせい、かなぁ。。。

Core2の世代による性能差の原因

図3で、Core2の中でも有意な差が見られた原因としては、
最新の45nmプロセスで作られたCore2(Wolfdale/Penryn)では、

高速化をもたらすRadix-16 DividerとSuper Shuffle Engine
http://pc.watch.impress.co.jp/docs/2007/0524/mpf01.htm

にあるように、Radix-16 Dividerの追加によって、前Core2(Conroe/Merom)に対して割り算が速くなっているようなので、この効果が出たのかなと思っています。

PentiumD・Athlon64X2での伸びが悪い原因

図2に示したように、PentiumD・Athlon64X2ではシングルスレッド時に比べ1.5〜1.6倍の速度向上と、理論値に比べ随分と低くなってしまいました。
理論どおりの性能が出たCore2と比べ、PentiumD・Athlon64X2に共通する違いとしては、コア間の共有L2がないという違いがあります*4

結論から言うと、原因は、デリゲートに渡していた引数(複素数*5の配列)の1つが参照渡しになっていることにありました。計算時には、この引数の実体は、PentiumD・Athlon64X2の場合、各コアのL2$に別々に格納されるため、キャッシュコヒーレンシを保つために適時L2$ラインの確認(通信)を行っているはずであり、これのコストが結構かかっていたと考えられます。
対して、Core2では共有L2をとっているため、各コアで同じデータを参照していても、L2$に入っている限りでは余計な追加コストが発生しなかったのではと思われます。

この推測を元に、デリゲートへの引数が全て値渡しになる(=各スレッドが用いるデータはすべて独立する)よう、複素数をクラスから構造体にして実装し直した所、Athlon64X2で理論値近い性能が出るようになりました(これについてはまた後日)。

今後の課題

  • USB-VGAアダプタの影響

を調べる。
あと、出来るのかどうか知らないのですが、

  • 計算時FPU以外に何が使われているのか、JITコンパイラが吐いたネイティブコードを確認

したいなぁと。

*1:1000+5000個のdouble型(8byte)配列を8つ

*2:ちゃんと計算してないのでホントかどうかは・・・

*3:&ここには載せていませんが、必要データ量を1/10にしても特に性能は改善されなかったので

*4:PentiumDは2die in 1Packageなので、正しくはCPU間の共有L2がない、かなぁ。

*5:内部にdouble型変数を2つもつ