使用<ctime>和指令重新排序</ctime>进行基准测试

时间:2010-11-22 16:19:09

标签: c++ c++11

到目前为止,我一直在使用传统的方法来对并发方法进行基准测试,即测量多次运行的持续时间:

template <typename Functor>
double benchmark(Functor const& f, size_t nbRuns)
{
  if (nbRuns == 0) { return 0.0; }

  f(); // Initialize before measuring, I am not interesting in setup cost

  time_t begin = time(0);
  for (size_t i = 0; i != nbRuns; ++i) { f(); }
  time_t end = time(0);

  return difftime(end, begin);
}
在我遇到这个问题之前,这似乎很好,很花哨:Optimizing away a "while(1);" loop in C++0x

让我感到不同寻常的是,允许编译器在循环之前执行输出......我突然想知道:

  

什么阻止编译器在循环之前执行time_t end = time(0);

因为如果确实如此,那就会以某种方式搞砸我的小基准代码。

虽然我们在这里,但如果在这种情况下可能会发生重新排序:

  

如何防止它?

除了C ++以外我无法想到相关标签,如果有人认为我错过了一个,请随意添加

2 个答案:

答案 0 :(得分:6)

这是一个棘手的问题。

  

是什么阻止了编译器   执行time_t end = time(0);之前   循环在这里?

一般来说,没有;事实上,即使在C ++ 03中。由于as-if规则,编译器可以发出任何具有相同可观察行为的代码。这意味着,如果省略f()不会更改任何指定的输入/输出或挥发性访问,则可能根本不会运行f()

  

令我不同寻常的是   允许编译器执行   在循环之前输出

这不是真的 - 空循环的问题是C ++ 0x不仅仅将非终结视为可观察行为。并不是它可以重新排序空循环和"Hello"的输出,而是编译器可以完全忽略空循环。

答案 1 :(得分:2)

通常我会使用一个对象将我的计时器放入一个范围内,这样当它超出范围时,它会计算析构函数中的“end”。

是否允许编译器在仍然在范围内时执行其析构函数?我不知道。

当然time_t只测量秒数,所以我通常会测量更细的颗粒,通常是几毫秒。有时毫秒不够精确(例如非常小的函数被称为很多次),在这种情况下你可能会使用微秒。

当然,在这种情况下,进入和离开示波器本身会产生开销,但它通常是“侵入式”分析中的一个很好的衡量标准,通常非常适合在实际情况下进行优化。 (您通常可以打开和关闭此功能)。