基于C++11实现的性能耗时统计组件 - 202204

2024-05-11 17:32

本文主要是介绍基于C++11实现的性能耗时统计组件 - 202204,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

平时经常需要对代码进行性能测试,自己用C++写了一个耗时统计组件,采用C++11标准,不依赖任何特定平台,包含文件即可使用。

// PerfTime.h#ifndef _CPP_PERFTIME_H_
#define _CPP_PERFTIME_H_namespace PerfTime {// 耗时统计类型enum class PerfType {PERF_E2E = 0, // 端到端类型,支持多线程PERF_ACC      // 累加类型,支持多线程};void StartHit(PerfType type, const char *mark); // 开始打点void EndHit(PerfType type, const char *mark); // 结束打点void OutputReport(const char *file, bool isOutputCmd = true); // 输出报告
}#endif // _CPP_PERFTIME_H_
// PerfTime.cpp#include "PerfTime.h"
#include <string>
#include <vector>
#include <map>
#include <mutex>
#include <chrono>
#include <algorithm>
#include <numeric>
#include <fstream>
#include <sstream>
#include <iostream>namespace PerfTime {using UINT64 = unsigned long long;//using namespace std::chrono;// 打点类型struct HitInfo {PerfType type;UINT64 timePoint;bool isStart = true;HitInfo(UINT64 tp, PerfType type, bool isStart) : timePoint(tp), type(type), isStart(isStart) {}};// 统计数据struct StatisticsInfo {UINT64 callCount;UINT64 costTime;StatisticsInfo(UINT64 call, UINT64 time) : callCount(call), costTime(time) {}};// 统计功能实现类class Interface {public:static void StartHit(PerfType type, const std::string &mark);static void EndHit(PerfType type, const std::string &mark);static void OutputReport(const std::string &file, bool isOutPutCmd);static UINT64 GetSysTimePoint();private:static std::map<std::string, StatisticsInfo> Cal();static void InsertHitInfo(PerfType type, const std::string &mark, bool isStart);static std::mutex mtRecord;static std::map<std::string, std::vector<HitInfo>> record;};// 静态数据成员定义std::mutex Interface::mtRecord;std::map<std::string, std::vector<HitInfo>> Interface::record;UINT64 Interface::GetSysTimePoint() {using namespace std::chrono;return time_point_cast<std::chrono::microseconds>(steady_clock::now()).time_since_epoch().count();}void Interface::InsertHitInfo(PerfType type, const std::string &mark, bool isStart) {auto tp = GetSysTimePoint();std::lock_guard<std::mutex> lck(mtRecord);record[mark].emplace_back(tp, type, isStart);}void Interface::StartHit(PerfType type, const std::string &mark) {InsertHitInfo(type, mark, true);}void Interface::EndHit(PerfType type, const std::string &mark) {InsertHitInfo(type, mark, false);}void Interface::OutputReport(const std::string &file, bool isOutPutCmd) {std::map<std::string, StatisticsInfo> res = Cal();std::ofstream ofs;ofs.open(file, std::ofstream::out | std::ofstream::ate);if (ofs.is_open()) {std::ostringstream oss;int index = 0;for (const auto &item: res) {oss << ++index << ". " << item.first << "\n" << "CallCount: " <<item.second.callCount << ", Time: " <<item.second.costTime << " (microseconds) | " <<item.second.costTime / 1000.0 << " (milliseconds) | " <<item.second.costTime / (1000.0 * 1000.0) << " (seconds)\n";}ofs << oss.str() << std::flush;if (isOutPutCmd) {std::cout << oss.str() << std::flush;}}}std::map<std::string, StatisticsInfo> Interface::Cal() {std::map<std::string, std::vector<HitInfo>> recordCp;{std::lock_guard<std::mutex> lck(mtRecord);recordCp = record;}// 循环计算每个 mark 耗时信息std::map<std::string, StatisticsInfo> res;for (const auto &oneRecord: recordCp) {std::vector<UINT64> startVec;std::vector<UINT64> endVec;const std::string &mark = oneRecord.first;const std::vector<HitInfo> &hitInfos = oneRecord.second;for (auto &hitInfo: hitInfos) {if (hitInfo.isStart) {startVec.push_back(hitInfo.timePoint);continue;}endVec.push_back(hitInfo.timePoint);}// 简单校验打点数据是否为空if (startVec.empty() || endVec.empty()) {res.insert({mark, {0, 0}});}// 计算耗时if (hitInfos.back().type == PerfType::PERF_E2E) {// 端到端类型UINT64 durTime = *(std::max_element(endVec.cbegin(), endVec.cend())) -*(std::min_element(startVec.cbegin(), startVec.cend()));res.insert({mark, {1, durTime}});} else {// 累加类型if (endVec.size() != startVec.size()) {// 数据校验,开始打点和结束打点数量需要一致res.insert({mark, {0, 0}});continue;}UINT64 durTime = std::accumulate(endVec.cbegin(), endVec.cend(), 0) -std::accumulate(startVec.cbegin(), startVec.cend(), 0);res.insert({mark, {endVec.size(), durTime}});}}return res;}void StartHit(PerfType type, const char *mark) {Interface::StartHit(type, mark);}void EndHit(PerfType type, const char *mark) {Interface::EndHit(type, mark);}void OutputReport(const char *file, bool isOutputCmd) {Interface::OutputReport(file, isOutputCmd);}
}
// 测试代码 main.cpp#include "PerfTime.h"
#include <thread>
#include <chrono>void fun1() {// 睡眠 200ms 模拟函数处理耗时std::this_thread::sleep_for(std::chrono::milliseconds(200));
}void fun2() {// 睡眠 150ms 模拟函数处理耗时std::this_thread::sleep_for(std::chrono::milliseconds(100));
}void fun3() {// 睡眠 100ms 模拟函数处理耗时std::this_thread::sleep_for(std::chrono::milliseconds(100));
}void threadFun() {PerfTime::StartHit(PerfTime::PerfType::PERF_ACC, "fun3_cost");fun3();PerfTime::EndHit(PerfTime::PerfType::PERF_ACC, "fun3_cost");
}int main() {PerfTime::StartHit(PerfTime::PerfType::PERF_E2E, "main");// 端到端测试PerfTime::StartHit(PerfTime::PerfType::PERF_E2E, "fun1_cost");fun1();PerfTime::EndHit(PerfTime::PerfType::PERF_E2E, "fun1_cost");// 累加耗时测试for (int i = 0; i < 5; ++i) {PerfTime::StartHit(PerfTime::PerfType::PERF_ACC, "fun2_cost");fun2();PerfTime::EndHit(PerfTime::PerfType::PERF_ACC, "fun2_cost");}// 多线程测试std::thread threads[10];for (int i = 0; i < 10; ++i) {threads[i] = std::thread(threadFun);}for (int i = 0; i < 10; ++i) {if (threads[i].joinable()) {threads[i].join();}}PerfTime::EndHit(PerfTime::PerfType::PERF_E2E, "main");// 输出报告PerfTime::OutputReport("d:\\report.txt");return 0;
}

