PerformanceProfiler.h

#pragmaonce#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>#endifusingnamespacestd;////////////////////////////////////////////////////////typedeflonglongLongType;//单例的基类——饿汉模式template<classT>classSingleton{public:staticT*GetInstance(){assert(_sInstance);return_sInstance;}protected:staticT*_sInstance;};template<classT>T*Singleton::_sInstance=newT;////////////////////////////////////////////////////classSaveAdapter{public:virtualvoidSave(constchar*format,...)=0;};classConsoleSaveAdapter:publicSaveAdapter{public:virtualvoidSave(constchar*format,...){va_listargs;va_start(args,format);vfprintf(stdout,format,args);va_end(args);}};classFileSaveAdapter:publicSaveAdapter{public:FileSaveAdapter(constchar*filename){_fout=fopen(filename,"w");assert(_fout);}~FileSaveAdapter(){if(_fout)fclose(_fout);}protected://防拷贝FileSaveAdapter(FileSaveAdapter&);FileSaveAdapter&operator=(FileSaveAdpter&);protected:FILE*_fout;};classSqlSaveAdapter:publicSaveAdapter{};//配置管理enumConfigOptions{NONE=0,//不作剖析PERFORMANCE_PROFILER=1,//开启剖析SAVE_TO_CONSOLE=2,//保存到控制台SAVE_TO_FILE=4,//保存到文件SORT_BY_COSTTIME=8,//按调用次数排序SORT_BY_CALLCOUNT=16,//按花费时间排序};classConfigManager:publicSingleton<ConfigManager>{public:voidSetOptions(intoptions){_options=options;}voidAddOption(intoption){_options|=option;}voidDelOption(intoption){_options&=(~option);}intGetOptions(){return_options;}protected:friendclassSingleton<ConfigManager>;ConfigManager():_options(NONE){}ConfigManager(constConfigManager&);ConfigManager&operator=(constConfigManager);protected:int_options};//PerformanceProfilerstructPPNode{string_filename;string_function;size_t_line;string_desc;//附加描述信息PPNode(constchar*filename,constchar*function,\size_tline,constchar*desc):_filename(filename),_function(function),_line(line),_desc(desc){}booloperator==(constPPNode&node)const{if(_line==node._line&&\_function==node._function&&\_filename==node._filename)returntrue;elsereturnfalse;}};structPPSection{PPSection():_totalCostTime(0),_totalCallCount(0),_totalRefCount(0){}voidBegin(intid);voidEnd(intid);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计算哈希值的仿函数structPPNodeHash{staticsize_tBKDRHash(constchar*str){unsignedintseed=131;//31131131313131131313unsignedinthash=0;while(*str){hash=hash*seed+(*str++);}return(hash&0x7FFFFFFF);}size_toperator()(constPPNode&node)const{staticstringhash;hash=node._desc;hash+=node._function;returnBKDRHash(hash.c_str());}};classPerformanceProfiler:publicSingleton<PerformanceProfiler>{typedefunordered_map<PPNode,PPSection*,PPNodeHash>PP_MAP;public:PPSection*CreateSection(constchar*filename,constchar*function,\size_tline,constchar*desc);voidOutPut();protected:void_OutPut(SaveAdapter&sa);friendclassSingleton<PerformanceProfiler>;PerformanceProfiler(){}PerformanceProfiler(constPerformanceProfiler&);PerformanceProfiler&operator=(constPerformanceProfiler&);protected://map<PPNode,PPSection*>_ppMap;//统计资源信息的容器PP_MAP_ppMap;mutex_mtx;};structReport{~Report(){PerformanceProfiler::GetInstance()->OutPut();}};staticintGetTheadId(){#ifdef_WIN32returnGetCurrentThreadId();#elsereturnthread_self();#endif//_WIN32}//剖析单线程场景#definePERFORMANCE_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);\}\#definePERFORMANCE_PROFILER_ST_END(sign)\if(ps##sign)\ps##sign->End(-1);\//剖析多线程场景#definePERFORMANCE_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());\}\#definePERFORMANCE_PROFILER_ST_END(sign)\if(ps##sign)\\ps##sign->End(GetTheadId());#defineSET_CONFIG_OPTIONS(option)\ConfigManager::GetInstance()->SetOptions(option);

PerformanceProfiler.cpp

#include"PerformanceProfiler.h"voidPPSection::Begin(intid){if(id!=-1)//多线程{lock_guard<mutex>lock(_mtx);//统计线程总的花费时间和调用次数if(_refCountMap[id]++==0)_beginTimeMap[id]=clock();}else//单线程{if(_totalRefCount++==0)_totalBeginTime=clock();}}voidPPSection::End(intid){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(constchar*filename,constchar*function,size_tline,constchar*desc){PPNodenode(filename,function,line,desc);PPSection*section=NULL;//RAIIlock_guard<mutex>lock(_mtx);PP_MAP::iteratorit=_ppMap.find(node);if(it!=_ppMap.end()){section=it->second;}else{section=newPPSection;_ppMap.insert(pair<PPNode,PPSection*>(node,section));}returnsection;}voidPerformanceProfiler::OutPut(){intoptions=ConfigManager::GetInstance()->GetOptions();if(options&SAVE_TO_CONSOLE){ConsoleSaveAdaptercsa;_OutPut(csa);}if(options&SAVE_TO_FILE){FileSaveAdapterfsa("PerformanceProfilerReport.txt");_OutPut(fsa);}}voidPerformanceProfiler::_OutPut(SaveAdapter&sa){vector<PP_MAP::iterator>vInfos;PP_MAP::iteratorppIt=_ppMap.begin();while(ppIt!=_ppMap.end()){PPSection*section=ppIt->second;map<int,LongType>::iteratortimeIt;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;}structSortByCostTime{booloperator()(PP_MAP::iteratorl,PP_MAP::iteratorr)const{return(l->second->_totalCostTime)>(r->second->_totalCostTime);}};//按花费时间排序sort(vInfos.begin(),vInfos.end(),SortByCostTime());intnum=1;for(size_ti=0;i<vInfos.size();++i){ppIt=vInfos[i];constPPNode&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>::iteratortimeIt;timeIt=section->_costTimeMap.begin();while(timeIt!=section->_costTimeMap.end()){intid=timeIt->first;sa.Save("Thread:%d,CostTime:%.2fs,CallCount:%lld\n",id,(double)timeIt->second/1000,section->_callCountMap[id]);section->_totalCostTime+=timeIt->second;section->_totalCallCount+=section->_callCountMap[id];++timeIt;}sa.Save("TotalCostTime:%.2fs,TotalCallCount:%lld,AverCostTime:%lldms\n\n",(double)section->_totalCostTime/1000,section->_totalCallCount,section->_totalCostTime/section->_totalCallCount);++ppIt;}}