使用 Google 基准测试时返回值会发生什么情况?



我正在使用Google基准测试对我们软件中的某些功能进行基准测试。假设函数签名如下所示。返回类型可以是任何其他派生数据类型。

std::map<uint32_t, bool> func(Obj& o1, Obj& o2);

基准测试函数如下所示。

static void BM_Func(benchmark::State& state) {
// Prepare the objects o1 and o2
for (auto _ : state)
func(Obj& o1, Obj& o2);
}
BENCHMARK(BM_Func);
BENCHMARK_MAIN();

现在,代码编译完毕,我能够收集基准测试结果。但是,我有以下问题。

  1. 返回值会发生什么情况?如果我真的应该被打扰吗 是否不再在基准测试函数中的任何地方使用这些值?
  2. 我应该像这样调用函数benchmark::DoNotOptimize( func(Obj& o1, Obj& o2) );以避免优化吗?我真的不明白什么时候用benchmark::DoNotOptimize调用函数

不使用benchmark::DoNotOptimize的危险在于编译器可能会意识到func绝对没有副作用。然后它会正确地得出结论,您的代码等效于for (auto _ : state) /* do nothing */;.你当然不想什么都衡量。

使用benchmark::DoNotOptimize会阻止编译器实现上述目标。它别无选择,只能实际调用func来获取结果对象(尽管相同的注意事项适用 - 如果它可以内联func并且func总是返回例如true,那么其余的func可能会被优化出来(。

如果返回的对象很大,则销毁它可能需要有意义的时间。由于这发生在代码的基准测试循环中,因此这次将包含在基准测试中。不过,避免这种情况非常重要,并且该函数的任何"真实"用户也必须承担这段时间,因此答案是"这些对象不会发生任何异常情况"。

你必须记住,有"好像规则"。因此,编译器可以对代码执行任何操作,只要执行的可见效果保持不变。

在性能测量的情况下,编译器可能会删除被测函数,因为删除它不会影响执行的可见效果。

因此,建议测试应如下所示:

static void BM_Func(benchmark::State& state) {
// Prepare the objects o1 and o2
for (auto _ : state) {
auto result = func(Obj& o1, Obj& o2);
benchmark::DoNotOptimize(result);
}
}

benchmark::DoNotOptimize将向编译器隐藏结果实际上未使用的事实。

请注意,基准测试必须使用与生产版本完全相同的优化标志来构建。因此,必须启用优化,并且过时的(从编译器的角度来看(代码将被删除。

顺便说一句,有一个很好的在线工具快速工作台,它使用 Google 基准测试,请注意,它还显示程序集结果,以便能够验证编译器优化的内容(以防某些代码被删除(。

最新更新