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;
}
}
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。