[C++]找準確的等待時間的方法

很多的執行環境,需要的是高精度的,誤差值小的。秒以下時間的精度,可以大概分成奈秒(ns,10的-9次方),微秒(us,10的-6次方),毫秒(ms,10的-3次方),更小的單位不是在我們一般計算機的範圍內。一般應用程式都用毫秒(ms)等級的方式來做等待或是計數,而C++裡頭有很多的時間函數,都是可以顯示毫秒單位的。不過可以顯示或設定不代表就很準確,像是Sleep這一種會飄動很大的函式,或是以秒為單位的,實際上就不是很適用,除非要求沒有很高的。這邊就單純去試驗哪個作法可以準確的執行一個固定時間(以1秒,1000毫秒為標準)。

會用到以下的方法:

-C++中用Assembler語法(RDTSC)
-QueryPerformanceCounter
-timeGetTime
-GetTickCount
-clock

說明:

-C++中用Assembler語法
用的方法就是所謂的RDTSC(Read Time Stamp Counter),他是Intel CPU從Pentium以上就提供的timestamp值,單位是64位元的微秒(us)值。有一說C++ compiler不認得RDTSC,所以透過直接控制機碼(0x0F, 0x31)的方式可以達到。既然是CPU timestamp,理論上可以達到奈秒(ns)等級,不過實際上很多討論是說省電機制,新製程或是雙核以上CPU,這些都會造成CPU頻率漂移,因此得到的這個值就大大不準了,要是一個長時間等待的計算,中間頻率一變動,換算下來都是錯的。
inline unsigned __int64 GetCycleCount()
{
  __asm _emit 0x0F
  __asm _emit 0x31
}

-QueryPerformanceCounter
Windows的高精度Timer,單位是64位元的微秒(us)值,搭配QueryPerformanceFrequency返回的硬體計數器的頻率(一般是CPU頻率)來看,運用2次的QueryPerformanceCounter取得的值,再去除以頻率,就可以得到時間。由於這個是Windows API的最精確Timer,所以我用這個函式來當作頭尾的時間抓取,中間再去擺放不同方式做的等待時間,最後差值來看比較結果。
QueryPerformanceFrequency((LARGE_INTEGER *)&frequency)
QueryPerformanceCounter((LARGE_INTEGER *)&counter)

- timeGetTime
這個是從系統啟動到被調用這個函式的時間,單位是一個32位元的毫秒(ms)值
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")
DWORD timeGetTime(void)

- GetTickCount
和上頭一樣是返回系統時間,單位是一個32位元的毫秒(ms)值
#include <windows.h>
DWORD GetTickCount(void)

- clock
和上頭一樣,但返回的是CPU的clock tick數,單位是一個long的值
clock_t clock(void)

然後以上具備之後,對每一種方法實做一個while loop等待,用的方式是等待同時也可以讓message收送,才不會都被這個while迴圈堵住:
now=end=0;
end = GetTime();
while(now<end+WaitTime){
  if(::PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
    if(msg.message==WM_QUIT){
      ::PostQuitMessage(0);
    }
    else{
      ::TranslateMessage(&msg);
      ::DispatchMessage(&msg);
    }
  }
  now = GetTime();
}

--程式執行圖--

最後我還是有加上Sleep的等待來比較一下,顯示單位是毫秒(ms)。可以看出,在我電腦RDTSC和QueryPerformanceCounter的效果最好,誤差在微秒(us)等級,最準。而clock的方法就比較差。因此之後需要做一個等待時間的函數,應該選擇的就是QueryPerformanceCounter。

--完整Source Code(VC++ 2008 vaildated)

0 意見:

搜尋此網誌

總網頁瀏覽量

TK呱呱

Made with by TK