2013-03-09 78 views
2

比方说,我想基准两个竞争实现的某些功能double a(double b, double c)。我已经有一个大的array <double, 1000000> vals从中我可以输入值,所以我的标杆看起来大致是这样的:如何强制编译器不跳过我的函数调用?

//start timer here 
double r; 
for (int i = 0; i < 1000000; i+=2) { 
    r = a(vals[i], vals[i+1]); 
} 
//stop timer here 

现在,一个聪明的编译器可以意识到,我永远只能使用最后一次迭代的结果,简单地杀死其余的,留给我double r = a(vals[999998], vals[999999])。这当然会破坏基准测试的目的。

有没有一种好的方法(如果它适用于多个编译器,则可以获得额外的积分),以防止这种优化,同时保持所有其他优化?我也看到其他线程插入空asm块,但我担心可能会阻止内联或重新排序。我也不是特别喜欢在每次迭代中添加结果sum += r;的想法,因为这是额外的工作, 对于这个问题,如果我们可以专注于其他替代解决方案,那将是非常好的,但对于任何对此感兴趣的人来说,在共识为+=的意见中有热烈的讨论在许多情况下是最合适的方法。

+0

你为什么要这么做? – 2013-03-09 11:12:13

+0

因为我有两个不同的'a'实现,我想比较它们。 – us2012 2013-03-09 11:13:10

+0

重新排序通常是作为优化afaik完成的。 – 2013-03-09 11:13:26

回答

3

a放在单独的编译单元中不是使用LTO(链接时优化)。这样的话:

  • 循环总是相同的(没有区别,由于基于a优化)
  • 函数调用的开销总是相同
  • 为了测量纯开销,并且有一个基准比较实现,只是基准空版本的a

注意,编译器不能假定调用a有没有副作用,因此它不能改善循环路程,取代它的机智h只是最后一次通话。


完全不同的方法可以使用RDTSC,它是CPU内核中的一个硬件寄存器,用于测量时钟周期。它有时对微基准有用,但正确理解结果并不是微不足道的。例如,检查出this和goggle/search SO以获取有关RDTSCs的更多信息。

+0

虽然会阻止内联,不是吗? – us2012 2013-03-09 11:20:49

+0

是的,因为没有LTO,编译器无法将方法从一个TU内联到另一个TU。 – 2013-03-09 11:21:58

+0

@ us2012:增加RDTSC,也许这是您的选择/想法? – 2013-03-09 11:43:05

相关问题