このコードを考えると:
#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)」と同じパフォーマンスを達成するにはどうすればよいですか?