Ola*_*laf 2 c++ benchmarking timing
我编写了一个计时函数,记录了函数的运行时间,并计算了多次运行的均值和标准差。我惊讶地发现即使是看似简单的任务(例如加两个双打)也有很高的标准偏差。我分析了python中的数据(请参见图)。C ++输出是19.6171 ns +/- 21.9653ns (82799807 runs)使用以下命令编译的:
gcc version 8.3.0 (Debian 8.3.0-19)
/usr/bin/c++ -O3 -DNDEBUG -std=gnu++17
Run Code Online (Sandbox Code Playgroud)
整个测试是在我的个人计算机上完成的,该计算机不是空闲的而是运行DE,浏览器,IDE和其他进程。测试期间有可用的RAM。我的带有HT的双核CPU空闲率低于10%。
在这种情况下,是否会出现从20 ns的平均值到50 µs的峰值?
运行时间图
这是的内容std::vector<double> run_times。我没有看到任何图案。

定时
gcc version 8.3.0 (Debian 8.3.0-19)
/usr/bin/c++ -O3 -DNDEBUG -std=gnu++17
Run Code Online (Sandbox Code Playgroud)
计时文件
#include <cstdint>
#include <ostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <chrono>
#include <numeric>
#include <fstream>
struct TimingResults{
// all time results are in nanoseconds
double mean;
double standard_deviation;
uint64_t number_of_runs;
};
std::ostream& operator<<(std::ostream& os, const TimingResults& results);
template <typename InputIterator>
std::pair<typename InputIterator::value_type, typename InputIterator::value_type>
calculate_mean_and_standard_deviation(InputIterator first, InputIterator last){
double mean = std::accumulate(first, last, 0.) / std::distance(first, last);
double sum = 0;
std::for_each(first, last, [&](double x){sum += (x - mean) * (x - mean);});
return {mean, std::sqrt(sum / (std::distance(first, last) - 1))};
}
template<uint64_t RunTimeMilliSeconds = 4000, typename F, typename... Args>
TimingResults measure_runtime(F func, Args&&... args){
std::vector<double> runtimes;
std::chrono::system_clock::time_point b;
auto start_time = std::chrono::high_resolution_clock::now();
do {
auto a = std::chrono::high_resolution_clock::now();
func(std::forward<Args>(args)...);
b = std::chrono::high_resolution_clock::now();
runtimes.push_back(std::chrono::duration_cast<std::chrono::nanoseconds>(b - a).count());
} while (std::chrono::duration_cast<std::chrono::milliseconds>(b-start_time).count() <= RunTimeMilliSeconds);
auto [mean, std_deviation] = calculate_mean_and_standard_deviation(runtimes.begin(), runtimes.end());
return {mean, std_deviation, runtimes.size()};
}
Run Code Online (Sandbox Code Playgroud)
main.cpp
#include <iostream>
#include "timing.h"
std::ostream& operator<<(std::ostream& os, const TimingResults& results){
return os << results.mean << " ns" << " +/- " << results.standard_deviation << "ns ("
<< results.number_of_runs << " runs)";
}
Run Code Online (Sandbox Code Playgroud)
现代的CPU可以轻松执行大约10 ^ 9 FLOPS的数量级,即,一次操作的预期时间低于1 ns。但是,这指的是峰值性能。对于大多数实际工作负载,由于内存和缓存的影响,性能将大大降低。
基准测试的问题在于您正在安排单个操作的时间。获取时间点的开销a和b可能简单地超过你实际上是试图测量的时间。此外,甚至std::chrono::high_resolution_clock不会为您提供皮秒级的精度(尽管从原理上讲,实现方式和硬件有关)。明显的解决方法是执行操作N时间,然后将时间除以N。在某个时候,您会看到结果变得一致。(随时发布您的结果。)
TL; DR:您正在尝试使用怀表计时闪电。