构建集成
在robotic_arm的third_party已经集成了benchmark,只需在相关测试用例代码的CmakeLists.txt添加如下内容:
target_link_libraries(xxx PRIVATE benchmark pthread)
Demo样例
存在以下模式样例:
1. 使用BENCHMARK、BENCHMARK_MAIN宏
#include <benchmark/benchmark.h>
#include <chrono>
#include <thread>
void BM_DemoSleep(benchmark::State& state) {
for (auto _ : state){
}
}
BENCHMARK(BM_DemoSleep);
BENCHMARK_MAIN();
2. 直接使用Benchmark相应的接口
#include <benchmark/benchmark.h>
#include <chrono>
#include <thread>
void BM_DemoSleep(benchmark::State& state) {
for (auto _ : state){
std::this_thread::sleep_for(std::chrono::nanoseconds(1000));
}
}
void BM_DemoSleep1(benchmark::State& state, int id) {
std::cout << "id:"<< id << std::endl;
for (auto _ : state){
std::this_thread::sleep_for(std::chrono::nanoseconds(1000));
}
}
int main(int argc, char** argv) {
::benchmark::Initialize(&argc, argv);
if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
::benchmark::RegisterBenchmark("BM_DemoSleep", &BM_DemoSleep);
::benchmark::RegisterBenchmark("BM_DemoSleep1", [](benchmark::State& state){
for (auto _ : state){
std::this_thread::sleep_for(std::chrono::nanoseconds(1000));
}
});
int id = 10;
::benchmark::RegisterBenchmark("BM_DemoSleep2", &BM_DemoSleep1, id);
::benchmark::RunSpecifiedBenchmarks();
::benchmark::Shutdown();
}
3. 使用Fixture
class BMDemo : public benchmark::Fixture {
public:
void SetUp(const benchmark::State& state) {
id_ = 2;
}
void TearDown(const ::benchmark::State& state) {
id_ = 0;
}
int GetId() const {return id_;};
private:
int id_{0};
};
BENCHMARK_F(BMDemo, Test0)(benchmark::State& state) {
for (auto _ : state) {
std::this_thread::sleep_for(std::chrono::milliseconds(GetId()));
}
}
BENCHMARK_F(BMDemo, Test1)(benchmark::State& state) {
for (auto _ : state) {
std::this_thread::sleep_for(std::chrono::milliseconds(GetId()));
}
}
原理:BENCHMARK_F(BMDemo, Test0)(benchmark::State& state){},会创建一个BMDemo_Test0_Benchmark的类,继承至BMDemo,然后实现BMDemo_Test0_Benchmark::BenchmarkCase(benchmark::State& state){}成员函数;在Fixture的Run方法中会一次调用SetUp->BenchmarkCase->TearDown
配置参数
1. Arg参数
接口名称 | 作用 |
---|
Benchmark* Arg(int64_t x); | 向Benchmark对象的std::vector<std::vector<int64_t> > args_添加一个元素(元素为vector{x}) | Benchmark* Range(int64_t start, int64_t limit); | Benchmark* Range(int64_t start, int64_t limit); | Benchmark* DenseRange(int64_t start, int64_t limit, int step = 1); | Benchmark* DenseRange(int64_t start, int64_t limit, int step = 1); | Benchmark* Args(const std::vector<int64_t>& args); | 向Benchmark对象的std::vector<std::vector<int64_t> > args_添加一个元素(元素为args) | Benchmark* ArgPair(int64_t x, int64_t y) | 向Benchmark对象的std::vector<std::vector<int64_t> > args_添加一个元素(元素为vector{x,y}) |
void BM_Arg(benchmark::State& state) {
std::cout << "arg1:" << state.range(0) << "\n";
for (auto _ : state) {
std::this_thread::sleep_for(std::chrono::milliseconds(state.range(0)));
}
}
int main(int argc, char** argv) {
::benchmark::Initialize(&argc, argv);
if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
::benchmark::RegisterBenchmark("BM_Arg", &BM_Arg)->Arg(10);
::benchmark::RegisterBenchmark("BM_Arg", &BM_Arg)->Arg(10)->Arg(11);
::benchmark::RunSpecifiedBenchmarks();
::benchmark::Shutdown();
}
2. 测试多少次(iterations)
会有如下策略(简单的将如果没有明确设置iteration,会使用相应的计算方法(会使用到min_time),递增迭代次数然后以最后一个确定的结果report): 我们可能逐渐增加基准的长度(迭代次数),直到我们确定结果是重要的。 一旦我们这样做了,我们就会报告最后的结果并退出。 请注意,如果有重复,则迭代计数仅为第一次重复计算,其他重复仅使用该预先计算的迭代计数。
::benchmark::RegisterBenchmark("BM_Arg", &BM_Arg)->Iterations(10);
::benchmark::RegisterBenchmark("BM_Arg", &BM_Arg);
3. 重复多少次(Repetitions)
指的是整个函数对象调用多少次,默认值是1
::benchmark::RegisterBenchmark("BM_Arg", &BM_Arg)->Iterations(10)->Repetitions(3);
4. 显示时间单位
Benchmark* Unit(TimeUnit unit); 设置显示时间单位: kNanosecond, kMicrosecond, kMillisecond, kSecond.
5. 多线程
| |
---|
Benchmark* Threads(int t); | 设置多少个线程运行测试(线程函数中运行注册的函数对象) | Benchmark* ThreadRange(int min_threads, int max_threads); | 类似args_, 以min_threads为起点,倍率为2,终点为 max_threads,向thread_counts_添加元素比如: Range(1, 16), Threads(1)->Threads(2)-> Threads(4)-> Threads(8)-> Threads(16),分别以1、2、4、8、16个线程进行测试 | Benchmark* DenseThreadRange(int min_threads, int max_threads, int stride = 1); | 类似args_, 以min_threads为起点,步长为1,终点为 max_threads,向thread_counts_添加元素,DenseThreadRange(1, 8, 3), 1、4、7、8个线程进行测试 |
6. 时间类型
void BM_Arg(benchmark::State& state) {
for (auto _ : state) {
auto start = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_for(sleep_duration);
auto end = std::chrono::high_resolution_clock::now();
auto elapsed_seconds =
std::chrono::duration_cast<std::chrono::duration<double>>(
end - start);
state.SetIterationTime(elapsed_seconds.count());
}
}
::benchmark::RegisterBenchmark("BM_Arg", &BM_Arg)->UseManualTime();
7. 统计分析结果
会统计每次的结果,然后输出分析结果: mean: 平均值、median: 中值、stddev: 标准差、cv:标准差/平均值 自定义分析结果,比如最小值,最大值 接口:
typedef double(StatisticsFunc)(const std::vector<double>&);
Benchmark* ComputeStatistics(std::string name, StatisticsFunc* statistics,
StatisticUnit unit = kTime);
示例:
::benchmark::RegisterBenchmark("BM_Arg", &BM_Arg)->Iterations(10)->Repetitions(10)->Unit(benchmark::kMillisecond)
->ComputeStatistics("max", [](const std::vector<double>& v)->double{
return *std::max_element(v.begin(), v.end());
}, benchmark::kTime)
->ComputeStatistics("min", [](const std::vector<double>& v)->double{
return *std::min_element(v.begin(), v.end());
}, benchmark::kTime);
命令行
–benchmark_out_format=<console|json|csv> 定义输出格式 –benchmark_out= 定义文件名 –benchmark_filter= 定义过滤规则(正则表达式) –benchmark_repetitions=n 定义重复次数 –benchmark_report_aggregates_only={true|false} 上报内容是否只上报聚合内容(省略每次repetition的内容) –benchmark_display_aggregates_only={true|false} 屏幕输出内容是否只上报聚合内容(省略每次repetition的内容)
其他
模版方法和模版Fixture本文无介绍,相关使用方法可以参考google benchmark的github地址
|