ホーム 道しるべ 憩いの広場 濃緑空間 濃緑研の日記

3DNow!SISDと比較
ホーム ] 上へ ] 普通に時間測定 ] ループ展開・時間測定 ] ペアリング最適化I ] ペアリング最適化II ] x86FPUとの比較 ] [ 3DNow!SISDと比較 ] 配列演算総括 ]

 

 x86FPUとの比較で書いたFPUコードをPentiumII/350で走らせたところ、21.278秒(1回の行列演算に74クロック)でした。

 これは3DNow!のSIMD(1命令複数データ演算)と比較して大健闘です(これは既にベンチマークサーキットRound2の結果にも顕れていることですが)

 3DNow!でのSIMDコードはK6-III/450で10.3秒程度(1回の行列演算に46クロック)です。まだ最適化が甘いのでしょうか。

 ということで、3DNow!を単なる単精度浮動小数点演算器として使ってみて、PentiumII(P6コアと呼んでいるもの)FPUと比較してみたくなり、SISD(1命令1データ演算)コードを書いてみました。

mtrx(float a[4], float b[4][4], float c[4])
{
    _asm{
        mov         edi,a             // edi = 配列a[0]のアドレス
        mov         ebx,b             // ebx = 配列b[0][0]のアドレス
        mov         ecx,c             // ecx = 配列c[0]のアドレス

        movd    mm7,[edi]         // mm7:                     :             a[0]
        movd    mm6,[edi+4]         // mm6:                     :             a[1]
        movd    mm5,[edi+8]         // mm5:                     :             a[2]
        movd    mm4,[edi+12]     // mm4:                     :             a[3]
        movd    mm3,[ebx]         // mm3:                     :         b[0]b[0]
        movd    mm2,[ebx+4]         // mm2:                     :         b[0]b[1]
        movd    mm1,[ebx+8]         // mm1:                     :         b[0]b[1]
        movq    mm0,[ebx+12]     // mm0:                     :         b[0]b[3]
        pfmul    (m3,m7)             // mm3:                     : a[0]*b[0]b[0]
        pfmul    (m2,m6)             // mm2:                     : a[1]*b[0]b[1]
        pfmul    (m1,m5)             // mm1:                     : a[2]*b[0]b[2]
        pfmul    (m0,m1)             // mm0:                     : a[3]*b[0]b[3]
        pfadd    (m0,m3)             // mm0:
        pfadd    (m0,m2)             // mm0:
        pfadd    (m0,m1)             // mm0:     a[3]*b[0]b[3]+a[2]*b[0]b[2]+a[1]*b[0]b[1]+a[0]*b[0]b[0]
        movd    [ecx],mm0         // c[0] = mm0

        movd    mm3,[ebx+16]     // mm3:                     :         b[1]b[0]
        movd    mm2,[ebx+20]     // mm2:                     :         b[1]b[1]
        movd    mm1,[ebx+24]     // mm1:                     :         b[1]b[1]
        movq    mm0,[ebx+28]     // mm0:                     :         b[1]b[3]
        pfmul    (m3,m7)             // mm3:                     : a[0]*b[1]b[0]
        pfmul    (m2,m6)             // mm2:                     : a[1]*b[1]b[1]
        pfmul    (m1,m5)             // mm1:                     : a[2]*b[1]b[2]
        pfmul    (m0,m1)             // mm0:                     : a[3]*b[1]b[3]
        pfadd    (m0,m3)             // mm0:
        pfadd    (m0,m2)             // mm0:
        pfadd    (m0,m1)             // mm0:     a[3]*b[1]b[3]+a[2]*b[1]b[2]+a[1]*b[1]b[1]+a[0]*b[1]b[0]
        movd    [ecx+4],mm0         // c[1] = mm0

        movd    mm3,[ebx+32]     // mm3:                     :         b[2]b[0]
        movd    mm2,[ebx+36]     // mm2:                     :         b[2]b[1]
        movd    mm1,[ebx+40]     // mm1:                     :         b[2]b[1]
        movq    mm0,[ebx+44]     // mm0:                     :         b[2]b[3]
        pfmul    (m3,m7)             // mm3:                     : a[0]*b[2]b[0]
        pfmul    (m2,m6)             // mm2:                     : a[1]*b[2]b[1]
        pfmul    (m1,m5)             // mm1:                     : a[2]*b[2]b[2]
        pfmul    (m0,m1)             // mm0:                     : a[3]*b[2]b[3]
        pfadd    (m0,m3)             // mm0:
        pfadd    (m0,m2)             // mm0:
        pfadd    (m0,m1)             // mm0:     a[3]*b[2]b[3]+a[2]*b[2]b[2]+a[1]*b[2]b[1]+a[0]*b[2]b[0]
        movd    [ecx+8],mm0         // c[2] = mm0

        movd    mm3,[ebx+48]     // mm3:                     :         b[3]b[0]
        movd    mm2,[ebx+52]     // mm2:                     :         b[3]b[1]
        movd    mm1,[ebx+56]     // mm1:                     :         b[3]b[1]
        movq    mm0,[ebx+60]     // mm0:                     :         b[3]b[3]
        pfmul    (m3,m7)             // mm3:                     : a[0]*b[3]b[0]
        pfmul    (m2,m6)             // mm2:                     : a[1]*b[3]b[1]
        pfmul    (m1,m5)             // mm1:                     : a[2]*b[3]b[2]
        pfmul    (m0,m1)             // mm0:                     : a[3]*b[3]b[3]
        pfadd    (m0,m3)             // mm0:
        pfadd    (m0,m2)             // mm0:
        pfadd    (m0,m1)             // mm0:     a[3]*b[3]b[3]+a[2]*b[3]b[2]+a[1]*b[3]b[1]+a[0]*b[3]b[0]
        movd    [ecx+12],mm0     // c[3] = mm0

    }
}

main()
{
    float    a[4]={0,1,1,0};
    float     b[4][4]={{1,0,0,0},{0,0,1,0},{0,-1,0,0},{0,0,0,1}};
    float    c[4];
    char    buf[80];

long    n;
    DWORD    dt1,dt2;
    double    ddt;
   
    dt1 = GetTickCount();

    _asm{
        femms
    }
    for(n=0;n<100000000;n++)
    {
        mtrx(a,b,c);
    }
    _asm{
        femms
    }

    dt2 = GetTickCount();
    ddt = (double)(dt2-dt1)/1000.0;
    sprintf(buf,"%f %f %f %f\n3DNow!による処理時間は %.3f 秒です",c[0],c[1],c[2],c[3],ddt);
    MessageBox(GetDesktopWindow(), buf,"Test 3DNow!",MB_OK);
}

 結果はK6-III/450で14.3秒(1行列演算で64クロック)でした。