网站建设资讯

NEWS

网站建设资讯

性能剖析器项目

PerformanceProfiler.h

成都创新互联坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都网站设计、成都网站建设、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的山海关网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!

#pragma once

#include 
#include 
#include 
#include 

#include 
#include 
#include 

//C++ 11
#include 
#include 
#include 

#ifdef _WIN32
	#include 
#else
	#include 
#endif

using namespace std;

////////////////////////////////////////////////////////
typedef long long LongType;

//单例的基类——饿汉模式
template
class Singleton
{
public:
	static T* GetInstance()
	{
		assert(_sInstance);
		return _sInstance;
	}
protected:
	static T* _sInstance;
};
template
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
{
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()
		:_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 _beginTimeMap;
	map _costTimeMap;
	map _callCountMap;
	map _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
{
	typedef unordered_map 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(const PerformanceProfiler&);
	PerformanceProfiler& operator=(const PerformanceProfiler&);

protected:
	//map _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 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 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 lock(_mtx);

	PP_MAP::iterator it = _ppMap.find(node);
	if (it != _ppMap.end())
	{
		section = it->second;
	}
	else
	{
		section = new PPSection;
		_ppMap.insert(pair(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 vInfos;
	PP_MAP::iterator ppIt = _ppMap.begin();
	while (ppIt != _ppMap.end())
	{
		PPSection* section = ppIt->second;
		map::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::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;
	}
}


当前名称:性能剖析器项目
文章路径:http://cdweb.net/article/ghjcpg.html