내 목표는 Mersenne Twister를 사용하여 Boost 균일 한 실제 배포를 둘러싼 래퍼를 만들어 라이브러리에서 사용할 수 있도록하는 것입니다. 그래서 다음과 같은 기본 클래스를 만들었습니다.
class mt19937
{
protected:
boost::random::mt19937 gen_;
boost::random::uniform_real_distribution<double> real_;
public:
mt19937(unsigned long s = 5489UL) : gen_(s), real_(0., 1.) {};
double get() { return real_(gen_); };
};
성능 테스트를 실행하면서 내 수업이 Boost 개체에 대한 직접 호출보다 훨씬 느리다는 것을 알았습니다. 실제로 100 억 개의 숫자를 샘플링하는 다음 코드는 내 컴퓨터에서 30 초를 차지합니다.
constexpr unsigned long seed = 5489UL;
constexpr size_t iter = 100000;
double x = 0.;
boost::random::mt19937 gen(seed);
boost::random::uniform_real_distribution<double> real(0., 1.);
for (size_t i = 0; i < iter; ++i)
for (size_t j = 0; j < iter; ++j)
x = real(gen);
mt19937
위에서 설명한 클래스 는 다음 코드와 함께 약 70 초가 걸립니다.
mt19937 stduniform(seed);
for (size_t i = 0; i < iter; ++i)
for (size_t j = 0; j < iter; ++j)
x = stduniform.get();
코드가 실행되는 첫 번째 경우에, Windows의 어셈블러 보는 것은 x = real(gen)
나에게 단지에 대한 호출 보인다 다음입니다 boost::random::detail::generate_uniform_real
및 할당에를 x
:
00007FF6D14639F0 movzx r9d,byte ptr [r15]
00007FF6D14639F4 lea rcx,[gen]
00007FF6D14639F9 movaps xmm2,xmm7
00007FF6D14639FC movaps xmm1,xmm8
00007FF6D1463A00 call boost::random::detail::generate_uniform_real<boost::random::mersenne_twister_engine<unsigned int,32,624,397,31,2567483615,11,4294967295,7,2636928640,15,4022730752,18,1812433253>,double> (07FF6D146141Ah)
함수를 사용하면 get()
다음과 같은 명령이 표시됩니다. 설명 할 수없는 레지스터와 점프에 대한 일부 작업을 수행하는 것 같습니다.
00007FF6D1463B61 movsd xmm3,mmword ptr [rbp+900h]
00007FF6D1463B69 lea rcx,[stduniform]
00007FF6D1463B6E movsd xmm4,mmword ptr [rbp+8F8h]
00007FF6D1463B76 movaps xmm2,xmm3
00007FF6D1463B79 mulsd xmm2,xmm6
00007FF6D1463B7D movaps xmm1,xmm4
00007FF6D1463B80 mulsd xmm1,xmm6
00007FF6D1463B84 movaps xmm0,xmm2
00007FF6D1463B87 subsd xmm0,xmm1
00007FF6D1463B8B comisd xmm0,xmm7
00007FF6D1463B8F jbe main+2F8h (07FF6D1463B98h)
00007FF6D1463B91 call boost::random::detail::generate_uniform_real<boost::random::mersenne_twister_engine<unsigned int,32,624,397,31,2567483615,11,4294967295,7,2636928640,15,4022730752,18,1812433253>,double> (07FF6D14615D7h)
00007FF6D1463B96 jmp main+307h (07FF6D1463BA7h)
00007FF6D1463B98 movzx r9d,byte ptr [rbx]
00007FF6D1463B9C movaps xmm2,xmm3
00007FF6D1463B9F movaps xmm1,xmm4
00007FF6D1463BA2 call boost::random::detail::generate_uniform_real<boost::random::mersenne_twister_engine<unsigned int,32,624,397,31,2567483615,11,4294967295,7,2636928640,15,4022730752,18,1812433253>,double> (07FF6D146141Ah)
인라인되어야하는 함수에 대한 호출이 100 억 번 수행되면이 오버 헤드가 추가 될 수 있습니까? 성능 향상을위한 코드에 대한 제안이 있습니까?
저는 Windows 환경에서 작업하고 있으며 Boost 1.7.1과 함께 VisualStudio2015의 컴파일러 vc14를 사용하고 있습니다. Linux 시스템에서 gcc4.9와 유사한 동작을 관찰했습니다. Boost에 대한 직접 호출에는 30 초가 걸리고 새 클래스에는 45 초가 걸립니다.
시간 내 주셔서 감사합니다.
강조 표시 한 "내가 설명 할 수없는 레지스터의 일부 작업"비트 :
00007FF6D1463B61 movsd xmm3,mmword ptr [rbp+900h]
00007FF6D1463B69 lea rcx,[stduniform]
00007FF6D1463B6E movsd xmm4,mmword ptr [rbp+8F8h]
00007FF6D1463B76 movaps xmm2,xmm3
00007FF6D1463B79 mulsd xmm2,xmm6
00007FF6D1463B7D movaps xmm1,xmm4
00007FF6D1463B80 mulsd xmm1,xmm6
00007FF6D1463B84 movaps xmm0,xmm2
00007FF6D1463B87 subsd xmm0,xmm1
00007FF6D1463B8B comisd xmm0,xmm7
00007FF6D1463B8F jbe main+2F8h (07FF6D1463B98h)
의 다음 줄과 일치하는 것 같습니다 generate_uniform_real
.
T result = numerator / divisor * (max_value - min_value) + min_value;
if(result < max_value) return result;
따라서 컴파일러 가이 함수에 min_value
및 max_value
인수를 인라인 할 수없는 것 같습니다 .
그만한 가치를 위해 다음과 같은 중요한 성능 차이를 재현 할 수 없었습니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다