简单 for 循环中的大量时间损失

A.H*_*tov 5 c++ benchmarking duration microbenchmark c++-chrono

我有一个非常简单的程序来测量一个函数花费了多少时间。

#include <iostream>
#include <vector>
#include <chrono>
struct Foo
{
    void addSample(uint64_t s)
    {
    }
};

void test(const std::vector<uint64_t>& samples)
{
    uint32_t onlyCallTime = 0;
    uint32_t loopOnlyTime = 0;
    Foo stats;
    std::chrono::high_resolution_clock::time_point callStart,callEnd;
    auto start = callStart = callEnd = std::chrono::high_resolution_clock::now();
    for(auto &s : samples)
    {
        callStart = std::chrono::high_resolution_clock::now();
        loopOnlyTime += std::chrono::duration_cast<std::chrono::microseconds>(callStart-callEnd).count();
        stats.addSample(s);
        callEnd = std::chrono::high_resolution_clock::now();
        onlyCallTime += std::chrono::duration_cast<std::chrono::microseconds>(callEnd-callStart).count();
    }
    auto end = std::chrono::high_resolution_clock::now();

    std::cout << "overall duration: " << std::chrono::duration_cast<std::chrono::microseconds>(end-start).count() << std::endl;
    std::cout << "only call duration: " << onlyCallTime << std::endl;
    std::cout << "only loop duration: " << loopOnlyTime << std::endl;
}

int main()
{
    std::vector<uint64_t> dataSetDecreasing;
    for(uint32_t i = 0; i < 1000000; ++i)
        dataSetDecreasing.push_back(1000000-i);
    test(dataSetDecreasing);
}
Run Code Online (Sandbox Code Playgroud)

输出真的很混乱。这里有些例子:

overall duration: 56047
only call duration: 195
only loop duration: 285
Run Code Online (Sandbox Code Playgroud)
overall duration: 40984
only call duration: 177
only loop duration: 243
Run Code Online (Sandbox Code Playgroud)
overall duration: 47328
only call duration: 187
only loop duration: 177
Run Code Online (Sandbox Code Playgroud)

我的看法是它callEnd-callStart捕获了对addSample+ 的调用duration_cast
callStart-callEnd捕获其他所有内容,因此循环初始化、迭代、条件和第二个duration_cast. 我错过了什么?其他 ~40000 微秒去哪里了?

g++ -Wall -Wextra -std=c++17 -O3
g++ (GCC) 10.2.1 20200723 (Red Hat 10.2.1-1)
我的操作系统一起编译的是 Fedora 版本 32(三十二)

Qui*_*mby 12

1 000 000 次迭代大约需要 50 000 微秒。平均而言,每次迭代的std::chrono::duration_cast<std::chrono::microseconds>时间远低于 1?s,并且小于 1?s 的任何时间舍入为 0。这意味着您的循环只计算由于某种原因(调度、页面错误、缓存可能)花费比平均时间更长的迭代。

由于每次测量都有一个与所测量的持续时间(加上其他误差)无关的基本误差,因此进行许多小测量并将它们相加将比测量一次整个持续时间精确得多。

  • 接得好。相反,以纳秒运行它,加起来几乎完全一样 (2认同)