PerformanceProfiler.h
#pragma once #include <iostream> #include <string> #include <map> #include <algorithm> #include <stdarg.h> #include <time.h> #include <assert.h> //C++ 11 #include <unordered_map> #include <thread> #include <mutex> #ifdef _WIN32 #include <windows.h> #else #include <pthread.h> #endif using namespace std; //////////////////////////////////////////////////////// typedef long long LongType; //单例的基类——饿汉模式 template<class T> class Singleton { public: static T* GetInstance() { assert(_sInstance); return _sInstance; } protected: static T* _sInstance; }; template<class T> T* Singleton::_sInstance = new T; //////////////////////////////////////////////////// class SaveAdapter { public: virtual void Save(const char* format, ...) = 0; }; class ConsoleSaveAdapter :public SaveAdapter { public: virtual void Save(const char* format, ...) { va_list args; va_start(args, format); vfprintf(stdout, format, args); va_end(args); } }; class FileSaveAdapter : public SaveAdapter { public: FileSaveAdapter(const char* filename) { _fout = fopen(filename, "w"); assert(_fout); } ~FileSaveAdapter() { if (_fout) fclose(_fout); } protected: //防拷贝 FileSaveAdapter(FileSaveAdapter&); FileSaveAdapter& operator=(FileSaveAdpter&); protected: FILE* _fout; }; class SqlSaveAdapter : public SaveAdapter {}; //配置管理 enum ConfigOptions { NONE = 0, //不作剖析 PERFORMANCE_PROFILER = 1, //开启剖析 SAVE_TO_CONSOLE = 2, //保存到控制台 SAVE_TO_FILE = 4, //保存到文件 SORT_BY_COSTTIME = 8, //按调用次数排序 SORT_BY_CALLCOUNT = 16, //按花费时间排序 }; class ConfigManager : public Singleton<ConfigManager> { public: void SetOptions(int options) { _options = options; } void AddOption(int option) { _options |= option; } void DelOption(int option) { _options &= (~option); } int GetOptions() { return _options; } protected: friend class Singleton<ConfigManager>; ConfigManager() :_options(NONE) {} ConfigManager(const ConfigManager&); ConfigManager& operator=(const ConfigManager); protected: int _options }; //Performance Profiler struct PPNode { string _filename; string _function; size_t _line; string _desc; //附加描述信息 PPNode(const char* filename, const char* function,\ size_t line, const char* desc) :_filename(filename) ,_function(function) ,_line(line) ,_desc(desc) {} bool operator==(const PPNode& node) const { if (_line == node._line &&\ _function == node._function &&\ _filename == node._filename) return true; else return false; } }; struct PPSection { PPSection() :_totalCostTime(0) ,_totalCallCount(0) ,_totalRefCount(0) {} void Begin(int id); void End(int id); map<int, LongType> _beginTimeMap; map<int, LongType> _costTimeMap; map<int, LongType> _callCountMap; map<int, LongType> _refCountMap; LongType _totalBeginTime; //开始时间 LongType _totalCostTime; //花费时间 LongType _totalCallCount; //调用次数 LongType _totalRefCount; //引用计数,解决递归问题 mutex _mtx; }; //PPNode计算哈希值的仿函数 struct PPNodeHash { static size_t BKDRHash(const char * str) { unsigned int seed = 131; // 31 131 1313 13131 131313 unsigned int hash = 0; while (*str) { hash = hash * seed + (*str++); } return (hash & 0x7FFFFFFF); } size_t operator()(const PPNode& node) const { static string hash; hash = node._desc; hash += node._function; return BKDRHash(hash.c_str()); } }; class PerformanceProfiler : public Singleton<PerformanceProfiler> { typedef unordered_map<PPNode, PPSection*, PPNodeHash> PP_MAP; public: PPSection* CreateSection(const char* filename, const char* function, \ size_t line, const char* desc); void OutPut(); protected: void _OutPut(SaveAdapter& sa); friend class Singleton<PerformanceProfiler>; PerformanceProfiler(){} PerformanceProfiler(const PerformanceProfiler&); PerformanceProfiler& operator=(const PerformanceProfiler&); protected: //map<PPNode, PPSection*> _ppMap; //统计资源信息的容器 PP_MAP _ppMap; mutex _mtx; }; struct Report { ~Report() { PerformanceProfiler::GetInstance()->OutPut(); } }; static int GetTheadId() { #ifdef _WIN32 return GetCurrentThreadId(); #else return thread_self(); #endif // _WIN32 } //剖析单线程场景 #define PERFORMANCE_PROFILER_EE_ST_BEGIN(sign, desc) \ PPSection* ps##sign = NULL; \ if (ConfigManager::GetInstance()->GetOptions() & PERFORMANCE_PROFILER) \ { \ ps##sign = PerformanceProfiler::GetInstance()->CreateSection(__FILE__, __FUNCTION__, __LINE__, desc);\ ps##sign->Begin(-1); \ } \ #define PERFORMANCE_PROFILER_ST_END(sign) \ if (ps##sign) \ ps##sign->End(-1); \ //剖析多线程场景 #define PERFORMANCE_PROFILER_EE_MT_BEGIN(sign, desc) \ PPSection* ps##sign = NULL; \ if (ConfigManager::GetInstance()->GetOptions() & PERFORMANCE_PROFILER) \ { \ ps##sign = PerformanceProfiler::GetInstance()->CreateSection(__FILE__, __FUNCTION__, __LINE__, desc);\ ps##sign->Begin(GetTheadId()); \ } \ #define PERFORMANCE_PROFILER_ST_END(sign) \ if (ps##sign) \ \ ps##sign->End(GetTheadId()); #define SET_CONFIG_OPTIONS(option) \ ConfigManager::GetInstance()->SetOptions(option);
PerformanceProfiler.cpp
#include "PerformanceProfiler.h" void PPSection::Begin(int id) { if (id != -1) //多线程 { lock_guard<mutex> lock(_mtx); //统计线程总的花费时间和调用次数 if (_refCountMap[id]++ == 0) _beginTimeMap[id] = clock(); } else //单线程 { if (_totalRefCount++ == 0) _totalBeginTime = clock(); } } void PPSection::End(int id) { if (id != -1) //多线程 { lock_guard<mutex> lock(_mtx); if (--_refCountMap[id] == 0) _costTimeMap[id] += clock() - _beginTimeMap[id]; ++_callCountMap[id]; } else //单线程 { if (--_totalRefCount == 0) _totalCostTime += clock() - _totalBeginTime; ++_totalCallCount; } } PPSection* PerformanceProfiler::CreateSection(const char* filename, const char* function, size_t line, const char* desc) { PPNode node(filename, function, line, desc); PPSection* section = NULL; //RAII lock_guard<mutex> lock(_mtx); PP_MAP::iterator it = _ppMap.find(node); if (it != _ppMap.end()) { section = it->second; } else { section = new PPSection; _ppMap.insert(pair<PPNode, PPSection*>(node, section)); } return section; } void PerformanceProfiler::OutPut() { int options = ConfigManager::GetInstance()->GetOptions(); if (options & SAVE_TO_CONSOLE) { ConsoleSaveAdapter csa; _OutPut(csa); } if (options & SAVE_TO_FILE) { FileSaveAdapter fsa("PerformanceProfilerReport.txt"); _OutPut(fsa); } } void PerformanceProfiler::_OutPut(SaveAdapter& sa) { vector<PP_MAP::iterator> vInfos; PP_MAP::iterator ppIt = _ppMap.begin(); while (ppIt != _ppMap.end()) { PPSection* section = ppIt->second; map<int, LongType>::iterator timeIt; timeIt = section->_costTimeMap.begin(); while (timeIt != section->_costTimeMap.end()) { section->_totalCostTime += timeIt->second; section->_totalCallCount += section->_callCountMap[timeIt->first]; ++timeIt; } vInfos.push_back(ppIt); ++ppIt; } struct SortByCostTime { bool operator()(PP_MAP::iterator l, PP_MAP::iterator r) const { return (l->second->_totalCostTime) > (r->second->_totalCostTime); } }; //按花费时间排序 sort(vInfos.begin(), vInfos.end(), SortByCostTime()); int num = 1; for (size_t i = 0; i < vInfos.size(); ++i) { ppIt = vInfos[i]; const PPNode& node = ppIt->first; PPSection* section = ppIt->second; //node信息 sa.Save("No.%d, Desc:%s\n", num++, node._desc.c_str()); sa.Save("Filename:%s, Line:%d, Function:%s\n", node._filename.c_str(), node._line, node._function.c_str()); //section信息 map<int, LongType>::iterator timeIt; timeIt = section->_costTimeMap.begin(); while (timeIt != section->_costTimeMap.end()) { int id = timeIt->first; sa.Save("Thread:%d, CostTime:%.2f s, CallCount:%lld\n", id, (double)timeIt->second / 1000, section->_callCountMap[id]); section->_totalCostTime += timeIt->second; section->_totalCallCount += section->_callCountMap[id]; ++timeIt; } sa.Save("TotalCostTime:%.2f s, TotalCallCount:%lld, AverCostTime:%lld ms\n\n", (double)section->_totalCostTime / 1000, section->_totalCallCount, section->_totalCostTime / section->_totalCallCount); ++ppIt; } }
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。