Google Benchmark: 从入门到高手
Google Benchmark 是一个用于 C++ 的微基准测试库,帮助开发者测量代码片段的性能。通过这个库,您可以分析代码在不同输入、数据规模和系统配置下的表现。
一、入门使用
安装
您可以通过包管理器或从源代码构建安装 Google Benchmark:
使用
vcpkg
安装:vcpkg install benchmark
从源码构建:
git clone https://github.com/google/benchmark.git cd benchmark cmake -E make_directory "build" cmake -E chdir "build" cmake .. cmake --build "build" --config Release sudo cmake --build "build" --config Release --target install
基本使用
包含头文件:
#include <benchmark/benchmark.h>
定义基准测试函数:
static void BM_Function(benchmark::State& state) { for (auto _ : state) { // 在此处放置您要基准测试的代码 } } BENCHMARK(BM_Function);
在
for (auto _ : state)
循环中,基准测试函数会多次运行,以获取可靠的测量值。运行基准测试: 在主函数中使用
BENCHMARK_MAIN();
宏来运行所有定义的基准测试。BENCHMARK_MAIN();
自定义基准测试
传递参数: 您可以使用
Args
或Range
方法传递不同的参数,测试不同的输入规模或条件。BENCHMARK(BM_Function)->Arg(8)->Arg(16); BENCHMARK(BM_Function)->Range(8, 8<<10);
设置时间单位: 默认情况下,Google Benchmark 使用
ns
作为时间单位。您可以通过Unit
方法更改为其他单位,例如ms
。BENCHMARK(BM_Function)->Unit(benchmark::kMillisecond);
多线程测试: 使用
Threads
方法指定线程数量,以测试多线程环境下的性能。BENCHMARK(BM_Function)->Threads(2);
报告内存使用: 使用
MeasureProcessMemory
方法可以报告基准测试过程中内存的使用情况。BENCHMARK(BM_Function)->MeasureProcessMemory();
运行与输出
编译并运行基准测试代码,Google Benchmark 将自动处理计时和结果报告。输出结果包括基准测试名称、迭代次数和每次迭代的时间(例如 ns/op
,us/op
)。
示例
以下是一个简单的示例,测量创建一个空 std::string
对象所需的时间:
#include <benchmark/benchmark.h>
static void BM_StringCreation(benchmark::State& state) {
for (auto _ : state) {
std::string empty_string;
}
}
BENCHMARK(BM_StringCreation);
BENCHMARK_MAIN();
在这个例子中,BM_StringCreation
测量了创建空字符串的时间。您可以通过 BENCHMARK_MAIN()
来运行这个基准测试。
二、进阶使用
基准测试的caes如何注入?
在 Google Benchmark 中,您可以通过多种方式将测试用例(cases)注入到基准测试函数中,以测试代码在不同条件下的性能。这些用例通常是通过函数参数或通过 Google Benchmark 提供的专用 API 注入的。以下是几种常见的方法:
1. 使用 Args
注入单个参数
如果您的基准测试需要单个参数,您可以使用 Args
方法为每个用例注入不同的值:
static void BM_Function(benchmark::State& state) {
int param = state.range(0); // 读取参数
for (auto _ : state) {
// 使用参数 param 进行基准测试
}
}
BENCHMARK(BM_Function)->Arg(1)->Arg(2)->Arg(3);
在这个例子中,BM_Function
函数会分别使用 1、2、3 作为参数进行测试。
2. 使用 Range
或 Ranges
注入一系列参数
Range
允许您为一个参数指定范围,而 Ranges
允许您为多个参数指定范围。Google Benchmark 会自动生成参数组合并运行测试。
// 使用单个参数范围
BENCHMARK(BM_Function)->Range(8, 8<<10);
// 使用多个参数范围
BENCHMARK(BM_Function)->Ranges({{8, 8<<10}, {1, 4}});
在这段代码中,第一个 Range
测试了 8 到 8<<10 范围内的参数。第二个 Ranges
测试了两个参数的所有组合。
3. 使用 ArgsProduct
注入参数的笛卡尔积
ArgsProduct
可以生成多个参数的笛卡尔积,以覆盖所有可能的参数组合。
static void BM_Function(benchmark::State& state) {
int param1 = state.range(0);
int param2 = state.range(1);
for (auto _ : state) {
// 使用 param1 和 param2 进行基准测试
}
}
BENCHMARK(BM_Function)->ArgsProduct({{1, 2, 3}, {4, 5}});
在这个例子中,BM_Function
将被分别调用 6 次,每次组合来自 param1
的 [1, 2, 3] 和 param2
的 [4, 5]。
4. 使用 Complexity
注入动态生成的测试用例
如果您的测试用例生成逻辑更为复杂,可以通过动态生成测试用例的方式注入:
static void BM_Function(benchmark::State& state) {
for (auto _ : state) {
// 根据输入动态生成测试用例
std::vector<int> data(state.range(0), 42);
// 测试逻辑
}
}
BENCHMARK(BM_Function)->RangeMultiplier(2)->Range(8, 8<<10)->Complexity();
在这个例子中,BM_Function
会基于输入动态生成一个大小为 state.range(0)
的向量进行测试。
5. 使用 Fixture
为复杂的测试用例设置
对于更复杂的设置,您可以使用 BenchmarkFixture
类,允许在每次测试之前设置和清理数据。
class MyBenchmark : public benchmark::Fixture {
public:
void SetUp(const ::benchmark::State& state) override {
// 设置代码
}
void TearDown(const ::benchmark::State& state) override {
// 清理代码
}
};
BENCHMARK_DEFINE_F(MyBenchmark, BM_Test)(benchmark::State& state) {
for (auto _ : state) {
// 基准测试逻辑
}
}
BENCHMARK_REGISTER_F(MyBenchmark, BM_Test)->Args({8});
这个例子中,SetUp
和 TearDown
会在每次基准测试前后被调用,从而可以设置和清理测试用例。
总结
通过这些方法,您可以灵活地将不同的测试用例注入到 Google Benchmark 的基准测试函数中,以测试不同的输入、配置和场景下代码的性能。
附录
Subscribe to my newsletter
Read articles from wuzhiguocarter directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
wuzhiguocarter
wuzhiguocarter
I am a senior software engineer working on DiDi.