如何在Google Benchmark中实现每次函数调用冷缓存且不计入计时?
冷缓存场景下Google Benchmark的函数计时问题
我正在使用Google Benchmark对函数进行计时,但需要查看其在冷缓存下的性能表现。我知道该基准测试库会反复运行函数直到计时稳定,但希望这个稳定计时能基于冷缓存的场景。我的基准测试代码大致如下:
template <class ...Args> void BM_MyFunc(benchmark::State& state, Args&&... args) { auto args_tuple = std::make_tuple(std::move(args)...); const int arg = std::get<0>(args_tuple); for (auto _ : state) { // flush cache by accessing a huge array for (int i = 0; i < N; i++) { huge_array[i] = rand(); } my_func(arg); } } BENCHMARK_CAPTURE(BM_MyFunc, my_func_with_42, 42);
问题在于将缓存刷新逻辑放在for (auto _ : state)循环内时,缓存刷新操作会被计入计时结果。如果将缓存刷新放在该循环外,则只会刷新一次缓存,基准测试库会将其视为异常情况并预热my_func,导致无法在冷缓存下测试。是否存在一种方式,能实现“每次函数调用前的准备操作”且不计入函数的计时结果?官方文档似乎未覆盖该特定场景。
解决方案:利用PauseTiming()和ResumeTiming()接口
Google Benchmark提供了暂停/恢复计时的API,刚好能满足“准备操作不计入计时”的需求。在缓存刷新前暂停计时,完成刷新后再恢复计时,这样只有目标函数my_func的执行时间会被统计。
修改后的代码如下:
template <class ...Args> void BM_MyFunc(benchmark::State& state, Args&&... args) { auto args_tuple = std::make_tuple(std::move(args)...); const int arg = std::get<0>(args_tuple); for (auto _ : state) { // 暂停计时,准备操作不计入结果 state.PauseTiming(); // 刷新缓存 for (int i = 0; i < N; i++) { huge_array[i] = rand(); } // 恢复计时,开始统计目标函数 state.ResumeTiming(); my_func(arg); } } BENCHMARK_CAPTURE(BM_MyFunc, my_func_with_42, 42);
补充说明
PauseTiming()会立刻停止当前计时周期,ResumeTiming()重新启动计时,两者之间的操作完全不会被计入基准测试的统计数据。- 这种方式既保证了每次调用
my_func前都是冷缓存状态,又不会把缓存刷新的耗时算到目标函数的性能结果里。 - 需确保
huge_array的大小足够覆盖系统各级缓存(比如至少大于L3缓存容量),否则缓存刷新可能不彻底。
内容的提问来源于stack exchange,提问作者rcplusplus
相关产品推荐
相关产品推荐

