QcFunctionProfiler.h:
#ifndef QC_FUNCTION_PROFILER_H
#define QC_FUNCTION_PROFILER_H
/*
** 这工具用于分析多程序片段运行的时间.
**
** 用法:
** 1) 用宏PROFILER_FUNCTION_ON() 打开分析开关
** 2) 在需要分析片段的前后分别加上 PROFILER_FUNCTION_BEGIN(标示符): PROFILER_FUNCTION_END()
** 若是C++文件,可以用{}给要分析的程序片段添加作用域,在作用域前加上 PROFILER_FUNCTION(标示符)。
** 3) 用宏PROFILER_FUNCTION_OFF() 关闭分析开关,并且输出分析结果。
**
** 限制:此工具限于Windows下的单线程程序。
*/
#ifdef _cplusplus
extern "C" {
#endif
extern void QcFunctionBegin(int*, const char*);
extern void QcFunctionEnd();
extern void QcProfilerOn();
extern void QcProfilerOff();
#ifdef _cplusplus
};
namespace Qc
{
class FunctionProfiler
{
FunctionProfiler(const FunctionProfiler&);
void operator=(const FunctionProfiler&);
public:
explicit FunctionProfiler(int* pId, const char* psName)
{
QcFunctionBegin(pId, psName);
}
~FunctionProfiler()
{
QcFunctionEnd();
}
};
}
#define PROFILER_FUNCTION(name)\
static int name##Id = 0;\
Qc::FunctionProfiler name##Profiler(&name##Id, #name);
#endif
#ifdef _DEBUG
#define PROFILER_FUNCTION_ON() QcProfilerOn()
#define PROFILER_FUNCTION_OFF() QcProfilerOff()
#define PROFILER_FUNCTION_BEGIN(name)\
static int name##Id = 0;\
QcFunctionBegin(&name##Id, #name)
#define PROFILER_FUNCTION_END() QcFunctionEnd()
#else
#define PROFILER_FUNCTION_ON()
#define PROFILER_FUNCTION_OFF()
#define PROFILER_FUNCTION_BEGIN(name)
#define PROFILER_FUNCTION_END()
#endif
#endif
QcFunctionProfiler.cpp
#include "QcFunctionProfiler.h"
#include <Windows.h>
#include <strstream>
#include <vector>
#include <string>
using namespace std;
#define PROFILER_HELPER Qc::ProfilerHelper::GetHelper()
static bool _gbProfilerOn = false;
inline static __int64 GetTicks()
{
__int64 iRet = 0;
return QueryPerformanceCounter((LARGE_INTEGER*)&iRet) ? iRet : 0;
}
inline static __int64 GetFrequency()
{
__int64 iRet = 0;
return QueryPerformanceFrequency((LARGE_INTEGER*)&iRet) ? iRet : 1000;
}
namespace Qc
{
class ProfilerHelper
{
private:
ProfilerHelper(){}
~ProfilerHelper(){}
struct ProfilerData
{
ProfilerData(int* pId, const char* psName)
: _pId(pId)
, _iCount(0)
, _iTotalTime(0)
, _iMaxTime(1)
, _iMinTime(0x7fffffffffffffff)
, _psName(psName)
{}
void Print(string& str)
{
static double fre = GetFrequency()/1000.0;
ostrstream stream;
stream << "\nThe profiler result of " << _psName << ":\n";
stream << "Call Time: " << _iCount << "\n";
stream << "The total time:" << _iTotalTime/fre << "(ms)\n";
stream << "The average time:" << _iTotalTime/fre/_iCount << "(ms)\n";
stream << "The max time:" << _iMaxTime/fre << "(ms)\n";
stream << "The min time:" << _iMinTime/fre << "(ms)\n"<< '\0';
str = stream.str();
stream.freeze(false);
}
int* _pId;
int _iCount;
__int64 _iTotalTime;
__int64 _iMaxTime;
__int64 _iMinTime;
const char* _psName;
};
struct FrameData
{
__int64 _iBeginTime;
int _iId;
};
typedef vector<ProfilerData> ProfilerDataList;
typedef vector<FrameData> CallStack;
inline ProfilerData* GetProfiler(int id)
{
ProfilerData* pRet = NULL;
if (id > 0 && id <= (int)_profilerDataList.size())
pRet = &_profilerDataList[id - 1];
return pRet;
}
public:
inline static ProfilerHelper& GetHelper()
{
return _gsProfilerHelper;
}
inline void AllocProfiler(int* pId, const char* psName)
{
_profilerDataList.push_back(ProfilerData(pId, psName));
*pId = _profilerDataList.size();
}
inline void FramePush(int id)
{
FrameData data;
data._iId = id;
_callStack.push_back(data);
_callStack.back()._iBeginTime = GetTicks();
}
inline void FramePop()
{
if (_callStack.size())
{
FrameData& frame = _callStack.back();
__int64 callTime = GetTicks() - frame._iBeginTime;
ProfilerData* pProfiler = GetProfiler(frame._iId);
pProfiler->_iCount++;
pProfiler->_iTotalTime += callTime;
pProfiler->_iMaxTime = max(pProfiler->_iMaxTime, callTime);
pProfiler->_iMinTime = min(pProfiler->_iMinTime, callTime);
_callStack.pop_back();
}
}
inline void Print()
{
string str;
ProfilerDataList::iterator iter = _profilerDataList.begin();
for (; iter != _profilerDataList.end(); iter++)
{
iter->Print(str);
OutputDebugStringA(str.c_str());
}
}
inline void Clear()
{
string str;
ProfilerDataList::iterator iter = _profilerDataList.begin();
for (; iter != _profilerDataList.end(); iter++)
{
iter->_pId = 0;
}
_profilerDataList.clear();
_callStack.clear();
}
private:
ProfilerDataList _profilerDataList;
CallStack _callStack;
static ProfilerHelper _gsProfilerHelper;
};
ProfilerHelper ProfilerHelper::_gsProfilerHelper;
}
void QcFunctionBegin(int* pId, const char* psName)
{
if (_gbProfilerOn)
{
if (*pId == 0)
{
PROFILER_HELPER.AllocProfiler(pId, psName);
}
PROFILER_HELPER.FramePush(*pId);
}
}
void QcFunctionEnd()
{
if (_gbProfilerOn)
{
PROFILER_HELPER.FramePop();
}
}
void QcProfilerOn()
{
if (!_gbProfilerOn)
{
_gbProfilerOn = true;
PROFILER_HELPER.Clear();
}
}
void QcProfilerOff()
{
if (_gbProfilerOn)
{
_gbProfilerOn = false;
PROFILER_HELPER.Print();
}
}
Test.cpp
#include "QcFunctionProfiler.h"
#include <stdlib.h>
#include <stdio.h>
int main()
{
PROFILER_FUNCTION_ON();
int iCount = 1000 * 100;
for (int i=0; i<iCount; i++)
{
PROFILER_FUNCTION_BEGIN(New);
int* pRet = new int;
*pRet = i;
PROFILER_FUNCTION_END();
PROFILER_FUNCTION_BEGIN(Malloc);
pRet = (int*)malloc(sizeof(int));
*pRet = i;
PROFILER_FUNCTION_END();
}
PROFILER_FUNCTION_OFF();
getchar();
return 0;
}