【问题标题】:performance of system clock in c and c++11c和c ++ 11中系统时钟的性能
【发布时间】:2014-07-04 09:11:40
【问题描述】:

我注意到计算经过时间的 C 风格比使用 C++11 更快。如果执行需要更多时间,则差异会越来越小。

#include <iostream>
#include <chrono>
#include <ctime>

long fibonacci(int n)
{
    if (n < 3) return 1;
    return fibonacci(n-1) + fibonacci(n-2);
}

int main()
{
    /* C++11-Style */
    std::chrono::time_point<std::chrono::system_clock> start, end;

    /* C-Style */
    clock_t c_start, c_end;
    double c_elapsed;

    /* Start */
    start = std::chrono::system_clock::now();
    c_start = clock();

    std::cout << "f(30) = " << fibonacci(30) << '\n';

    /* End */
    c_end = clock();
    end = std::chrono::system_clock::now();

    /* Compute Elasped time */
    c_elapsed = ((double)(c_end-c_start))/CLOCKS_PER_SEC;
    std::chrono::duration<double> elapsed_seconds = end-start;
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);

    std::cout << "finished computation at " << std::ctime(&end_time)
              << "  elapsed time: " << elapsed_seconds.count() << "s\n";
    std::cout << "c_elapsed time: " << c_elapsed << "s" << std::endl;
}

结果是

f(30) = 832040
finished computation at Fri Jul  4 05:03:10 2014
  elapsed time: 0.00417783s (C++11)
c_elapsed time: 0.003686s   (C)

为什么会这样?

【问题讨论】:

  • 您的chrono 点也考虑到第二个clock 呼叫。
  • 您应该使用更重的工作负载以避免不准确和开销,检查当您缩放斐波那契 argumanet 时比率是否保持这种方式
  • 当您启动基于chrono 的时钟时,您将包括调用c-style 时钟的费用。您稍后启动 c 风格的时钟并尽快停止它。您应该将您的函数拆分为 2 个函数,每个函数仅使用其中一种方法,否则执行完全相同的工作量。
  • @CroCo:我没有否决这个问题,但人们可能认为这个问题有点愚蠢/明显。事实上,这些人中的大多数人可能无法说出机器人和我在下面的答案中发现的所有问题,所以我认为在这种情况下你可以放心地忽略反对者。但是,如果您确实进行了一些研究并学会了如何制定适当的基准,那也不会受到伤害:这种懒惰在这里是不受欢迎的。
  • @CroCo:我对你投了反对票,因为坦率地说,这距离“获得 CS 学位”还有一千英里。这不仅仅是基本的。您遇到的问题与 C++11 似乎较慢这一事实无关,而与您没有关于如何构建远程公平基准的第一条线索这一事实有关。这不是我们可以在 SO 答案中解决的问题,因此您的问题非常不适合本网站。

标签: c++ c performance c++11 time


【解决方案1】:

这个测试有几个问题。

  1. 这是一个样本。

    谁知道下次运行它会发生什么。据我们所知,差异可能在 0.002 和 -42.1723 之间波动,而这个样本恰好显示接近 0.002 的差异。如何知道结果是否可重复,或者如果只尝试一次,结果会如何变化?

  2. 这是一个完全未知特征的时钟样本。

    如果第一个时钟只能以 0.00417783 秒的增量进行测量,而第二个时钟只能以 0.003686 秒的增量进行测量,但实验实际上是在 0.005 秒内运行的,该怎么办?如果不知道时钟的测量能力如何,如何知道结果差异是否有意义?

  3. 它为每个时钟测量不同的东西。

    第一个时钟测量包括对第二个时钟代码的两次调用。如果时钟不是从一种测量到另一种测量的唯一变化,那么如何知道结果的差异是否可以通过时钟的差异来解释?

因此测试毫无意义。

更好的测试应该:

  1. 确定时钟的特性。

    首先需要知道时钟测量时间的精确度。知道了这一点,就可以对实验进行扩展,从而将低精度的影响降低到我们不关心的程度。

  2. 用两个时钟测量相同的东西。

    比较苹果和苹果。除了第一个感兴趣的部分:时钟之外,这两个测量应该没有区别。

  3. 采集多个样本。

    通过多次采样,我们可以了解结果是否是一次侥幸(可能由外部因素引起)以及结果如何变化。

【讨论】:

    【解决方案2】:

    你的测试不公平!这有几个原因。

    基准测试失败

    您有 clock() 调用仅围绕斐波那契计算,但 std::chrono::system_clock::now() 调用围绕斐波那契计算加上两个 clock() 调用!

    让我们再看一遍:

      C                | C++11
      ====================================
      fibonacci(30)    | clock()
                       | fibonacci(30)
                       | clock()
    

    您的 C++11 版本应该导致更长的持续时间似乎是完全合理的。

    使用隔离机制重新运行您的基准测试(例如每个代码变体使用一个完全独立的文件),并增加定时计算的大小以获得更有意义的结果;运行它 100 次,然后取平均值之类的。

    不同的语义

    话虽如此,我我相当一致地看到clock() is slower:

    #include <ctime>
    #include <chrono>
    
    int main()
    {
        for (size_t i = 0; i < 20000; i++)
    #ifdef CSTYLE
            clock();
    #else
            std::chrono::system_clock::now();
    #endif
    }
    
    g++ -std=c++11 -O2 -Wall -pedantic main.cpp && time ./a.out &&
    g++ -std=c++11 -O2 -Wall -pedantic -DCSTYLE main.cpp && time ./a.out
    real  0m0.027s
    user  0m0.008s
    sys   0m0.016s
    
    real  0m0.038s
    user  0m0.000s
    sys   0m0.036s
    

    我不知道为什么会这样,但因此,比较 elapsed_seconds.count() 和 c_elapsed 并期望对结果做出任何坚定的合理化在很大程度上是愚蠢的。

    【讨论】:

    • 我觉得这不可能已经过去 2 年而不被注意到,但是您上面的数据不是显示 system_clock::now() 更快吗?使用 clock() 的版本需要 0.038 秒,而另一个版本需要 0.027 秒。我错过了什么吗?
    猜你喜欢
    • 2011-03-19
    • 1970-01-01
    • 1970-01-01
    • 2012-08-22
    • 1970-01-01
    • 2021-04-06
    • 2019-03-20
    • 2013-08-18
    • 1970-01-01
    相关资源
    最近更新 更多