PerformanceProfiler.h
#include<iostream> #include<string> #include<map> #include<vector> #include<algorithm> #include<mutex> #include<stdarg.h> #include<assert.h> #include<time.h> #include <thread> // std::this_thread::sleep_for #include <chrono> // std::chrono::seconds #ifdef _WIN32 #include<windows.h> #else #include<pthread.h> #endif typedef long long LongType; using namespace std; //////////////////////////////////////////////////////////////////////// //单例模式(饿汉模式) template<class T> class EagerSingleton { public: static T* GetInstance() { assert(_instance); return _instance; } protected: /*EagerSingleton(); // ? EagerSingleton(const EagerSingleton& s); EagerSingleton& operator = (const EagerSingleton& s);*/ protected: static T* _instance; }; template<class T> T* EagerSingleton<T>::_instance = new T; ////////////////////////////////////////////////////////////////////////// //配置管理 enum ConifgOptions { NONE = 0, PERFORMANCE_PROFILER_EE = 1, // 开启效率剖析 PERFORMANCE_PROFILER_RS = 2, // 开启资源剖析 SAVE_TO_CONSOLE = 4, // 保存到控制台 SAVE_TO_FILE = 8, // 保存到文件 SORT_BY_CALL_COUNT = 16, // 结果按调用次数排序 SORT_BY_COST_TIME = 32, // 结果按花费时间排序 }; class ConifgManager :public EagerSingleton<ConifgManager> { friend class EagerSingleton<ConifgManager>; public: int SetOption(int flag); int GetOption(); void AddOption(int flag); void DelOption(int flag); protected: ConifgManager() :_flag(NONE) { // 读取配置文件,设置选选项 } protected: int _flag; }; ////////////////////////////////////////////////////////////////////////// //保存适配器 class SaveAdapter { public: //基类为纯虚函数,子类重写 virtual void Save(const char* fmt, ...) = 0; }; class ConsoleSaveAdapter :public SaveAdapter { public: virtual void Save(const char* fmt, ...) { va_list args; va_start(args, fmt); vfprintf(stdout, fmt, args); va_end(args); } }; class FileSaveAdapter :public SaveAdapter { public: FileSaveAdapter(const char* filename) { fout = fopen(filename, "w"); assert(fout); } virtual void Save(const char* fmt, ...) { va_list args; va_start(args, fmt); vfprintf(fout, fmt, args); va_end(args); } ~FileSaveAdapter() { if (fout) { fclose(fout); } } protected: FileSaveAdapter(const FileSaveAdapter&); FileSaveAdapter& operator=(const FileSaveAdapter&); protected: FILE* fout; }; ////////////////////////////////////////////////////////////////////////// //性能剖析器->节点信息 static int GetThreadId() { #ifdef _WIN32 return GetCurrentThreadId(); #else return thread_self(); #endif } struct PPNode { string _filename; //文件名 string _function; //函数名 size_t _line; //行号 string _desc; //附加项描述 //字符串为空得写“”而不能省略不写 PPNode(const char* filename = "", const char* function = "", size_t line = 0, const char* desc = "") : _filename(filename) , _function(function) , _line(line) , _desc(desc) {} //红黑树得支持operator<() bool operator<(const PPNode& node) const; }; //剖析段 typedef map<int, LongType> StatisticsMap; struct PPSection { public: PPSection() {} void Begin(int id); void End(int id); StatisticsMap _beginTimeMap; StatisticsMap _costTimeMap; StatisticsMap _callCountMap; StatisticsMap _refCountMap; //递归引用计数 LongType _totalCostTime; mutex _mtx; }; class PerformanceProfiler :public EagerSingleton<PerformanceProfiler> { friend class EagerSingleton<PerformanceProfiler>; typedef map<PPNode, PPSection*> PPMap; public: PPSection* CreateSection(const char* filename, const char* function, size_t line, const char* desc); void OutPut(); void _OutPut(SaveAdapter& sa); protected: PerformanceProfiler() {} PerformanceProfiler(const PerformanceProfiler&); PerformanceProfiler& operator=(const PerformanceProfiler&); protected: PPMap _ppMap; }; //? //struct Release //{ // ~Release() // { // PerformanceProfiler::GetInstance()->OutPut(); // } //}; //static Release gR; #define PERFORMANCE_PROFILER_EE_BEGIN(sign, desc) \ PPSection* sign##section = NULL; \ int sign##flag = ConifgManager::GetInstance()->GetOption(); \ if(sign##flag & PERFORMANCE_PROFILER_EE) \ { \ sign##section = performanceProfiler::GetInstance() \ ->CreateSection(__FILE__, __FUNCTION__, __LINE__, desc); \ sign##section->Begin(GetThreadId()); \ } #define PERFORMANCE_PROFILEER_EE_END(sign) \ if (sign##flag&PERFORMANCE_PROFILEER_EE) \ sign##section->End(GetthreadId()); #define SET_CONFIG_OPTION(flag) \ ConifgManager::GetInstance()->SetOption(flag);
PerformanceProfiler.cpp
using namespace std; #include "PerformanceProfiler.h" //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //配置管理 int ConifgManager::SetOption(int flag) { int old = _flag; _flag = flag; return old; } int ConifgManager::GetOption() { return _flag; } void ConifgManager::AddOption(int flag) { _flag |= flag; } void ConifgManager::DelOption(int flag) { _flag &= (~flag); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //剖析节点 inline bool PPNode::operator<(const PPNode& node) const { return (_line < node._line) || (_filename < node._filename) || (_function < node._function); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //剖析段 void PPSection::Begin(int id) { lock_guard<mutex> lock(_mtx); //id用来分辨不同线程 if (_refCountMap[id]++ == 0) { _beginTimeMap[id] = clock(); } _callCountMap[id]++; } void PPSection::End(int id) { lock_guard<mutex> lock(_mtx); if (--_refCountMap[id] == 0) { LongType costTime = clock() - _beginTimeMap[id]; _costTimeMap[id] += costTime; _totalCostTime += costTime; } } PPSection* PerformanceProfiler::CreateSection(const char* filename, const char* function, size_t line, const char* desc) { PPNode node(filename, function, line, desc); PPSection*& section = _ppMap[node]; if (section == NULL) { section = new PPSection; } return section; } void PerformanceProfiler::OutPut() { int flag = ConifgManager::GetInstance()->GetOption(); if (flag&SAVE_TO_CONSOLE) { ConsoleSaveAdapter csa; _OutPut(csa); } if (flag&SAVE_TO_FILE) { FileSaveAdapter fsa("PerformanceProfilerReport.txt"); _OutPut(fsa); } } void PerformanceProfiler::_OutPut(SaveAdapter& sa) { vector<PPMap::iterator> vInfos; int num = 1; PPMap::iterator ppIt = _ppMap.begin(); while (ppIt != _ppMap.end()) { vInfos.push_back(ppIt); ++ppIt; } struct SortByCostTime { bool operator()(PPMap::iterator left, PPMap::iterator right) { return left->second->_totalCostTime > right->second->_totalCostTime; } }; sort(vInfos.begin(), vInfos.end(), SortByCostTime()); vector<PPMap::iterator>::iterator it = vInfos.begin(); while (it != vInfos.end()) { const PPNode& node = (*it)->first; PPSection* section = (*it)->second; sa.Save("NO.%d,Desc:%s\n", num++, node._desc.c_str()); sa.Save("Filename:%s,Function:%s,Line:%u\n", node._filename.c_str(), node._function.c_str(), node._line); LongType totalCostTime = 0; LongType totalCallCount = 0; int id = 0; LongType costTime = 0; LongType callCount = 0; StatisticsMap::iterator timeIt = section->_costTimeMap.begin(); while(timeIt!=section->_costTimeMap.end()) { id = timeIt->first; costTime = timeIt->second; callCount = section->_callCountMap[id]; totalCostTime += costTime; totalCallCount += callCount; sa.Save("ThreadId:%d,CostTime:%.2f,callCount:%lld\n", id, (double)costTime, totalCallCount); ++it; } } }
test.cpp
#include "PerformanceProfiler.h" //测试用例 //普通情况 /////////////////////////////////////////////////////////////////////////////////// //void Test1() //{ // PPSection* section = PerformanceProfiler::GetInstance() \ // ->CreateSection(__FILE__, __FUNCTION__, __LINE__, "第一段代码"); // // section->Begin(); // Sleep(5000); // section->End(); //} void Test2() { PERFORMANCE_PROFILER_EE_BEGIN(sql, "数据库"); Sleep(1000); PERFORMANCE_PROFILER_EE_END(sql); PERFORMANCE_PROFILER_EE_BEGIN(network, "网络"); Sleep(2000); PERFORMANCE_PROFILER_EE_END(network); } //Test2调用3次 void TestN2() { for (int i = 3; i > 0; i--) { Test2(); } } /////////////////////////////////////////////////////////////////////////////////// //测试递归 LongType Fib(size_t n) { PERFORMANCE_PROFILER_EE_BEGIN(fib, "递归"); LongType ret = 0; if (n < 2) { ret = n; } else { ret = Fib(n - 1) + Fib(n - 2); } PERFORMANCE_PROFILER_EE_END(fib); return ret; } void TestN3() { PERFORMANCE_PROFILER_EE_BEGIN(fib, "FIB"); Fib(20); PERFORMANCE_PROFILER_EE_END(fib); } //测试多线程 void ThreadRun(int count) { cout << this_thread::get_id() << endl; while (count--) { PERFORMANCE_PROFILER_EE_BEGIN(ThreadRun, "ThreadRun"); this_thread::sleep_for(std::chrono::milliseconds(100)); PERFORMANCE_PROFILER_EE_END(ThreadRun); } } void TestMhread() { cout << this_thread::get_id() << endl; thread t1(ThreadRun, 15); thread t2(ThreadRun, 10); thread t3(ThreadRun, 5); t1.join(); t2.join(); t3.join(); } int main() { SET_CONFIG_OPTION(PERFORMANCE_PROFILER_EE | SAVE_TO_CONSOLE); //Test2(); //TestN3(); TestMhread(); system("pause"); return 0; }