Skip to main content

Command Palette

Search for a command to run...

Google Benchmark: 从入门到高手

Updated
2 min read
Google Benchmark: 从入门到高手
W

I am a senior software engineer working on DiDi.

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

一、入门使用

安装

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

  1. 使用 vcpkg 安装:

     vcpkg install benchmark
    
  2. 从源码构建

     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. 包含头文件

     #include <benchmark/benchmark.h>
    
  2. 定义基准测试函数

     static void BM_Function(benchmark::State& state) {
         for (auto _ : state) {
             // 在此处放置您要基准测试的代码
         }
     }
     BENCHMARK(BM_Function);
    

    for (auto _ : state) 循环中,基准测试函数会多次运行,以获取可靠的测量值。

  3. 运行基准测试: 在主函数中使用 BENCHMARK_MAIN(); 宏来运行所有定义的基准测试。

     BENCHMARK_MAIN();
    

自定义基准测试

  1. 传递参数: 您可以使用 ArgsRange 方法传递不同的参数,测试不同的输入规模或条件。

     BENCHMARK(BM_Function)->Arg(8)->Arg(16);
     BENCHMARK(BM_Function)->Range(8, 8<<10);
    
  2. 设置时间单位: 默认情况下,Google Benchmark 使用 ns 作为时间单位。您可以通过 Unit 方法更改为其他单位,例如 ms

     BENCHMARK(BM_Function)->Unit(benchmark::kMillisecond);
    
  3. 多线程测试: 使用 Threads 方法指定线程数量,以测试多线程环境下的性能。

     BENCHMARK(BM_Function)->Threads(2);
    
  4. 报告内存使用: 使用 MeasureProcessMemory 方法可以报告基准测试过程中内存的使用情况。

     BENCHMARK(BM_Function)->MeasureProcessMemory();
    

运行与输出

编译并运行基准测试代码,Google Benchmark 将自动处理计时和结果报告。输出结果包括基准测试名称、迭代次数和每次迭代的时间(例如 ns/opus/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. 使用 RangeRanges 注入一系列参数

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});

这个例子中,SetUpTearDown 会在每次基准测试前后被调用,从而可以设置和清理测试用例。

总结

通过这些方法,您可以灵活地将不同的测试用例注入到 Google Benchmark 的基准测试函数中,以测试不同的输入、配置和场景下代码的性能。

附录

benchmark user guide

More from this blog

私有云存储的解决方案选型全攻略

选择私有云存储方案时,需要考虑多个因素,包括易用性、功能、安全性、可扩展性、成本、社区支持等。以下是你提到的几个私有云存储方案的简要比较: Filerun 特点:界面类似Google Drive,支持WebDAV,提供文件同步和分享功能。 优势:用户友好的界面,易于设置和使用。 劣势:功能相比其他一些解决方案可能较少,且为闭源软件。 KodBox 特点:基于Seafile的企业级文件同步和分享解决方案,支持私有部署。 优势:强大的文件同步功能,支持文件版本控制和权限管理。 劣...

Oct 26, 20242 min read

最佳实践:如何工程化你的c++项目

工程化一个C++项目涉及许多方面,包括项目结构、构建系统、依赖管理、代码风格、测试、CI/CD(持续集成/持续部署)等。以下是一些最佳实践,帮助你工程化你的C++项目: 一、最佳实践参考规范 1. 组织项目结构 清晰的目录结构:为源代码、头文件、测试、文档、和构建文件分别创建目录。例如: /project-root ├── src/ # 源代码 ├── include/ # 头文件 ├── tests/ # 测试代码 ├── doc...

Aug 30, 20243 min read
最佳实践:如何工程化你的c++项目

最佳实践:如何工程化你的Python项目

在管理Python工程项目时,采用最佳实践能够提高代码质量、可维护性和协作效率。以下是一些推荐的Python工程项目管理最佳实践: 一、最佳实践参考规范 1. 项目结构 一个清晰的项目结构有助于组织代码和文件,使项目易于理解和导航。通常的项目结构如下: project-name/ │ ├── src/ # 源代码目录 │ └── package_name/ # 项目主包 │ ├── __init__.py │ ├── module1....

Aug 30, 20243 min read
最佳实践:如何工程化你的Python项目

Google Test:从入门到高手

Google Test(简称GTest)是一个由Google开发的C++测试框架,广泛用于单元测试。以下是从入门到高手的学习路径,涵盖基本使用到高级技巧。 一、入门阶段 安装与配置 安装Google Test库。 在CMake项目中集成Google Test,简单配置编译环境。 使用find_package(GTest)或手动编译Google Test源码。 编写简单测试 测试案例:使用TEST宏编写简单的测试案例。 断言(Assertions):学习EXPECT_EQ、ASS...

Aug 25, 20241 min read
Google Test:从入门到高手

Untitled Publication

15 posts