代码之家  ›  专栏  ›  技术社区  ›  Matthieu M.

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

  •  6
  • Matthieu M.  · 技术社区  · 14 年前

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

    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 回复  |  直到 7 年前
        1
  •  6
  •   jpalecek    14 年前

    这是个棘手的问题。

    是什么阻止编译器 执行时间结束=时间(0);之前 这里的环路?

    一般来说,没有什么,事实上,即使在C++ 03中。由于as-if规则,编译器可能会发出具有相同可观察行为的任何代码。也就是说,如果省略 f() 不更改任何指定的输入/输出或挥发物访问,它可能不会运行 f() 完全。

    让我觉得不寻常的是 允许编译器执行 循环前输出

    这不是真的-空循环的问题是C++0X不把不终止看作是可观察的行为。不是它可以重新排序空循环和 "Hello" ,而是编译器可以完全忽略空循环。

        2
  •  2
  •   CashCow    12 年前

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

    是否允许编译器在作用域内执行其析构函数?我不知道。

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

    当然,在这种情况下,在进入和离开作用域本身时会有开销,但在“侵入式”分析中,这通常是一个很好的措施,在实际情况下,这通常非常有利于优化。(您经常可以打开和关闭该功能)。