这里提供一个简单的函数计时方法,利用QueryPerformanceFrequency和QueryPerformanceCount函数进行精确计时,这是最精确的计时方法。
原理是在函数被调用时记录时间,结束时利用局部对象的析构函数再记录一次时间,将这个时间差累积到对应的函数的统计数据中。当程序退出时,全局对象释放,将所有函数的数据输出到调试窗口。使用时,需要再函数开头位置插入一条宏:_PF。需要计时的函数内都插入一条这样的宏。为了方便,宏被定义的比较短。
FunctionName ActiveTime Average Clled
WinMain 5.480105 5.480105 1
MsgProc 0.975687 0.015245 64
InitD3D 0.222094 0.222094 1
InitGeometry 0.004631 0.004631 1
Render 4.876714 0.021771 224
SetupMatrices 0.001405 0.000006 224
Cleanup 0.209167 0.209167 1
#define PERFDATA_INIT_SIZE 32
#define PERFDATA_INC_SIZE 32
class PerformanceDaemon


{
private:
typedef struct _PERF_DATA

{
DWORD nID;
LPSTR pstrName;
DWORD TotolCalled;
LONGLONG TotolTime;
//LARGE_INTEGER FuncBeginTime;

}PERF_DATA,*LPPERF_DATA;


LPPERF_DATA m_pDatas;
DWORD m_dwUsed;
DWORD m_dwSize;

LARGE_INTEGER m_TickNow;
LARGE_INTEGER m_Freq;
void SetSize(DWORD dwSize)

{
assert(dwSize>m_dwUsed);
LPPERF_DATA pData=new PERF_DATA[dwSize];
memcpy(pData,m_pDatas,m_dwUsed*sizeof(PERF_DATA));
memset(pData+m_dwUsed,0,(dwSize-m_dwUsed)*sizeof(PERF_DATA));
delete []m_pDatas;
m_pDatas=pData;
m_dwSize=dwSize;
}
public:

PerformanceDaemon ()

{
m_pDatas=0;
m_dwUsed=0;
m_dwSize=0;
SetSize(PERFDATA_INIT_SIZE);

QueryPerformanceFrequency(&m_Freq);
QueryPerformanceCounter(&m_TickNow);

}



void FuncStart(LPSTR pstrName,DWORD &nID)

{
if(nID>=m_dwUsed && nID!=0xFFFF) return;
if(nID==0xFFFF) //add new function record;

{

PERF_DATA data;
SIZE_T nLenght;
nLenght=strlen(pstrName);
memset(&data,0,sizeof(data));
data.pstrName=new CHAR[nLenght+1];
strcpy(data.pstrName,pstrName);

if(m_dwUsed >= m_dwSize)
SetSize(m_dwSize+PERFDATA_INC_SIZE);
nID=m_dwUsed++;

m_pDatas[nID]=data;

}
QueryPerformanceCounter(&m_TickNow);
}
void GetTime(LONGLONG *pTime)

{
*pTime=m_TickNow.QuadPart;
}

void FuncEnd(DWORD nID,LONGLONG *pTime)

{
LARGE_INTEGER TickNow;
QueryPerformanceCounter(&TickNow);
if(nID>=m_dwUsed && nID!=0xFFFF) return;
m_pDatas[nID].TotolTime+= TickNow.QuadPart-*pTime;
m_pDatas[nID].TotolCalled++;
m_TickNow=TickNow;
}

void DumpFunctionPerfmance()

{
CHAR strBuffer[256];

OutputDebugString("FunctionName\t\tActiveTime\tAverage\t Clled\n");
for(DWORD i=0;i<m_dwUsed;i++)

{
double t;
DWORD n=m_pDatas[i].TotolCalled;

t=m_pDatas[i].TotolTime/double(m_Freq.QuadPart);
sprintf(strBuffer,"%16s %12f\t%8f%6u\t\n",m_pDatas[i].pstrName,t,t/n,n);
OutputDebugString(strBuffer);
}
}


~PerformanceDaemon ()

{
DumpFunctionPerfmance();
for(DWORD i=0;i<m_dwUsed;i++)

{
delete []m_pDatas[i].pstrName;
}

delete []m_pDatas;
}

};
PerformanceDaemon Perf;
class PerformanceWatcher


{
DWORD dwID;
LONGLONG StartTime; //为了解决嵌套调用问题

public:
//just for convinience
PerformanceWatcher(LPSTR pstrFunName,DWORD &nID)

{
Perf.FuncStart(pstrFunName,nID);
dwID=nID;
Perf.GetTime(&StartTime);
}
~PerformanceWatcher()

{
Perf.FuncEnd(dwID,&StartTime);
}

};


#ifdef _DEBUG
#define _PF \
static DWORD __PerfCounter=0xFFFF;\
PerformanceWatcher __PerfWatcher(__FUNCTION__,__PerfCounter);
#else
#define _PF
#endif