Atomの浮動小数演算性能
ITmediaのこちらの記事に、Atomでは倍精度浮動小数はソフトウェアで処理されるという記述がありました。確かにx87系FPUには単精度・倍精度・拡張倍精度の3つの精度モードがありますが、普通に高級言語でソフトを作るとレジスタ間では常に倍精度か拡張倍精度で処理され、メモリアクセスの際にfloatなりdoubleなりに変換されるコードになったハズ(たぶん。。。)。となると、既存の小数を扱うソフトはそのままだとパフォーマンスが大幅に低下することになります。せっかくAtomでマシンを組んだので、実測してみました。
ベンチマークに使ったプログラムは以下の通り(VisualC++用)。同じレジスタにひたすら除算と乗算を繰り返しているだけなので、ベンチマークとしての信憑性はいまひとつですが、およその速度比率は求められるはずです。
#include <windows.h>
#include <stdio.h>
void main(void)
{
__int64 freq, ctr1, ctr2;
float f_a[2] = {1.23, 1.23}, f_b[2] = {4.56, 4.56};
double d_a = 1.23, d_b = 4.56;
const char *prec[] = {"single", "double", "long double"};
unsigned short fcw[] = {0x007F, 0x027F, 0x037F};
int i;
QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
/* FPU 単精度、倍精度、拡張倍精度計測 */
for (i = 0; i < 3; i ++) {
QueryPerformanceCounter((LARGE_INTEGER *)&ctr1);
__asm {
push ecx
mov ecx, i
fldcw word ptr [fcw + ecx*2]
fld d_b
fld d_a
mov ecx, 100000000
fpu_loop:
fdiv st(0), st(1)
fmul st(0), st(1)
loop fpu_loop
fst d_a
fst d_b
pop ecx
};
QueryPerformanceCounter((LARGE_INTEGER *)&ctr2);
printf("FPU %s: %fs\n", prec[i], (ctr2 - ctr1)*1.0 / freq);
}
/* SSE 単精度計測 */
QueryPerformanceCounter((LARGE_INTEGER *)ctr1);
__asm {
push ecx
movlps xmm0, f_a
movhps xmm0, f_a
movlps xmm1, f_b
movhps xmm1, f_b
mov ecx, 100000000
sse_loop:
divps xmm0, xmm1
mulps xmm0, xmm1
loop sse_loop
pop ecx
};
QueryPerformanceCounter((LARGE_INTEGER *)&ctr2);
printf("SSE: %fs.\\n", (ctr2 - ctr1)*1.0 / freq);
/* SSE2 倍精度計測 */
QueryPerformanceCounter((LARGE_INTEGER *)&ctr1);
__asm {
push ecx
movlpd xmm0, d_a
movhpd xmm0, d_a
movlpd xmm1, d_b
movhpd xmm1, d_b
mov ecx, 100000000
sse2_loop:
divpd xmm0, xmm1
mulpd xmm0, xmm1
loop sse2_loop
pop ecx
};
QueryPerformanceCounter((LARGE_INTEGER *)&ctr2);
printf("SSE2: %fs.\\n", (ctr2 - ctr1)*1.0 / freq);
}
結果。%はそれぞれのFPU単精度の時間を100%とした相対値です。コアごとの傾向を見るためのものなので、絶対値は気にしないでください。
| Atom(Diamondville) | Core2(Conroe) | CeleronD(Prescot) | PentiumM(Banias) | |
|---|---|---|---|---|
| FPU(単精度) | 2.3870秒(100%) | 1.0173秒(100%) | 1.6001秒(100%) | 2.3345秒(100%) |
| FPU(倍精度) | 4.2026秒(180%) | 1.6070秒(158%) | 1.9201秒(120%) | 3.7526秒(161%) |
| FPU(拡張倍精度) | 4.8927秒(205%) | 1.8656秒(183%) | 2.1215秒(134%) | 4.3684秒(187%) |
| SSE(単精度x4) | 9.4088秒(394%) | 0.9540秒(94%) | 4.0408秒(253%) | 7.8163秒(335%) |
| SSE2(倍精度x2) | 8.6567秒(363%) | 1.6052秒(158%) | 3.1251秒(195%) | 6.2911秒(269%) |
確かにAtomはFPU倍精度が遅いですが、他と比べて大幅に遅いわけでもなく、ソフト処理していると思わせるほどではありません。というか、ソフトでトラップ処理する場合OSのサポートが必要になってしまうので、ソフトウェアで処理するというのはマイクロコードによる実装比が高いといった意味合いかもしれませんね。また、単精度・倍精度問わず、SSEの遅さが光ります。ヘタをするとFPUで普通でやる場合に負けるかも。Core2とは対照的です。
なお、VisualC++の場合、float、doubleの使用状況にかかわらず倍精度モードで演算されるバイナリになるようです(拡張倍精度はサポートされていない)。SSE2未対応のため表にありませんが、手持ちのCPUで単位クロックあたりのスコアがもっとも優秀だったのはAthlonXPでした。
TrackBack URI : http://sfb7.org/diary/wp-trackback.php?p=30
コメント (0)