简单 for 循环中的大量时间损失
Massive time loss in simple for loop
我有一个非常简单的程序来测量一个函数花费了多少时间。
#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);
}
输出真的很混乱。以下是一些示例:
overall duration: 56047
only call duration: 195
only loop duration: 285
overall duration: 40984
only call duration: 177
only loop duration: 243
overall duration: 47328
only call duration: 187
only loop duration: 177
我怎么看 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)
我的 OS 是 Fedora 发行版 32(三十二)
1 000 000 次迭代大约需要 50 000 微秒。这平均每次迭代不到 1μs,std::chrono::duration_cast<std::chrono::microseconds>
会将小于 1μs 的任何时间四舍五入到 0。这意味着您的循环只计算由于某种原因(调度、页面错误、可能是缓存)花费的时间比平均时间长的迭代次数。
由于每次测量都有一个与测量的持续时间无关的基本误差(加上其他误差),因此进行许多小的测量并将它们相加会比测量整个持续时间一次精确得多。
我有一个非常简单的程序来测量一个函数花费了多少时间。
#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);
}
输出真的很混乱。以下是一些示例:
overall duration: 56047
only call duration: 195
only loop duration: 285
overall duration: 40984
only call duration: 177
only loop duration: 243
overall duration: 47328
only call duration: 187
only loop duration: 177
我怎么看 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)
我的 OS 是 Fedora 发行版 32(三十二)
1 000 000 次迭代大约需要 50 000 微秒。这平均每次迭代不到 1μs,std::chrono::duration_cast<std::chrono::microseconds>
会将小于 1μs 的任何时间四舍五入到 0。这意味着您的循环只计算由于某种原因(调度、页面错误、可能是缓存)花费的时间比平均时间长的迭代次数。
由于每次测量都有一个与测量的持续时间无关的基本误差(加上其他误差),因此进行许多小的测量并将它们相加会比测量整个持续时间一次精确得多。