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;
}
时间: 08-07

PerformanceProfiler的相关文章

性能剖析器

 PerformanceProfiler.h: #include<iostream> using namespace std; #include<map> #include<windows.h> #include<time.h> #include<string> #include<assert.h> #include<stdarg.h> #include<thread> #include<mutex>

性能剖析器项目

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> #inclu

nginx http模块开发入门

导语 本文对nginx http模块开发需要掌握的一些关键点进行了提炼,同时以开发一个简单的日志模块进行讲解,让nginx的初学者也能看完之后做到心里有谱.本文只是一个用作入门的概述. 目录 背景 主线 认识nginx http请求处理流程 日志模块开发准备 配置解析流程 挂载处理函数 获取日志数据 模块编译 完整源码 结尾 背景 网上已经有很多介绍nginx http模块开发入门的文章,但是大多以hello_word程序为例,简单讲解一下代码,看完之后可能只能够依葫芦画瓢,做不了其它事情,更不