性能剖析器

 PerformanceProfiler.h:
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

typedef long long LongType;

////////////保存适配器抽象基类//////////////
class SaveAdapter
{
public:
           //纯虚函数,强制要求派生类重写,重新实现
           virtual void Save(const char* fmt, ...) = 0;
};

//控制台保存适配器
class ConsoleSaveAdapter :public SaveAdapter//公有继承
{
           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(0)
          {
                   _fout = fopen( filename, "w" );
                    assert(_fout);
          }
          
          ~FileSaveAdapter()
          {
                    if (_fout)
                   {
                             fclose(_fout);
                   }
          }

           virtual void Save(const char* format , ...)
          {
                    if (_fout)
                   {
                              va_list args;
                              va_start(args, format);
                             vfprintf(_fout, format, args);//输出重定向到_fout
                              va_end(args);
                   }
          }

protected:
           //设置为保护类型,造成scopedPtr,防拷贝
          FileSaveAdapter( const FileSaveAdapter & f);
           FileSaveAdapter& operator=(const FileSaveAdapter& f);
private:
           FILE* _fout;
};

/////////////单例基类///////////////////
//单例模式的是指就是全局的静态指针,这个指针只能生成一个对象
template
class Singleton
{
public:
           static T * GetInstance()
          {
                    if (_sInstance == NULL )
                   {
                              lock_guard lock(_mutex);
                              if (_sInstance == NULL )
                             {
                                      _sInstance = new T ();
                             }
                   }
                    return _sInstance;
          }

protected:
           //默认构造函数
          Singleton()
          {}
           //成员变量
           static T * _sInstance;
           static mutex _mutex;
};

//静态成员初始化
template
T* Singleton ::_sInstance = NULL;

template
mutex Singleton ::_mutex;

enum PP_CONFIG_OPTION
{
           PPCO_NONE = 0,               //不做剖析
           PPCO_PROFILER = 2,           //开启剖析
           PPCO_SAVE_TO_CONSOLE = 4,    //保存到控制台
           PPCO_SAVE_TO_FILE = 8,       //保存到文件
           PPCO_SAVE_BY_CALL_COUNT = 16,//按调用次数降序保存
           PPCO_SAVE_BY_COST_TIME=32,   //按调用花费时间降序保存

};


/////////////配置管理////////////////
class ConfigManager :public Singleton
{
public:
           void SetOptions(int flag)
          {
                   _flag = flag;
          }
          
           int GetOptions()
          {
                    return _flag;
          }

          ConfigManager()
                   :_flag( PPCO_PROFILER | PPCO_SAVE_TO_CONSOLE | PPCO_SAVE_TO_FILE)
          {}

private:
           int _flag;
};

///////////////获取路径中最后的文件名///////////////////
static string GetFileName(const string& path )
{
           char ch = '/' ;

#ifdef _WIN32
          ch = '\\';
#endif

           size_t pos = path .rfind(ch);//逆序查找
           if (pos == string ::npos)
          {
                    return path ;
          }
           else
          {
                    return path .substr(pos + 1);
          }
}

/////////性能剖析节点///////////
struct PPNode
{
           string _filename;//文件名
           string _function;//函数名
           int _line;       //行号
           string _desc;    //描述

          PPNode( const char * filename, const char * function, int line , const char * desc)
                   :_filename( filename)
                   , _function( function)
                   , _line( line)
                   , _desc( desc)
          {}

           bool operator<(const PPNode& node)const
          {
                    if (_line > node ._line)
                              return false ;
                    if (_line < node ._line)
                              return true ;
                    if (_filename > node ._filename)
                              return false ;
                    if (_filename < node ._filename)
                              return true ;
                    if (_function > node ._function)
                              return false ;
                    if (_function < node ._function)
                              return true ;
                    return false ;
          }

           //比较相等
           bool operator==(const PPNode& node)const
          {
                    return _function == node ._function
                             &&_line == node._line
                             &&_filename == node._filename;
          }

           //打印PPNode节点信息
           void Serialize(SaveAdapter & sa)const
          {
                    sa.Save("Filename:%s,Function:%s,Line:%d\n" , _filename.c_str(), _function.c_str(), _line);
          }
};


