基于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

相关文章

MySQL 多列 IN 查询之语法、性能与实战技巧(最新整理)

《MySQL多列IN查询之语法、性能与实战技巧(最新整理)》本文详解MySQL多列IN查询,对比传统OR写法,强调其简洁高效,适合批量匹配复合键,通过联合索引、分批次优化提升性能,兼容多种数据库... 目录一、基础语法:多列 IN 的两种写法1. 直接值列表2. 子查询二、对比传统 OR 的写法三、性能分析

Linux下删除乱码文件和目录的实现方式

《Linux下删除乱码文件和目录的实现方式》:本文主要介绍Linux下删除乱码文件和目录的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下删除乱码文件和目录方法1方法2总结Linux下删除乱码文件和目录方法1使用ls -i命令找到文件或目录

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

mybatis执行insert返回id实现详解

《mybatis执行insert返回id实现详解》MyBatis插入操作默认返回受影响行数,需通过useGeneratedKeys+keyProperty或selectKey获取主键ID,确保主键为自... 目录 两种方式获取自增 ID:1. ​​useGeneratedKeys+keyProperty(推

Spring Boot集成Druid实现数据源管理与监控的详细步骤

《SpringBoot集成Druid实现数据源管理与监控的详细步骤》本文介绍如何在SpringBoot项目中集成Druid数据库连接池,包括环境搭建、Maven依赖配置、SpringBoot配置文件... 目录1. 引言1.1 环境准备1.2 Druid介绍2. 配置Druid连接池3. 查看Druid监控

Linux在线解压jar包的实现方式

《Linux在线解压jar包的实现方式》:本文主要介绍Linux在线解压jar包的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux在线解压jar包解压 jar包的步骤总结Linux在线解压jar包在 Centos 中解压 jar 包可以使用 u

Linux系统性能检测命令详解

《Linux系统性能检测命令详解》本文介绍了Linux系统常用的监控命令(如top、vmstat、iostat、htop等)及其参数功能,涵盖进程状态、内存使用、磁盘I/O、系统负载等多维度资源监控,... 目录toppsuptimevmstatIOStatiotopslabtophtopdstatnmon

c++ 类成员变量默认初始值的实现

《c++类成员变量默认初始值的实现》本文主要介绍了c++类成员变量默认初始值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录C++类成员变量初始化c++类的变量的初始化在C++中,如果使用类成员变量时未给定其初始值,那么它将被

C++中NULL与nullptr的区别小结

《C++中NULL与nullptr的区别小结》本文介绍了C++编程中NULL与nullptr的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编... 目录C++98空值——NULLC++11空值——nullptr区别对比示例 C++98空值——NUL

C++ Log4cpp跨平台日志库的使用小结

《C++Log4cpp跨平台日志库的使用小结》Log4cpp是c++类库,本文详细介绍了C++日志库log4cpp的使用方法,及设置日志输出格式和优先级,具有一定的参考价值,感兴趣的可以了解一下... 目录一、介绍1. log4cpp的日志方式2.设置日志输出的格式3. 设置日志的输出优先级二、Window