代码性能测试——benchmark库
在平常的代码开发中,我们一般用
googletest
做单元测试用例,如果需要对代码如某个函数的执行时间或效率进行测量,一般用benchmark
。
目录
- 1.benchmark 安装
- 2.benchmark 介绍
- 2.1 示例
- 2.2 benchmark 测试说明
- 2.3 benchmark 计时
- 3.示例
- 测试kdTree()耗时
- 测量排序算法性能
benchmark 是一个用于性能测试和基准测试的库。它主要用于测量代码执行的时间、效率等性能指标,帮助开发者评估不同实现之间的效率差异,或者测试特定代码片段在不同环境下的表现。
具体来说,benchmark 的作用包括:
- 性能测量:能够精确测量代码的执行时间,可以帮助开发者识别性能瓶颈。
- 比较不同实现:通过对比多个实现的执行时间,帮助开发者选择最优方案。
- 自动化基准测试:自动执行测试,减少人工干预,可以用于自动化性能评估。
- 准确性:通过多次运行来消除偶然的误差,提供更稳定的数据。
1.benchmark 安装
- 下载 benchmark 库
https://github.com/google/benchmark.git
- 编译 benchmark 库
创建一个构建目录并使用CMake进行编译和安装:
git clone https://github.com/google/benchmark.git
git clone https://github.com/google/googletest.git benchmark/googletest # 因为编译benchmark需要googletestcd benchmark
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
sudo make install # 安装到系统目录下
2.benchmark 介绍
2.1 示例
#include <benchmark/benchmark.h>static void BM_SomeFunction(benchmark::State& state) {
// 在此处执行设置
for (auto _ : state) {// 此代码获得计时SomeFunction();benchmark::DoNotOptimize();}}// 将该函数作为benchmark
BENCHMARK(BM_SomeFunction);
// 运行benchmark测试
BENCHMARK_MAIN();
benchmark::State& state
:是 Google Benchmark 提供的一个状态对象,用于控制测试的执行。state 管理测试循环,保证代码在性能测试过程中多次执行,以获得稳定的性能结果。for (auto _ : state)
:是一个范围循环,benchmark::State 对象提供了类似范围的迭代支持。该循环将根据 Google Benchmark 自动确定的迭代次数运行测试代码,直到Google Benchmark认为已经收集到足够的数据为止。这种结构确保每次运行都具有相同的执行环境,帮助减少外部噪声带来的影响。benchmark::DoNotOptimize()
:是 Google Benchmark 提供的一个工具函数,用来防止编译器对测试代码进行优化。以确保测试中的代码不会被跳过或优化掉。这样可以确保测试结果更接近真实性能。BENCHMARK(BM_SomeFunction)
:这行代码注册了定义的 BM_SomeFunction 的benchmark测试,让 Google Benchmark 能够在主函数中自动调用。BENCHMARK_MAIN()
:是 Google Benchmark 的主函数入口,它会自动运行所有注册的benchmark测试。
2.2 benchmark 测试说明
在 for (auto _ : state)
循环中插入想要测试的代码,Benchmark 会多次执行该代码,并统计每次运行的时间,最终输出平均执行时间、CPU时间等。
默认情况下,Benchmark会自动测量每次迭代的时间。但有时可能需要排除一些准备工作的时间,可以使用state.PauseTiming()
和state.ResumeTiming()
来暂停和恢复计时:
for (auto _ : state) {state.PauseTiming();// 不需要计入时间的函数SomeFunctionNoTimekeeping();state.ResumeTiming();SomeFunction();
}
2.3 benchmark 计时
Benchmark 库使用标准库中的 std::chrono
提供的高精度时钟(通常是 std::chrono::high_resolution_clock
)来进行计时。这是C++中的高精度时钟,通常提供纳秒级别的精度,在运行代码之前和之后记录时钟时间,计算代码执行所耗费的时间。
Benchmark 的 State 类会控制迭代次数,并在性能测试开始和结束时调用时钟进行时间测量。
benchmark::State
会自动控制测试运行的起始时间、迭代次数和循环。在测试完成后,Benchmark 会汇总这些数据,输出迭代次数、平均执行时间等性能指标。
3.示例
测试kdTree()耗时
#include <pcl/console/time.h>
#include <pcl/point_cloud.h> //点类型定义头文件
#include <pcl/kdtree/kdtree_flann.h> //kdtree类定义头文件int kdTreeTest()
{srand(time(NULL)); //用系统时间初始化随机种子//创建一个PointCloud<pcl::PointXYZ>pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);// 随机点云生成cloud->width = 1000; //此处点云数量cloud->height = 1; //表示点云为无序点云cloud->points.resize(cloud->width * cloud->height);for (size_t i = 0; i < cloud->points.size(); ++i) //循环填充点云数据{cloud->points[i].x = 1024.0f * rand() / (RAND_MAX + 1.0f); // // 产生数值为0-1024的浮点数cloud->points[i].y = 1024.0f * rand() / (RAND_MAX + 1.0f);cloud->points[i].z = 1024.0f * rand() / (RAND_MAX + 1.0f);}//创建KdTreeFLANN对象,并把创建的点云设置为输入,创建一个searchPoint变量作为查询点pcl::KdTreeFLANN<pcl::PointXYZ> kdtree; // pcl::KdTreeFLANN<PointT, Dist>::setInputCloud (const PointCloudConstPtr// &cloud, const IndicesConstPtr &indices)//设置搜索空间kdtree.setInputCloud(cloud);//设置查询点并赋随机值pcl::PointXYZ searchPoint;searchPoint.x = 1024.0f * rand() / (RAND_MAX + 1.0f);searchPoint.y = 1024.0f * rand() / (RAND_MAX + 1.0f);searchPoint.z = 1024.0f * rand() / (RAND_MAX + 1.0f);// K 临近搜索//创建一个整数(设置为10)和两个向量来存储搜索到的K近邻,两个向量中,一个存储搜索到查询点近邻的索引,另一个存储对应近邻的距离平方int K = 10;std::vector<int> pointIdxNKNSearch(K); //存储查询点近邻索引std::vector<float> pointNKNSquaredDistance(K); //存储近邻点对应距离平方//打印相关信息std::cout << "K nearest neighbor search at (" << searchPoint.x << " " << searchPoint.y << " " << searchPoint.z<< ") with K=" << K << std::endl;if (kdtree.nearestKSearch(searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0) //执行K近邻搜索{//打印所有近邻坐标for (size_t i = 0; i < pointIdxNKNSearch.size(); ++i)std::cout << " " << cloud->points[pointIdxNKNSearch[i]].x << " " << cloud->points[pointIdxNKNSearch[i]].y<< " " << cloud->points[pointIdxNKNSearch[i]].z<< " (squared distance: " << pointNKNSquaredDistance[i] << ")" << std::endl;}/**********************************************************************************下面的代码展示查找到给定的searchPoint的某一半径(随机产生)内所有近邻,重新定义两个向量pointIdxRadiusSearch pointRadiusSquaredDistance来存储关于近邻的信息********************************************************************************/// 半径 R内近邻搜索方法std::vector<int> pointIdxRadiusSearch; //存储近邻索引std::vector<float> pointRadiusSquaredDistance; //存储近邻对应距离的平方float radius = 256.0f * rand() / (RAND_MAX + 1.0f); //随机的生成某一半径//打印输出std::cout << "Neighbors within radius search at (" << searchPoint.x << " " << searchPoint.y << " " << searchPoint.z<< ") with radius=" << radius << std::endl;// 假设我们的kdtree返回了大于0个近邻。那么它将打印出在我们"searchPoint"附近的10个最近的邻居并把它们存到先前创立的向量中。if (kdtree.radiusSearch(searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) >0) //执行半径R内近邻搜索方法{for (size_t i = 0; i < pointIdxRadiusSearch.size(); ++i)std::cout << " " << cloud->points[pointIdxRadiusSearch[i]].x << " "<< cloud->points[pointIdxRadiusSearch[i]].y << " " << cloud->points[pointIdxRadiusSearch[i]].z<< " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;}return 0;
}#include <benchmark/benchmark.h>
#include <gtest/gtest.h>static void BM_Kdtree(benchmark::State &state)
{// 运行基准测试for (auto _ : state) {kdTreeTest();}
}
// 注册基准测试
BENCHMARK(BM_Kdtree);BENCHMARK_MAIN();
输出:
测量排序算法性能
#include <benchmark/benchmark.h>
#include <vector>
#include <algorithm>// 选择排序算法
void selectionSort(std::vector<int>& arr) {for (size_t i = 0; i < arr.size(); ++i) {size_t minIdx = i;for (size_t j = i + 1; j < arr.size(); ++j) {if (arr[j] < arr[minIdx]) {minIdx = j;}}std::swap(arr[i], arr[minIdx]);}
}// 快速排序算法
void quickSort(std::vector<int>& arr, int low, int high) {if (low < high) {int pivot = arr[high];int i = low - 1;for (int j = low; j < high; ++j) {if (arr[j] < pivot) {++i;std::swap(arr[i], arr[j]);}}std::swap(arr[i + 1], arr[high]);int pi = i + 1;quickSort(arr, low, pi - 1);quickSort(arr, pi + 1, high);}
}// 基准测试函数,使用 Google Benchmark 库
static void BM_SelectionSort(benchmark::State& state) {std::vector<int> arr = {5, 2, 9, 1, 5, 6};for (auto _ : state) {selectionSort(arr);}
}// 快速排序基准测试
static void BM_QuickSort(benchmark::State& state) {std::vector<int> arr = {5, 2, 9, 1, 5, 6};for (auto _ : state) {quickSort(arr, 0, arr.size() - 1);}
}// 注册基准测试
BENCHMARK(BM_SelectionSort);
BENCHMARK(BM_QuickSort);// 定义测试入口
BENCHMARK_MAIN();
输出:
2025-08-24T22:37:58+08:00
Running ./three_dim_test
Run on (20 X 4600 MHz CPU s)
CPU Caches:L1 Data 48 KiB (x10)L1 Instruction 32 KiB (x10)L2 Unified 1280 KiB (x10)L3 Unified 24576 KiB (x1)
Load Average: 0.88, 0.85, 0.80
-----------------------------------------------------------
Benchmark Time CPU Iterations
-----------------------------------------------------------
BM_SelectionSort 160 ns 160 ns 4371089
BM_QuickSort 217 ns 218 ns 3213221