# Google Benchmark: 从入门到高手

Google Benchmark 是一个用于 C++ 的微基准测试库，帮助开发者测量代码片段的性能。通过这个库，您可以分析代码在不同输入、数据规模和系统配置下的表现。

# 一、入门使用

### 安装

您可以通过包管理器或从源代码构建安装 Google Benchmark：

1. **使用** `vcpkg` 安装：
    
    ```sh
    vcpkg install benchmark
    ```
    
2. **从源码构建**：
    
    ```sh
    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
    ```
    

### 基本使用

1. **包含头文件**：
    
    ```cpp
    #include <benchmark/benchmark.h>
    ```
    
2. **定义基准测试函数**：
    
    ```cpp
    static void BM_Function(benchmark::State& state) {
        for (auto _ : state) {
            // 在此处放置您要基准测试的代码
        }
    }
    BENCHMARK(BM_Function);
    ```
    
    在 `for (auto _ : state)` 循环中，基准测试函数会多次运行，以获取可靠的测量值。
    
3. **运行基准测试**： 在主函数中使用 `BENCHMARK_MAIN();` 宏来运行所有定义的基准测试。
    
    ```cpp
    BENCHMARK_MAIN();
    ```
    

### 自定义基准测试

1. **传递参数**： 您可以使用 `Args` 或 `Range` 方法传递不同的参数，测试不同的输入规模或条件。
    
    ```cpp
    BENCHMARK(BM_Function)->Arg(8)->Arg(16);
    BENCHMARK(BM_Function)->Range(8, 8<<10);
    ```
    
2. **设置时间单位**： 默认情况下，Google Benchmark 使用 `ns` 作为时间单位。您可以通过 `Unit` 方法更改为其他单位，例如 `ms`。
    
    ```cpp
    BENCHMARK(BM_Function)->Unit(benchmark::kMillisecond);
    ```
    
3. **多线程测试**： 使用 `Threads` 方法指定线程数量，以测试多线程环境下的性能。
    
    ```cpp
    BENCHMARK(BM_Function)->Threads(2);
    ```
    
4. **报告内存使用**： 使用 `MeasureProcessMemory` 方法可以报告基准测试过程中内存的使用情况。
    
    ```cpp
    BENCHMARK(BM_Function)->MeasureProcessMemory();
    ```
    

### 运行与输出

编译并运行基准测试代码，Google Benchmark 将自动处理计时和结果报告。输出结果包括基准测试名称、迭代次数和每次迭代的时间（例如 `ns/op`，`us/op`）。

### 示例

以下是一个简单的示例，测量创建一个空 `std::string` 对象所需的时间：

```cpp
#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` 方法为每个用例注入不同的值：

```cpp
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 会自动生成参数组合并运行测试。

```cpp
// 使用单个参数范围
BENCHMARK(BM_Function)->Range(8, 8<<10);

// 使用多个参数范围
BENCHMARK(BM_Function)->Ranges({{8, 8<<10}, {1, 4}});
```

在这段代码中，第一个 `Range` 测试了 8 到 8&lt;&lt;10 范围内的参数。第二个 `Ranges` 测试了两个参数的所有组合。

### 3\. 使用 `ArgsProduct` 注入参数的笛卡尔积

`ArgsProduct` 可以生成多个参数的笛卡尔积，以覆盖所有可能的参数组合。

```cpp
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` 注入动态生成的测试用例

如果您的测试用例生成逻辑更为复杂，可以通过动态生成测试用例的方式注入：

```cpp
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` 类，允许在每次测试之前设置和清理数据。

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

# 附录

[benchmark user guide](https://github.com/google/benchmark/blob/main/docs/user_guide.md)
