【问题标题】:Best accurate way to measure/compare elapsed time in C++在 C++ 中测量/比较经过时间的最佳准确方法
【发布时间】:2022-07-06 09:06:23
【问题描述】:

我为什么要写这篇文章?

  • 因为这是一个需要仔细解决的大问题
  • 而且由于有很多人在时间测量方面遇到问题以改进他们的代码

那么让我向您展示在 C++ 代码中测量时间的完美方法


场景

假设我有一个自定义函数,可以找到一个数字的 地板平方根

int floorSqrt(int x)
{
    if (x <= 1) return x;
    int i = 1, result = 1;
    while (result <= x) { i++; result = i * i; }
    return i - 1;
}

而且我知道&lt;cmath&gt;库中的函数floor(sqrt(x))可以使用!

但我很关心时间性能,我想知道哪个函数执行的时间更长?

于是我搜索了很多,找到了一个原始的解决方案!

这是计算每个函数在其begin和end处的时间并计算difference

#include <chrono>

int num = 20221;

// measure time for floorSqrt(x)
auto begin1 = std::chrono::steady_clock::now();
floorSqrt(num);
auto end1 = std::chrono::steady_clock::now();
auto time1 = std::chrono::duration_cast<std::chrono::nanoseconds> (end1 - begin1).count();

// measure time for floor(sqrt(num))
auto begin2 = std::chrono::steady_clock::now();
floor(sqrt(num));
auto end2 = std::chrono::steady_clock::now();
auto time2 = std::chrono::duration_cast<std::chrono::nanoseconds> (end2 - begin2).count();

// print results
std::cout << "floorSqrt ("<< num << ") : "  << time1 << std::endl;
std::cout << "floor(sqrt("<< num << ")): "  << time2 << std::endl;

输出

floorSqrt (20221) : 130180
floor(sqrt(20221)): 18013

太好了,现在我知道floor(sqrt(x)) 快112167 纳秒!

但是让我们重复这个测试 10 次,看看结果

for (size_t i = 0; i < 10; i++)
{
    /* previous code */
}

输出

floorSqrt (20221) : 131491
floor(sqrt(20221)): 130523
floorSqrt (20221) : 1952
floor(sqrt(20221)): 2078
floorSqrt (20221) : 1495
floor(sqrt(20221)): 1825
floorSqrt (20221) : 1460
floor(sqrt(20221)): 1823
floorSqrt (20221) : 1454
floor(sqrt(20221)): 1716
floorSqrt (20221) : 1464
floor(sqrt(20221)): 1720
floorSqrt (20221) : 1498
floor(sqrt(20221)): 1762
floorSqrt (20221) : 1453
floor(sqrt(20221)): 1706
floorSqrt (20221) : 1432
floor(sqrt(20221)): 1730
floorSqrt (20221) : 1461
floor(sqrt(20221)): 1727

哪个是正确的测试?!!!


问题

测量和比较执行时间的理想且准确的方法是什么?

【问题讨论】:

    标签: c++ performance benchmarking


    【解决方案1】:

    解决方案

    在这种情况下,解决方案非常简单!

    1. 循环n次的代码
    2. 将所有结果存储在数组中
    3. 在数组中求中位数
    4. 比较两个函数的中值结果

    当然没那么容易,需要考虑很多很多细节!

    幸运的是,C++ Timeit library 可以准确、正确地完成这些事情!


    如何测量 C++ 函数的执行时间?

    #include "timeit.hpp"
    
    std::cout << timeit(1000, floorSqrt, num).nanoseconds() << std::endl;
    

    输出

    5537
    

    不确定准确性?

    那么让我们使用repeatit函数重复测试10次,看看结果

    repeatit(10,[]{ std::cout << timeit(1000, floorSqrt, num).nanoseconds() << std::endl; });
    

    输出

    5648
    5641
    5667
    5679
    5691
    5634
    5695
    5664
    5747
    5644
    

    当然由于其他原因结果不会一样,但比正常测试要好很多


    如何比较两个函数的执行时间?

    int func1(){ return floorSqrt(num);   }
    int func2(){ return floor(sqrt(num)); }
    repeatit(10,[]{ compareit(1000, func1, func2); });
    

    输出

    [COMPARE IT] first(5827) > second(1770) x3 
    [COMPARE IT] first(5825) > second(1762) x3 
    [COMPARE IT] first(5825) > second(1764) x3 
    [COMPARE IT] first(5832) > second(1765) x3 
    [COMPARE IT] first(5830) > second(1761) x3 
    [COMPARE IT] first(5836) > second(1768) x3 
    [COMPARE IT] first(5824) > second(1767) x3 
    [COMPARE IT] first(5831) > second(1768) x3 
    [COMPARE IT] first(5822) > second(1762) x3 
    [COMPARE IT] first(5828) > second(1765) x3 
    

    获得高精度的提示

    • 不要像vscode那样在IDE中运行测试
    • 使用valgrind之类的东西在终端中运行它

    这样,我们就得到了两个函数之间真正的区别,并准确地比较了它们

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-22
      • 1970-01-01
      • 2017-03-08
      • 2022-01-23
      相关资源
      最近更新 更多