在类中使用随机生成器时出现性能问题



我的目标是用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_valuemax_value参数内联到此函数。

就其价值而言,我无法在上重现显著的性能差异

  • 苹果clang 11.0.0版(clang-1110.0.33.17(
  • 升压1.69.0_2

最新更新