之前对程序时间测试做过试验,只用了getcurrenttime来返回当前的时间。两个时间相减得到程序运行的时间。今天在网上看到一篇关于程序运行时间测量的文章就转载过来了。
http://blog.verycd.com/ari/showentry=54024
http://blog.verycd.com/ari/showentry=54025
下面的代码给出使 用3个函数封装和测试代码,用RDTSC指令来计时的代码参考了一个Ticktest的源代码,作者不详。
getTime1,使用 GetTickCount返回一个表示当前时间的值,单位秒。
getTime2,和getTime1类似,精度更高。
getTime3, 返回一个64bit的一个计数器,欲转换为秒,需除以CPU频率。示例代码见函数test3.
#include "stdafx.h"
#include "windows.h"
#include "tchar.h"
double getTime1()
{
DWORD t=GetTickCount();
return (double)t/1000.00;
}
double getTime2() //使用高精度计时器
{
static LARGE_INTEGER s_freq;
LARGE_INTEGER performanceCount;
double t;
if (s_freq.QuadPart==0)
{
if ( !QueryPerformanceFrequency( &s_freq))
return 0;
}
QueryPerformanceCounter( &performanceCount );
t=(double)performanceCount.QuadPart / (double)s_freq.QuadPart;
return t;
}
void test1()
{
double t1,t2;
t1=getTime1();
Sleep(1000);
t2=getTime1()-t1;
printf("It take %.8f second/n",t2);
}
void test2()
{
double t1,t2;
t1=getTime2();
Sleep(1000);
t2=getTime2()-t1;
printf("It take %.8f second/n",t2);
}
inline BOOL isNTOS() //检测是否运行在NT操作系统
{
typedef BOOL (WINAPI *lpfnGetVersionEx) (LPOSVERSIONINFO);
static int bIsNT=-1;
if (bIsNT!=1)
return (BOOL)bIsNT;
// Get Kernel handle
HMODULE hKernel32 = GetModuleHandle(_T("KERNEL32.DLL"));
if (hKernel32 == NULL)
return FALSE;
#ifdef _UNICODE
lpfnGetVersionEx lpGetVersionEx = (lpfnGetVersionEx) GetProcAddress(hKernel32, _T("GetVersionExW"));
#else
lpfnGetVersionEx lpGetVersionEx = (lpfnGetVersionEx) GetProcAddress(hKernel32, _T("GetVersionExA"));
#endif
if (lpGetVersionEx)
{
OSVERSIONINFO osvi;
memset(&osvi, 0, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!lpGetVersionEx(&osvi))
bIsNT=FALSE;
else
bIsNT=(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT);
}
else
{
//Since GetVersionEx is not available we known that
//we are running on NT 3.1 as all modern versions of NT and
//any version of Windows 95/98 support GetVersionEx
bIsNT=TRUE;
}
return bIsNT;
}
inline static BOOL checkRDSTC() //检测CPU是否支持RDSTC指令
{
static int bHasRDSTC= -1;
SYSTEM_INFO sys_info;
if ( bHasRDSTC !=-1 )
return (BOOL)bHasRDSTC;
GetSystemInfo(&sys_info);
if (sys_info.dwProcessorType==PROCESSOR_INTEL_PENTIUM)
{
try
{
_asm
{
_emit 0x0f ; rdtsc
_emit 0x31
}
}
catch (...) // Check to see if the opcode is defined.
{
bHasRDSTC=FALSE; return FALSE;
}
// Check to see if the instruction ticks accesses something that changes.
volatile ULARGE_INTEGER ts1,ts2;
_asm
{
xor eax,eax
_emit 0x0f ; cpuid
_emit 0xa2
_emit 0x0f ; rdtsc
_emit 0x31
mov ts1.HighPart,edx
mov ts1.LowPart,eax
xor eax,eax
_emit 0x0f ; cpuid
_emit 0xa2
_emit 0x0f ; rdtsc
_emit 0x31
mov ts2.HighPart,edx
mov ts2.LowPart,eax
}
// If we return true then there's a very good chance it's a real RDTSC instruction!
if (ts2.HighPart>ts1.HighPart)
bHasRDSTC=TRUE;
else if (ts2.HighPart==ts1.HighPart && ts2.LowPart>ts1.LowPart)
bHasRDSTC=TRUE;
else
{
printf("RDTSC instruction NOT present./n");
bHasRDSTC=FALSE;
}
}
else
bHasRDSTC=FALSE;
return bHasRDSTC;
}
//***********************************************
void getTime3( LARGE_INTEGER *pTime) //返加当前CPU的内部计数器
{
if (checkRDSTC())
{
volatile ULARGE_INTEGER ts;
//on NT don't bother disabling interrupts as doing
//so will generate a priviledge instruction exception
if (!isNTOS())
_asm cli
//----------------
_asm
{
xor eax,eax
//-------------save rigister
push ebx
push ecx
_emit 0x0f ; cpuid - serialise the processor
_emit 0xa2
//------------
_emit 0x0f ; rdtsc
_emit 0x31
mov ts.HighPart,edx
mov ts.LowPart,eax
pop ecx
pop ebx
}
//-----------------
if (!isNTOS())
_asm sti
//---------
pTime->QuadPart=ts.QuadPart;
}
else
pTime->QuadPart=0;
}
// maxDetermainTime:最大测定时间,单位毫秒,在首次调用该函数时,
// 将花费maxDetermineTime的时间来测定CPU频率,以后的调用将直接返加静态变量的值
double GetCPUFrequency(DWORD maxDetermineTime )
{
static double CPU_freq;
LARGE_INTEGER period,t1,t2;
register LARGE_INTEGER goal,current;
if (CPU_freq>1000) //this value have been initilization
return CPU_freq;
if (!QueryPerformanceFrequency(&period) || !checkRDSTC())
{
CPU_freq=-1.00;
return CPU_freq;
}
QueryPerformanceCounter(&goal);
goal.QuadPart += period.QuadPart * maxDetermineTime/1000;
getTime3( &t1); //开始计时
do //延时maxDetermineTime毫秒
{
QueryPerformanceCounter(¤t);
} while(current.QuadPart<goal.QuadPart);
getTime3(&t2); //结束计时
CPU_freq=double((t2.QuadPart-t1.QuadPart)*1000/maxDetermineTime);
char buff[100];
sprintf(buff,"Estimated the processor clock frequency =%gHz/n",CPU_freq);
::MessageBox(NULL,buff,"",MB_OK);
return CPU_freq;
}
void test3()
{
LARGE_INTEGER t,t1,t2;
double f1,f2;
GetCPUFrequency(100); //花费0.1秒时间计算CPU频率
f1=getTime2();
getTime3(&t1);
Sleep(1000);
getTime3(&t2);
f2=getTime2();
t.QuadPart=t2.QuadPart-t1.QuadPart;
printf("It take %.8f second by getTime3/n",(double)t.QuadPart/GetCPUFrequency(100));
printf("It take %.8f second by getTime2/n",f2-f1);
}
int main(int argc, char* argv[])
{
test1();
test2();
test3();
return 0;
}