最简可用的BENCHMARK函数需定义void BM_X(benchmark::State&),用BENCHMARK(BM_X)注册,并在for(auto _: state)循环内执行被测代码;必须调用benchmark::Initialize()和RunSpecifiedBenchmarks()启动框架。

怎么写一个最简可用的 BENCHMARK 函数
直接定义一个带 benchmark::State& 参数的函数,用 BENCHMARK 宏注册,就能跑起来。它不是普通函数调用,而是被 benchmark 框架循环驱动执行的。
常见错误是忘记在循环体里调用 state.PauseTiming() 或 state.ResumeTiming(),导致 setup/teardown 时间混进测量结果;更隐蔽的是没加 state.KeepRunning() 循环,结果只跑了一次,统计无效。
-
BENCHMARK宏会自动生成注册逻辑,不需要手动RegisterBenchmark - 必须在
for (auto _ : state)循环内执行待测代码,这是框架控制迭代和计时的关键 - 若函数内部有初始化开销(如分配内存),应放在循环外,并用
state.PauseTiming()包裹
#include <benchmark/benchmark.h>
static void BM_StringCreation(benchmark::State& state) {
for (auto _ : state) {
std::string s = "hello"; // 被测操作
}
}
BENCHMARK(BM_StringCreation);如何传参并生成多个测试变体
用 BENCHMARK_CAPTURE 或手动调用 benchmark::RegisterBenchmark,避免硬编码参数——否则改个数值就得重编译。
参数类型受限:只支持整数、浮点数、字符串字面量。传指针或自定义类型会编译失败;想测不同容器大小?用 Arg 或 Args 系列方法更稳。
立即学习“C++免费学习笔记(深入)”;
-
Args({N})给单个基准函数绑定一组参数,ArgsProduct可生成笛卡尔积 -
BENCHMARK_CAPTURE适合捕获局部变量,但注意生命周期:变量必须比注册过程活得久(通常定义在 main 前或用 static) - 参数值会出现在报告的 benchmark 名里,比如
BM_VectorPushBack/1024
static void BM_VectorPushBack(benchmark::State& state) {
for (auto _ : state) {
std::vector<int> v;
v.reserve(state.range(0));
for (int i = 0; i < state.range(0); ++i)
v.push_back(i);
}
}
BENCHMARK(BM_VectorPushBack)->Arg(128)->Arg(1024)->Arg(8192);为什么 state.range(0) 返回值总是 0
因为没调用 Arg、Args 或其他参数设置方法,range() 默认无值,访问越界返回 0。这不是 bug,是未初始化状态。
另一个常见原因是用了 Range 但没配 ->RangeMultiplier,导致只生成一个默认值(通常是 1)。调试时可加 std::cerr << state.range(0) << "\n" 看实际传入值,但注意别放在计时循环里。
- 用
Args({x, y, z})显式指定离散值,最不容易出错 -
Range(low, high)配合RangeMultiplier(k)才会生成 log-scaled 序列(如 1, 10, 100) - 如果用
Apply自定义参数逻辑,务必确保 lambda 返回void并正确调用args->Arg(...)
链接时报 undefined reference to `main' 怎么办
Google Benchmark 不提供 main,你得自己写。漏掉 main 或用了 gtest_main 这类替代入口,就会链接失败。
官方推荐方式是调用 benchmark::Initialize + benchmark::RunSpecifiedBenchmarks,不要手写复杂逻辑。如果项目已用 CMake,确认链接了 benchmark::benchmark target 而非仅头文件。
- 必须在
main中调用benchmark::Initialize(&argc, &argv),否则--benchmark_filter等参数不生效 - 若同时用 gtest 和 benchmark,不要链接
gtest_main;二者main冲突 - 静态链接时(
-DBENCHMARK_ENABLE_INSTALL=OFF),确保所有 .cc 文件都参与编译,尤其是benchmark_main.cc(它含默认 main)
int main(int argc, char** argv) {
benchmark::Initialize(&argc, &argv);
benchmark::RunSpecifiedBenchmarks();
}参数解析、计时精度、多线程干扰这些细节,往往比写对语法更影响结果可信度。比如在笔记本上跑,默认可能启 turbo boost,同一段代码前后两次结果差 15% 都正常——真要对比,得关掉频率调节,固定 CPU 绑核,再跑三次取中位数。



















