在使用Google Benchmark框架检查我的基准测试的输出时,我观察到在许多情况下测量的 cpu 时间的标准偏差明显大于测量的实时标准偏差。
这是为什么?还是由于测量误差导致的结果?我对此感到非常惊讶,因为我预计 cpu 时间更具可重复性。
这是对我系统的一般观察。尽管如此,我还是提供了一个简单的例子:
#include <benchmark/benchmark.h>
#include <cmath>
static void BM_SineEvaluation(benchmark::State& state)
{
for (auto _ : state)
{
double y = 1.0;
for (size_t i = 0; i < 100; ++i)
{
y *= std::sin(y) * std::sin(y) + std::cos(y) * std::cos(y);
y+= std::sin(std::cos(y));
}
benchmark::DoNotOptimize(y);
}
}
BENCHMARK(BM_SineEvaluation);
该示例甚至不包含堆分配。编译器没有优化任何 sin/cos 函数。这就是所有的代码。时间测量完全在 Google Benchmark 库中完成,该库可在 github 上公开获得。但到目前为止我还没有研究过实现。
当使用命令行参数 --benchmark_repetitions=50 --benchmark_report_aggregates_only=true 运行程序时,我得到如下输出:
----------------------------------------------------------------
Benchmark Time CPU Iterations
----------------------------------------------------------------
BM_SineEvaluation_mean 11268 ns 11270 ns 64000
BM_SineEvaluation_median 11265 ns 11230 ns 64000
BM_SineEvaluation_stddev 11 ns 90 ns 64000
我在带有 Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24218.1 for x86 (Visual Studio 2015) 和 /O2 的非常旧的 Intel Core i7 920 (Bloomfield) 上使用 Google Benchmark v1.4.1。
编辑:我在 Intel i5-4300U CPU 和 gcc-8.1.1 上对 Fedora-28 做了进一步的测量(它足够聪明,可以用 -O2 调用 sincos),并发现了一个对比的行为:
----------------------------------------------------------------
Benchmark Time CPU Iterations
----------------------------------------------------------------
BM_SineEvaluation_mean 54642 ns 54556 ns 12350
BM_SineEvaluation_median 54305 ns 54229 ns 12350
BM_SineEvaluation_stddev 946 ns 888 ns 12350
当省略 -O2 时(更接近 MSVC,因为它有单独的 sin/cos 调用),我仍然得到相同的定性结果:实时的标准偏差也大于 cpu 时间的标准偏差。
我不太确定从中得出什么结论。这是否意味着 Windows 上的时间测量不那么精确?