IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> Google benchmark使用手册及范例 -> 正文阅读

[C++知识库]Google benchmark使用手册及范例

构建集成

在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(); // main函数,运行benchmark初始化和执行

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); // 初始化Benchmark
  if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
  
  // 使用函数指针注册
  ::benchmark::RegisterBenchmark("BM_DemoSleep", &BM_DemoSleep);
  // 使用Lamba函数注册
  ::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())); // test code
  }
}
BENCHMARK_F(BMDemo, Test1)(benchmark::State& state) {
  for (auto _ : state) {
     std::this_thread::sleep_for(std::chrono::milliseconds(GetId())); // test code
  }
}

原理: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"; // state.range(0)获取参数
  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); // ->Arg()设置单个参数
    ::benchmark::RegisterBenchmark("BM_Arg", &BM_Arg)->Arg(10)->Arg(11); //分别以10,11参数运行BM_Arg
  ::benchmark::RunSpecifiedBenchmarks();
  ::benchmark::Shutdown(); 
}

2. 测试多少次(iterations)

会有如下策略(简单的将如果没有明确设置iteration,会使用相应的计算方法(会使用到min_time),递增迭代次数然后以最后一个确定的结果report):
我们可能逐渐增加基准的长度(迭代次数),直到我们确定结果是重要的。 一旦我们这样做了,我们就会报告最后的结果并退出。 请注意,如果有重复,则迭代计数仅为第一次重复计算,其他重复仅使用该预先计算的迭代计数。

::benchmark::RegisterBenchmark("BM_Arg", &BM_Arg)->Iterations(10); // 迭代执行10次,也就是for(auto _ : state){}循环会迭代10次

::benchmark::RegisterBenchmark("BM_Arg", &BM_Arg); // 会按照计算规则,迭代n次

3. 重复多少次(Repetitions)

指的是整个函数对象调用多少次,默认值是1

::benchmark::RegisterBenchmark("BM_Arg", &BM_Arg)->Iterations(10)->Repetitions(3); // 迭代执行10次,也就是for(auto _ : state){}循环会迭代10次; 重复调用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();
        // Simulate some useful workload with a sleep
        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地址

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-04 13:12:48  更:2021-12-04 13:13:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:57:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码