首页 > 代码库 > 性能剖析器项目

性能剖析器项目

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;
	}
}



本文出自 “zgw285763054” 博客,请务必保留此出处http://zgw285763054.blog.51cto.com/11591804/1859988

性能剖析器项目