我的目标是用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 ojects慢得多。事实上,以下代码对100亿个数字进行了采样,在我的机器上使用了30s:
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环境中工作,使用VisualStudio2015的编译器vc14和Boost 1.7.1。我在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
参数内联到此函数。
就其价值而言,我无法在上重现显著的性能差异
- 苹果clang 11.0.0版(clang-1110.0.33.17(
- 升压1.69.0_2