【问题标题】:Global time cost versus sum of local time costs -- "for" loop全局时间成本与本地时间成本之和——“for”循环
【发布时间】:2019-10-25 14:34:07
【问题描述】:

虽然看起来很愚蠢,但我想知道在尝试协调 for 循环的时间成本时是否可能存在缺陷

  • 来自for 循环之外的时间点(全局外部时间成本)
  • 或者,从循环内部的时间点开始,并被累积考虑(本地内部时间成本)?

下面的例子说明了我在获得两个相等的测量值时遇到的困难:

#include <iostream>
#include <vector> // std::vector
#include <ctime> // clock(), ..

int main(){
  clock_t clockStartLoop;
  double timeInternal(0)// the time cost of the loop, summing all time costs of commands within the "for" loop
    , timeExternal // time cost of the loop, as measured outside the boundaries of "for" loop
    ;
  std::vector<int> vecInt; // will be [0,1,..,10000] after the loop below
  clock_t costExternal(clock());
  for(int i=0;i<10000;i++){
    clockStartLoop = clock();
    vecInt.push_back(i);
    timeInternal += clock() - clockStartLoop; // incrementing internal time cost
  }
  timeInternal /= CLOCKS_PER_SEC;
  timeExternal = (clock() - costExternal)/(double)CLOCKS_PER_SEC;

  std::cout << "timeExternal = "<< timeExternal << " s ";
  std::cout << "vs timeInternal = " << timeInternal << std::endl;
  std::cout << "We have a ratio of " << timeExternal/timeInternal << " between the two.." << std::endl;
}

我通常得到一个大约 2 的比率作为输出,例如

timeExternal = 0.008407 s vs timeInternal = 0.004287 我们两者之间的比率为 1.96105..

,而我希望比率接近 1。

  • 是否只是因为循环中有一些操作 internal 不是由clock() 差异测量的(例如递增timeInternal)?
  • for(..) 中的i++ 操作能否在外部测量中不可忽略,并解释与内部测量的区别?

我实际上正在处理一个更复杂的代码,我想在一个循环中隔离时间成本,确保我考虑的所有时间片确实构成了一个完整的馅饼(直到现在我从未实现过......) .非常感谢

【问题讨论】:

  • 很可能大部分时间都花在clock() 调用本身上,然后您正在测量 1 次 clock() 调用与 2 次的累积时间。为什么不使用适当的 C++ 分析器?
  • 因为我在适当的分析器方面没有经验(还没有?)。也许是时候获得一些了,谢谢。
  • 我建议你比较一下这段代码的两个版本:一个只有外部时间,一个只有内部时间的总和

标签: c++ performance time


【解决方案1】:

timeExternal = 0.008407 s vs timeInternal = 0.004287 我们两者之间的比率为 1.96105..

预计比率约为 2 - 到目前为止,循环中最重的调用是 clock() 本身(在大多数系统上,clock() 是对内核的系统调用)。

想象clock() 的实现类似于以下伪代码

clock_t clock() {
    go_to_kernel(); // very long operation
    clock_t rc = query_process_clock();
    return_from_kernel(); // very long operation
    return rc;
}

现在回到循环,我们可以注释花费时间的地方:

  for(int i=0;i<10000;i++){
    // go_to_kernel - very long operation
    clockStartLoop = clock();
    // return_from_kernel - very long operation
    vecInt.push_back(i);
    // go_to_kernel - very long operation
    timeInternal += clock() - clockStartLoop;
    // return_from_kernel - very long operation
  }

因此,在对clock() 的两次调用之间,我们有 2 个长操作,循环中的总数为 4。因此比率为 2 比 1。

  • 是否只是因为循环内部存在未被clock() 差异衡量的操作(例如递增timeInternal)?

不,增加timeInterval 可以忽略不计。

  • for(..) 中的i++ 操作能否在外部测量中不可忽略,并解释与内部测量的区别?

不,i++ 也可以忽略不计。删除对clock() 的内部调用,您将看到更快的执行时间。在我的系统上是 0.00003 秒。

clock() 之后的下一个开销最大的操作是 vector::push_back(),因为它需要调整 vector 的大小。这由二次增长因子摊销,可以通过在进入循环之前调用vector::reserve() 完全消除。

结论:在进行基准测试时,请确保对整个循环而不是单个迭代进行计时。更好的是,使用像 Google Benchmark 这样的框架,这将有助于避免许多其他陷阱(如编译器优化)。还有 quick-bench.com 用于简单案例(基于 Google Benchmark)。

【讨论】:

    猜你喜欢
    • 2023-03-03
    • 2015-04-23
    • 1970-01-01
    • 2012-08-30
    • 1970-01-01
    • 2015-05-16
    • 1970-01-01
    • 1970-01-01
    • 2020-07-11
    相关资源
    最近更新 更多