如何强制编译器不要跳过我的函数调用?

时间:2013-03-09 11:11:31

标签: c++ benchmarking compiler-optimization

假设我想对某些函数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;的想法每次迭代,因为这是额外的工作,不应该包含在结果时间中。对于这个问题的目的,如果我们可以专注于其他替代解决方案,那将是很好的,尽管对此感兴趣的人有一个热烈的讨论在评论中,共识是+=在许多情况下是最合适的方法。

1 个答案:

答案 0 :(得分:3)

a放在单独的编译单元中,然后使用LTO(链接时优化)。那样:

  • 循环始终相同(由于基于a的优化而没有差异)
  • 函数调用的开销总是相同的
  • 要衡量纯粹的开销并拥有比较实施的基准,只需对a
  • 的空版本进行基准测试

请注意,编译器不能假设对a的调用没有副作用,因此无法优化循环并将其替换为最后一次调用。


完全不同的方法可以使用RDTSC,它是CPU内核中用于测量时钟周期的硬件寄存器。它有时对微观基准有用,但正确理解结果并不是一件容易的事。例如,查看this并搜索/搜索SO以获取有关RDTSC的更多信息。