程式執行時間的測量
轉自:http://blog.csdn.net/wzdworld001/article/details/1644111
程式執行時間的測量
摘要:本文詳細的討論了在windows平臺中,測量程式執行時間的幾個函式,GetTickCount, QueryPerformanceCounter和RDTSC,並給出示例程式碼。
演算法的好壞有好多評價指標,其中一個重要的指標是時間複雜度。如果兩個程式完成一個同樣的任務,即功能相同,處理的資料相同,那麼執行時間較短者為優。作業系統和庫函式一般都提供了對時間測量的函式,這麼函式一般都會返回一個代表當前時間的數值,通過在執行某個程式或某段程式碼之前呼叫一次時間函式來得到一個數值,在程式或者程式碼段執行之後再呼叫一次時間函式來得到另一個數值,將後者減去前者即為程式的執行時間。
在windwos平臺(指windwow95及以後的版本,下同),常用的用於測量時間的函式或方法有三種:1.API函式GetTickCount或C函式clock, 2.API函式QueryPerformanceCounter, 3:彙編指令RDSTC
1.API函式GetTickCount:
函式原形:DWORD GetTickCount(VOID);
該函式取回從電腦開機至現在的毫秒數,即每個時間單位為1毫秒。他的解析度比較低,常用在測量用時較長程式,如果你的程式用時為100毫秒以上,可以使用這個函式.另一個和GetTickCount類似的函式是clock,該函式的回的時間的單位的是CLOCKS_PER_SEC,在windows95/2000作業系統,該值是1000,也就是說,在windows平臺,這兩個函式的功能幾乎完全相同。
2.API函式QueryPerformanceCounter:
函式原形:BOOL QueryPerformanceCounter( LARGE_INTEGER *lpPerformanceCount);該函式取回當前的高分辨值performance計數器,用一個64bit數來表示。如果你的硬體不支援高分辨performance計數器,系統可能返加零。不像GetTickCount,每個計數器單位表示一個固定的時間1毫秒,為了知道程式確切的執行時間,你需要呼叫函式QueryPerformanceFrequency來得到每秒performance計數器的次數,即頻率。
3.彙編指令RDTSC:
RDTSC 指令讀取CPU內部的“時間戳(TimeStamp)",它是一個64位無符號數計數器,這條指令執行完畢後,儲存在EDX:EAX寄存中。該指令從intel奔騰CPU開始引入,一些老式的CPU不支援該指令,奔騰後期的CPU包括AMD的CPU均支援這條指令。和QueryPerformanceCounter類似,要想知道程式的確實的執行時間,必須知道CPU的頻率,即平常所說的CPU的主頻。不幸的是沒有現成的函式可以得到CPU的頻率。一種辦法可行的辦法延時一段指定時間,時間的測量可以用QueryPerformanceCounter來做,在這段時間的開始和結束呼叫RDTSC,得到其時鐘數的差值,然後除以這段時間的的秒數就可以了。
下面的程式碼給出使用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;
}
相關文章
- Java如何測量方法執行時間Java
- 測量程式的執行時間(二)
- 測量程式的執行時間(一)
- 如何測量程式碼執行時間
- JavaScript 檢測程式碼執行時間JavaScript
- 測量Linux程式執行時間和佔用記憶體的方法Linux記憶體
- VC程式執行時間測試函式C程式函式
- javascript測試程式碼的執行時間程式碼例項JavaScript
- javascript如何測試一段程式碼的執行時間JavaScript
- js檢測一段程式碼的執行消耗時間JS
- 計算php程式執行時間的程式PHP
- 一段測試try...catch執行時間的程式碼
- Linux命令執行時間測試Linux
- Linux 檢視程式啟動時間、執行時間Linux
- 如何測試Linux命令執行時間?Linux
- Golang時間函式及測試函式執行時間案例Golang函式
- Stopwatch 計算程式執行時間
- .NET程式碼樹執行時間計時器
- R語言記錄程式執行的時間R語言
- PAT-B 1026 程式執行時間【時間】
- abap執行時間
- 程式執行時的記憶體空間分佈記憶體
- 透過pl/sql計算程式的執行時間SQL
- 通過pl/sql計算程式的執行時間SQL
- lr計算程式執行消耗時間的比較:
- python程式計算執行時間差Python
- 後臺執行以及保持程式在後臺長時間執行
- 使用console進行效能測試和計算程式碼執行時間
- 執行crontab最好的時間(轉)
- 小程式框架執行時效能大測評框架
- JavaScript 計算程式碼執行花費時間JavaScript
- 1026. 程式執行時間(15)
- Java專案計算程式執行時間方法Java
- 程式碼效能分析-Dottrace跟蹤程式碼執行時間
- job 執行時間比排程間隔時間長
- Java執行緒的CPU時間片Java執行緒
- 檢視語句執行的時間
- 正常執行時間監控