PerformanceProfiler

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章