///////////////性能剖析段///////////////////////
struct PPSection
{
           friend class PerformanceProfiler;
public:
          PPSection()
                   :_beginTime(0)  
                   , _totalCostTime(0)  
                   , _totalCallCount(0)
                   , _totalRefCount(0)
          {}

           void Begin(int id)//开始函数
          {
                    lock_guard lock(_mutex);
                   ++_callCountMap[ id];
                    if (_refCountMap[id ] == 0)
                   {
                             _beginTimeMap[ id] = clock();//计时函数
                   }
                   ++_refCountMap[ id];
                   ++_totalCallCount;
                   ++_totalRefCount;
          }

           void End(int id)
          {
                    lock_guard lock(_mutex);
                    LongType refCount = --_refCountMap[id ];
                   --_totalRefCount; //先将总的引用计数减1
                    //引用计数<=0时,更新剖析段花费的时间
                    if (refCount <= 0)
                   {
                              map:: iterator it = _beginTimeMap.find(id );
                              if (it != _beginTimeMap.end())
                             {
                                       LongType costTime = clock() - it->second;
                                       if (_refCountMap[id ] == 0)
                                      {
                                                _costTimeMap[ id] += costTime;
                                      }
                                       else
                                      {
                                                _costTimeMap[ id] = costTime;
                                      }
                                      _totalCostTime += costTime;

                             }
                   }
          }

           //线程打印信息
           void Serialize(SaveAdapter & sa)
          {
                    //如果总的引用计数不等于0,表示剖析段不匹配
                    if (_totalRefCount)
                              sa.Save("Performance Profiler Not Match!\n" );
                    //序列化效率统计信息
                    auto costTimeIt = _costTimeMap.begin();
                    for (; costTimeIt != _costTimeMap.end(); ++costTimeIt)
                   {
                              LongType callCount = _callCountMap[costTimeIt->first];
                              sa.Save("Thread Id:%d,Cost Time:%.2f,Call Count:%d\n",
                                      costTimeIt->first, (double)costTimeIt->second / CLOCKS_PER_SEC , callCount);
                   }
                    //CLOCKS_PER_SEC将clock函数时间转化为以秒为单位
                    sa.Save("Total CostTime:%.2f,Total Call Count:%d\n" ,
                             ( double)_totalCostTime / CLOCKS_PER_SEC , _totalCallCount);
          }
private:
           //加锁
           //
           //多个线程同时访问时,每个线程的开始时间,花费时间,访问次数都不相同
           map _beginTimeMap;
           map _costTimeMap;
           map _callCountMap;
           map _refCountMap; //利用引用计数方式解决递归时的计时问题
          
           //总的
           int _beginTime;//总的开始时间
           LongType _totalCostTime; //花费时间
           LongType _totalCallCount;//调用次数
           LongType _totalRefCount;//引用次数

           //锁
           mutex _mutex;
};

///////////获取当前线程id////////////////
static int GetThreadId()
{
#ifdef _WIN32
           return ::GetCurrentThreadId();
#else
           return ::thread_self();
#endif
}


//性能剖析器
class PerformanceProfiler :public Singleton
{
public:
           friend class Singleton< PerformanceProfiler>;
           PPSection* CreateSection(const char* filename, const char * function,
                    int line, const char* desc);
           static void OutPut();

protected:
           static bool CompareByCallCount(map< PPNode, PPSection*>::iterator lhs, map< PPNode, PPSection *>::iterator rhs);
           static bool CompareByCostTime(map< PPNode, PPSection*>::iterator lhs, map< PPNode, PPSection *>::iterator rhs);

          PerformanceProfiler()
          {
                    //程序结束时输出剖析结果
                   atexit(OutPut);
                   time(&_beginTime);
          }

