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;在每次迭代期间添加结果的想法,因为这是不应该包含在就这个问题而言,如果我们可以专注于其他替代解决方案,那就太好了,尽管对于对此感兴趣的任何人,评论中都会进行热烈的讨论,其中共识是在许多情况下这+=最合适的方法. )

4

1 回答 1

4

放入a单独的编译单元,不要使用LTO(链接时优化)。那样:

  • 循环总是相同的(由于基于 的优化而没有区别a
  • 函数调用的开销总是一样的
  • 要测量纯开销并有一个基线来比较实现,只需对一个空版本的a

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


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

于 2013-03-09T11:18:39.450 回答