2

このコードを考えると:

#include <iostream>
#include <chrono>

typedef unsigned long long T;

namespace Benchmark
{
    T a, b;
    inline void L_Add() { a += b; b += a; }
    inline void Unroll_10() { L_Add(); L_Add(); L_Add(); L_Add(); L_Add(); L_Add(); L_Add(); L_Add(); L_Add(); L_Add(); }
    inline void Unroll_100() { Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); }
    inline void Unroll_1000(T& a_, T& b_)
    {
        a = a_; b = b_;
        Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100();
        a_ = a; b_ = b;
    }
};

inline void L_Add(T& a, T& b) { a += b; b += a; }
inline void Unroll_10(T& a, T& b) { L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); }
inline void Unroll_100(T& a, T& b) { Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); }
inline void Unroll_1000(T& a, T& b) { Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); }

int main()
{
    std::chrono::high_resolution_clock::time_point StartTime, EndTime;
    T a = 3;
    T b = 5;
    StartTime = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 1000000; ++i)
        Benchmark::Unroll_1000(a, b);
    EndTime = std::chrono::high_resolution_clock::now();
    std::cout << a << " : " << std::chrono::duration_cast<std::chrono::milliseconds>(EndTime - StartTime).count() / 2000.0 << "ns" << std::endl;

    a = 3;
    b = 5;
    StartTime = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 1000000; ++i)
        Unroll_1000(a, b);
    EndTime = std::chrono::high_resolution_clock::now();
    std::cout << a << " : " << std::chrono::duration_cast<std::chrono::milliseconds>(EndTime - StartTime).count() / 2000.0 << "ns" << std::endl;

    return 0;
}

そして、この出力:

12646046898197897264 : 0.3875ns
12646046898197897264 : 2.253ns

「Benchmark::Unroll_1000(a, b)」の逆アセンブリが次のようになる理由を知りたいと思っていました。

add rax,rcx  
add rcx,rax 

一方、「Unroll_1000(a, b)」の分解は次のとおりです。

mov rax,qword ptr [rdx]  
add qword ptr [rcx],rax  
mov rax,qword ptr [rcx]  
add qword ptr [rdx],rax 

私の理解では、同じコードを生成する必要があります。誰かが私を啓発できますか?また、グローバル変数なしで「Benchmark::Unroll_1000(a, b)」と同じパフォーマンスを達成するにはどうすればよいですか?

4

1 に答える 1