这篇关于基于C++11实现的性能耗时统计组件 - 202204的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/980188

相关文章

关于C++中的虚拟继承的一些总结(虚拟继承,覆盖,派生,隐藏)

1.为什么要引入虚拟继承 虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下: class A class B1:public virtual A; class B2:pu

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

C++的模板(八):子系统

平常所见的大部分模板代码,模板所传的参数类型,到了模板里面,或实例化为对象,或嵌入模板内部结构中,或在模板内又派生了子类。不管怎样,最终他们在模板内,直接或间接,都实例化成对象了。 但这不是唯一的用法。试想一下。如果在模板内限制调用参数类型的构造函数会发生什么?参数类的对象在模板内无法构造。他们只能从模板的成员函数传入。模板不保存这些对象或者只保存他们的指针。因为构造函数被分离,这些指针在模板外

C++工程编译链接错误汇总VisualStudio

目录 一些小的知识点 make工具 可以使用windows下的事件查看器崩溃的地方 dumpbin工具查看dll是32位还是64位的 _MSC_VER .cc 和.cpp 【VC++目录中的包含目录】 vs 【C/C++常规中的附加包含目录】——头文件所在目录如何怎么添加,添加了以后搜索头文件就会到这些个路径下搜索了 include<> 和 include"" WinMain 和

C/C++的编译和链接过程

目录 从源文件生成可执行文件(书中第2章) 1.Preprocessing预处理——预处理器cpp 2.Compilation编译——编译器cll ps:vs中优化选项设置 3.Assembly汇编——汇编器as ps:vs中汇编输出文件设置 4.Linking链接——链接器ld 符号 模块,库 链接过程——链接器 链接过程 1.简单链接的例子 2.链接过程 3.地址和

C++必修:模版的入门到实践

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C++学习 贝蒂的主页:Betty’s blog 1. 泛型编程 首先让我们来思考一个问题,如何实现一个交换函数? void swap(int& x, int& y){int tmp = x;x = y;y = tmp;} 相信大家很快就能写出上面这段代码,但是如果要求这个交换函数支持字符型

公共筛选组件(二次封装antd)支持代码提示

如果项目是基于antd组件库为基础搭建,可使用此公共筛选组件 使用到的库 npm i antdnpm i lodash-esnpm i @types/lodash-es -D /components/CommonSearch index.tsx import React from 'react';import { Button, Card, Form } from 'antd'

通过SSH隧道实现通过远程服务器上外网

搭建隧道 autossh -M 0 -f -D 1080 -C -N user1@remotehost##验证隧道是否生效,查看1080端口是否启动netstat -tuln | grep 1080## 测试ssh 隧道是否生效curl -x socks5h://127.0.0.1:1080 -I http://www.github.com 将autossh 设置为服务,隧道开机启动

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料 基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为

C++入门01

1、.h和.cpp 源文件 (.cpp)源文件是C++程序的实际实现代码文件,其中包含了具体的函数和类的定义、实现以及其他相关的代码。主要特点如下:实现代码: 源文件中包含了函数、类的具体实现代码,用于实现程序的功能。编译单元: 源文件通常是一个编译单元,即单独编译的基本单位。每个源文件都会经过编译器的处理,生成对应的目标文件。包含头文件: 源文件可以通过#include指令引入头文件,以使