如果你正在寻找一款C++性能测试工具,那么此文不容错过。
市面上的benchmark工具或多或少存在一些使用上的不方便,那么是否存在一个使用简便又功能强大的性能测试工具呢?答案是google/benchmark 。
google/benchmark是一个由Google开发的基于googletest框架的C++ benchmark工具,它易于安装和使用,并提供了全面的性能测试接口。
下面来介绍google/benchmark的安装并用一个简短的例子介绍它的简单实用。
安装google/benchmark google/benchmark基于C++11标准和googletest框架,所以安装前需要先做一些准备工作。
首先是g++和cmake
1 sudo apt install g++ cmake 
 
确保你的g++版本在5.0以上,否则可能不能很好的支持C++11的某些特性。
然后是googletest框架,你可以选择单独安装,不过这里我选择将其作为benchmark源码树的依赖而不单独安装它,因为benchmark在编译安装时需要googletest,但是在使用时并不需要。
选择一个合适的目录,然后运行下面的命令:
1 2 3 4 5 6 7 git clone https://github.com/google/benchmark.git git clone https://github.com/google/googletest.git benchmark/googletest mkdir build && cd  build cmake -DCMAKE_BUILD_TYPE =RELEASE ../benchmark make -j4  sudo make install 
 
头文件会被安装到/usr/local/include,库文件会被安装到/usr/local/lib。
安装完成之后,来看一下benchmark如何使用。
google/benchmark的简单使用 这个例子将会对比三种访问std::array容器内元素方法的性能,进行演示benchmark的使用方法。
先看代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 #include  <benchmark/benchmark.h>  #include  <array>    constexpr  int  len = 6 ;  constexpr  auto  my_pow (const  int  i)  {    return  i * i; }   static  void  bench_array_operator (benchmark::State& state)  {    std::array<int , len> arr;     constexpr  int  i = 1 ;     for  (auto  _: state) {         arr[0 ] = my_pow (i);         arr[1 ] = my_pow (i+1 );         arr[2 ] = my_pow (i+2 );         arr[3 ] = my_pow (i+3 );         arr[4 ] = my_pow (i+4 );         arr[5 ] = my_pow (i+5 );     } } BENCHMARK (bench_array_operator);  static  void  bench_array_at (benchmark::State& state)  {    std::array<int , len> arr;     constexpr  int  i = 1 ;     for  (auto  _: state) {         arr.at (0 ) = my_pow (i);         arr.at (1 ) = my_pow (i+1 );         arr.at (2 ) = my_pow (i+2 );         arr.at (3 ) = my_pow (i+3 );         arr.at (4 ) = my_pow (i+4 );         arr.at (5 ) = my_pow (i+5 );     } } BENCHMARK (bench_array_at);  static  void  bench_array_get (benchmark::State& state)  {    std::array<int , len> arr;     constexpr  int  i = 1 ;     for  (auto  _: state) {         std::get<0 >(arr) = my_pow (i);         std::get<1 >(arr) = my_pow (i+1 );         std::get<2 >(arr) = my_pow (i+2 );         std::get<3 >(arr) = my_pow (i+3 );         std::get<4 >(arr) = my_pow (i+4 );         std::get<5 >(arr) = my_pow (i+5 );     } } BENCHMARK (bench_array_get);  BENCHMARK_MAIN ();
 
可以看到每一个benchmark测试用例都是一个类型为std::function<void(benchmark::State&)>的函数,其中benchmark::State&负责测试的运行及额外参数的传递。
随后我们使用for(auto _ : state) {}来运行需要测试的内容,state会选择合适的次数来运行循环,时间的计算从循环内的语句开始,所以我们可以选择像例子中一样在for循环之外初始化测试环境,然后再循环体内编写需要测试的代码。
测试用例编写完成之后我们需要使用BENCHMARK(<function_name>);将我们的测试用例注册进benchmark,这样程序运行时才会执行我们的测试。
最后用BENCHMARK_MAIN();替代直接编写的main函数,它会处理命令行参数并运行所有注册过的测试用例生成测试结果。
示例中大量使用了constexpt,这时为了能再编译期计算出需要的数值避免对测试产生太多噪音。
编译测试程序:
1 g++ -Wall  -std =c++14  benchmark_example.cpp -pthread  -lbenchmark  
 
benchmark需要链接libbenchmark.so,所以需要指定-lbenchmark,此外还需要thread的支持,因为libstdc++不提供thread的底层实现,我们需要pthread。
运行测试程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 2022-05-11T17:17:16+08:00 Running ./a.out Run on (24 X 3800 MHz CPU s) CPU Caches:   L1 Data 32 KiB (x12)   L1 Instruction 32 KiB (x12)   L2 Unified 512 KiB (x12)   L3 Unified 16384 KiB (x4) Load Average: 2.91, 3.07, 3.10 ***WARNING*** CPU scaling is enabled, the benchmark real time measurements may be noisy and will incur extra overhead. --------------------------------------------------------------- Benchmark                     Time             CPU   Iterations --------------------------------------------------------------- bench_array_operator       19.8 ns         19.8 ns     35558602 bench_array_at             19.8 ns         19.8 ns     35103622 bench_array_get            20.2 ns         20.1 ns     34736601 
 
显示的警告信息表示在当前系统环境有一些噪音可能导致结果不太准确,并不影响我们的测试。
测试结果与预期基本相符,std::get最快,at()最慢。