本文主要是介绍基于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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!