性能評価:FMA

C++言語で記述したプログラムと、アセンブリ言語で記述した関数を利用したときの性能差を検証してみましょう。
arques.hatenablog.com

符号付64ビット整数型

性能評価プログラム

C++で記述した関数と、アセンブリ言語で記述した関数を複数回呼び出します。それぞれに要した時間をclock関数で計測し、性能を評価します。common.hやアセンブリ言語で記述した関数は「特定値のインデックス抽出」で示したものと同じです。以降に、呼び出し側のソースリストを示します。

#include "..\common.h"  // TEMPLATES

#define T double
extern "C"
{
    void afmaaddpd  (const T*, const T*, T*, const T, const size_t);
    void afmasubpd  (const T*, const T*, T*, const T, const size_t);

    void afnmaaddpd (const T*, const T*, T*, const T, const size_t);
    void afnmasubpd (const T*, const T*, T*, const T, const size_t);

    void afmaddsubpd(const T*, const T*, T*, const T, const size_t);
    void afmsubaddpd(const T*, const T*, T*, const T, const size_t);
}
typedef void (*Dfunc)(const T*, const T*, T*, const T, const size_t);

extern "C"
Dfunc afunc[] = { afmaaddpd, afmasubpd, afnmaaddpd,
                                afnmasubpd, afmaddsubpd, afmsubaddpd };
Dfunc cfunc[] = { cfmaadd,   cfmasub,   cfnmaadd,
                                cfnmasub,   cfmaddsub,   cfmsubadd   };

// main
int main(void)
{
    const size_t ArrLen = 32768;
    static_assert(ArrLen % 16 == 0,
        "number of elements must be an integral multiple of 16.");
    T k = 11.5f;
    #define LOOPS   10000

    try
    {
        T* a = (T*)_mm_malloc(sizeof(T) * ArrLen, 64);
        T* b = (T*)_mm_malloc(sizeof(T) * ArrLen, 64);
        T* c = (T*)_mm_malloc(sizeof(T) * ArrLen, 64);
        T* v = (T*)_mm_malloc(sizeof(T) * ArrLen, 64);

        init(a, b, ArrLen);

        clock_t start;
        for (int i = 0; i < sizeof(cfunc) / sizeof(*cfunc);i++)
        {
            cout << "---[" << i << "]---  " << endl;

            start = clock();
            for (int j = 0; j < LOOPS;j++)
                cfunc[i](a, b, c, k, ArrLen);
            print_elTime("cpp: ", start, clock());

            start = clock();
            for (int j = 0; j < LOOPS;j++)
                afunc[i](a, b, v, k, ArrLen);
            print_elTime("asm: ", start, clock());

            verify(c, v, ArrLen);
        }
        _mm_free(v);
        _mm_free(c);
        _mm_free(b);
        _mm_free(a);
    }
    catch (char* str)
    {
        cerr << str << endl;
    }
    return 0;
}

これまでと同様に、時間の計測を行います。上記プログラムへ /O2 オプションを指定してビルド&実行したときの性能を示します。

アセンブリ言語で開発した関数は、C++言語で開発した関数より約1.8倍~10.4倍高速です。

32ビット浮動小数点型


アセンブリ言語で開発した関数は、C++言語で開発した関数より約1.9倍~26.9倍高速です。