在 Windows Server 2003 和 WindowsXP 中使用 QueryPerformanceCounter 函數(shù)的程序可能執(zhí)行不當(dāng)
- LARGE_INTEGER m_liPerfFreq={0};
- //獲取每秒多少CPU Performance Tick
- QueryPerformanceFrequency(&m_liPerfFreq);
- LARGE_INTEGER m_liPerfStart={0};
- QueryPerformanceCounter(&m_liPerfStart);
- for(int i=0; i< 100; i++)
- cout << i << endl;
- LARGE_INTEGER liPerfNow={0};
- // 計(jì)算CPU運(yùn)行到現(xiàn)在的時(shí)間
- QueryPerformanceCounter(&liPerfNow);
- int time=( ((liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000)/m_liPerfFreq.QuadPart);
- char buffer[100];
- sprintf(buffer,"執(zhí)行時(shí)間 %d millisecond ",time);
- cout<<buffer<<endl;
QueryPerformanceCounter()這個(gè)函數(shù)返回高精確度性能計(jì)數(shù)器的值,它可以以微妙為單位計(jì)時(shí).但是 QueryPerformanceCounter()確切的精確計(jì)時(shí)的最小單位是與系統(tǒng)有關(guān)的,所以,必須要查詢(xún)系統(tǒng)以得到 QueryPerformanceCounter()返回的嘀噠聲的頻率.
QueryPerformanceFrequency()提供了這個(gè)頻率值,返回每秒嘀噠聲的個(gè)數(shù).
計(jì)算確切的時(shí)間是從第一次調(diào)用QueryPerformanceCounter()開(kāi)始的
假設(shè)得到的LARGE_INTEGER為nStartCounter,過(guò)一段時(shí)間后再次調(diào)用該函數(shù)結(jié)束的,
設(shè)得到nStopCounter.
兩者之差除以QueryPerformanceFrequency()的頻率就是開(kāi)始到結(jié)束之間的秒數(shù).由于計(jì)時(shí)函數(shù)本身要耗費(fèi)很少的時(shí)間,要減去一個(gè)很少的時(shí)間開(kāi)銷(xiāo).但一般都把這個(gè)開(kāi)銷(xiāo)忽略.公式如下:
nStopCounter-nStartCounter
ElapsedTime=------------------------------------ - overhead
frequency
double time=(nStopCounter.QuadPart-nStartCounter.QuadPart)/frequency.QuadPart
這兩個(gè)函數(shù)是VC提供的僅供Windows 95及其后續(xù)版本使用的精確時(shí)間函數(shù),并要求計(jì)算機(jī)從硬件上支持精確定時(shí)器。
QueryPerformanceFrequency()函數(shù)和QueryPerformanceCounter()函數(shù)的原型如下:
BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); BOOL QueryPerformanceCounter(LARGE_INTEGER *lpCount);
數(shù)據(jù)類(lèi)型ARGE_INTEGER既可以是一個(gè)8字節(jié)長(zhǎng)的整型數(shù),也可以是兩個(gè)4字節(jié)長(zhǎng)的整型數(shù)的聯(lián)合結(jié)構(gòu), 其具體用法根據(jù)編譯器是否支持64位而定。該類(lèi)型的定義如下:
typedef union _LARGE_INTEGER { struct { DWORD LowPart ;// 4字節(jié)整型數(shù) LONG HighPart;// 4字節(jié)整型數(shù) }; LONGLONG QuadPart ;// 8字節(jié)整型數(shù) }LARGE_INTEGER ;
在進(jìn)行定時(shí)之前,先調(diào)用QueryPerformanceFrequency()函數(shù)獲得機(jī)器內(nèi)部定時(shí)器的時(shí)鐘頻率, 然后在需要嚴(yán)格定時(shí)的事件發(fā)生之前和發(fā)生之后分別調(diào)用QueryPerformanceCounter()函數(shù),利用兩次獲得的計(jì)數(shù)之差及時(shí)鐘頻率,計(jì)算出事件經(jīng) 歷的精確時(shí)間。下列代碼實(shí)現(xiàn)1ms的精確定時(shí):
- LARGE_INTEGER litmp;
- LONGLONG QPart1,QPart2;
- double dfMinus, dfFreq, dfTim;
- QueryPerformanceFrequency(&litmp);
- dfFreq = (double)litmp.QuadPart;// 獲得計(jì)數(shù)器的時(shí)鐘頻率
- QueryPerformanceCounter(&litmp);
- QPart1 = litmp.QuadPart;// 獲得初始值
- do
- {
- QueryPerformanceCounter(&litmp);
- QPart2 = litmp.QuadPart;//獲得中止值
- dfMinus = (double)(QPart2-QPart1);
- dfTim = dfMinus / dfFreq;// 獲得對(duì)應(yīng)的時(shí)間值,單位為秒
- }while(dfTim<0.001);
其定時(shí)誤差不超過(guò)1微秒,精度與CPU等機(jī)器配置有關(guān)。 下面的程序用來(lái)測(cè)試函數(shù)Sleep(100)的精確持續(xù)時(shí)間:
- LARGE_INTEGER litmp;
- LONGLONG QPart1,QPart2;
- double dfMinus, dfFreq, dfTim;
- QueryPerformanceFrequency(&litmp);
- dfFreq = (double)litmp.QuadPart;// 獲得計(jì)數(shù)器的時(shí)鐘頻率
- QueryPerformanceCounter(&litmp);
- QPart1 = litmp.QuadPart;// 獲得初始值
- Sleep(100);
- QueryPerformanceCounter(&litmp);
- QPart2 = litmp.QuadPart;//獲得中止值
- dfMinus = (double)(QPart2-QPart1);
- dfTim = dfMinus / dfFreq;// 獲得對(duì)應(yīng)的時(shí)間值,單位為秒
由于Sleep()函數(shù)自身的誤差,上述程序每次執(zhí)行的結(jié)果都會(huì)有微小誤差。下列代碼實(shí)現(xiàn)1微秒的精確定時(shí):
- LARGE_INTEGER litmp;
- LONGLONG QPart1,QPart2;
- double dfMinus, dfFreq, dfTim;
- QueryPerformanceFrequency(&litmp);
- dfFreq = (double)litmp.QuadPart;// 獲得計(jì)數(shù)器的時(shí)鐘頻率
- QueryPerformanceCounter(&litmp);
- QPart1 = litmp.QuadPart;// 獲得初始值
- do
- {
- QueryPerformanceCounter(&litmp);
- QPart2 = litmp.QuadPart;//獲得中止值
- dfMinus = (double)(QPart2-QPart1);
- dfTim = dfMinus / dfFreq;// 獲得對(duì)應(yīng)的時(shí)間值,單位為秒
- }while(dfTim<0.000001);