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 的基准测试函数中,以测试不同的输入、配置和场景下代码的性能。