           //输出序列化信息
           //为了有效使用了vector能够调用sort排序,只要自己添加Compare仿函数
           void _Output(SaveAdapter & sa)
          {
                    sa.Save("=====================Performance Profiler Report====================\n\n");
                    sa.Save("Profiler Begin Time:%s\n",ctime(&_beginTime));
                    unique_lock lock(_mutex);
                    vector::iterator > vInfos;

                    //PPSection作为查询值,里面保存运行时间,运行次数,开始时间和结束时间
                    auto it = _ppMap.begin();
                    for (; it != _ppMap.end(); ++it)
                   {
                             vInfos.push_back(it);
                   }
                   
                    //按配置条件对剖析结果进行排序输出
                    int flag = ConfigManager ::GetInstance()->GetOptions();
                    if (flag&PPCO_SAVE_BY_COST_TIME )
                             sort(vInfos.begin(), vInfos.end(), CompareByCostTime);
                    else
                             sort(vInfos.begin(), vInfos.end(), CompareByCallCount);
                    for (int index = 0; index < vInfos.size(); ++index)
                   {
                              sa.Save("NO%d. Delciption:%s\n" , index + 1, vInfos[index]->first._desc.c_str());
                             vInfos[index]->first.Serialize( sa);
                             vInfos[index]->second->Serialize( sa);
                              sa.Save("\n" );
                   }
                     sa.Save("================================end==============================\n\n" );
          }
private:
           map _ppMap;
           time_t _beginTime;
           mutex _mutex;
};


//////////atexit函数/////////
struct Release
{
          ~Release()
          {
                    PerformanceProfiler::GetInstance()->OutPut();
          }
};

/////性能剖析阶段开始/////
#define PERFORMANCE_PROFILER_EE_BEGIN (sign,desc) \
           PPSection* sign##section = NULL ;  \
if (ConfigManager::GetInstance()->GetOptions()&PPCO_PROFILER)\
{\
          sign##section = PerformanceProfiler ::GetInstance()->CreateSection(__FILE__, __FUNCTION__, __LINE__ , desc); \
          sign##section->Begin(GetThreadId()); \
}

#define PERFORMANCE_PROFILER_EE_END (sign)  \
if (sign##section)\
          sign##section->End(GetThreadId());

//设置剖析选项
#define SET_PERFORMANCE_PROFILER_OPTIONS (flag)\
           ConfigManager::GetInstance()->SetOptions(flag);

###########################################################################################

PerformanceProfiler.cpp:

#include"performanceProfiler.h"

PPSection* PerformanceProfiler ::CreateSection(const char* filename, const char* function,
           int line , const char* desc )
{
           //第一次必须进行查找
           PPSection* pps = NULL ;
           PPNode node(filename , function, line, desc );
           unique_lock lock(_mutex);

           map :: iterator it = _ppMap.find(node);
           if (it != _ppMap.end())
          {
                    return it->second;
          }
           else
          {
                   pps = new PPSection ;
                   _ppMap[node] = pps;
          }
           return pps;
}

void PerformanceProfiler ::OutPut()
{
           int flag = ConfigManager ::GetInstance()->GetOptions();
           if (flag&PPCO_SAVE_TO_CONSOLE )
          {
                    ConsoleSaveAdapter csa;
                    PerformanceProfiler::GetInstance()->_Output(csa);
          }
           if (flag&PPCO_SAVE_TO_FILE )
          {
                    FileSaveAdapter fsa("PerformanceProfilerReport.txt" );
                    PerformanceProfiler::GetInstance()->_Output(fsa);
          }
}

bool PerformanceProfiler ::CompareByCallCount(map< PPNode, PPSection*>::iterator lhs, map:: iterator rhs )
{
           return lhs ->second->_totalCallCount > rhs->second->_totalCallCount;
}

bool PerformanceProfiler ::CompareByCostTime(map< PPNode, PPSection*>::iterator lhs, map:: iterator rhs )
{
           return lhs ->second->_totalCostTime > rhs->second->_totalCostTime;
}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

test.cpp:
void Run(int n)
{
           while(n --)
          {
                    PERFORMANCE_PROFILER_EE_BEGIN(ntwork, "网络传输" );
                   Sleep(1000);
                    PERFORMANCE_PROFILER_EE_END(ntwork);

                    PERFORMANCE_PROFILER_EE_BEGIN(mid, "中间逻辑" );
                   Sleep(500);
                    PERFORMANCE_PROFILER_EE_END(mid);

                    PERFORMANCE_PROFILER_EE_BEGIN(sql, "数据库" );
                   Sleep(500);
                    PERFORMANCE_PROFILER_EE_END(sql);
          }
}

void Test()
{
           thread t1(Run, 1);
           thread t2(Run, 2);
           thread t3(Run, 3);

          t1.join();
          t2.join();
          t3.join();
}

int main()
{
          Test();
           PerformanceProfiler::GetInstance()->OutPut();
          system( "pause");
           return 0;
}

名称栏目:性能剖析器
文章来源:http://ybzwz.com/article/jjphed.html