請問 GetTickCount() 是準的嗎?
- GetTickCount() 由線上說明可以知道,它是取得自系統啟動到目前的時間,以毫秒為單位。使用 GetTickCount() 作一般計時,算是很常用的應用,也有一些軟體使用 GetTickCount() 及目前時間去反推系統啟動的時間。
我目前遇到的問題是這樣子的:
# 電腦使用 Mobile 的 CPU。
# 我的系統每 0.5 秒會記一筆資料到檔案,同時把當時的時間及 GetTickCount() 值也一併記下。
# 系統在 IDLE 無人操作時,不知道什麼原因,會發生時間自動調快 1~2 分鐘,但前後筆資料的 GetTickCount() 值是連續的,也就是只有差 0.5 秒。例如:
記錄時間 GetTickCount
17:53:23.062 21,598,625
17:53:23.562 21,599,125
17:53:24.062 21,599,625
17:55:32.562 21,600,125
17:55:33.062 21,600,625
17:55:33.562 21,601,125
在 17:53:24.062 直接跳到 17:55:32.562 但 GetTickCount 的差值是 500 (ms)
由記錄上看,在無人操作時,此跳動時間每小時會發生一次,每次跳 2 分鐘左右。
是否 GetTickCount 在每台電腦上執行的速度不太一樣,可能有些電腦取得的 Count 數的真實時間單位是 1ms
但有些可能多一點點或少一點點,如 1.001 ms 而每秒多 1ms 或是 .999 ms 每秒少 1ms 如果累積的一定程度,
與 BIOS Real Time Clock 的差異就變大。
也就是我的問題,即 GetTickCount 是準的嗎?
如果 GetTickCount 不準會怎樣?
是否有可能是 Windows 系統本身會去判斷系統時間與 BIOS Real Time Clock 差太多時,會自動調整時間?
回答
這邊有一篇你可以看看中斷時間跟硬體的關係,包含裡面黑暗執行緒那篇連結也看看:
http://tlcheng.spaces.live.com/blog/cns!145419920BFD55A7!1640.entry
你這個問題,我建議你檢查那台電腦是否有自動校時程式,比如說 ntpclock ,這個應該是被程式或指令直接設定時間,所以時間有變化而計數器正常。
電腦時間的精度與解析度的詳細探討在上面網址有說明了,這邊只重覆描述 MSDN 上的說明,GetTickCount 在 Win9x 下解析度是 54ms ,在 WinNT 下是 10ms ,10 ms 以下的是主機板的能耐,所以 GetTickCount 是在粗解析度下,執行效能最快的函式。
GetTickCount 不準的話,應該是你主機板上的頻率震盪器有問題,或是水銀電池快沒電了,那個要問主機板廠商,通常會叫你寄回維修,一搞就要兩周。
作業系統不會主動調時,所以通常為校時程式,加入 AD 的話,會定時向 AD Server 校時 (下對上),當然若是管理員有特別寫定時校時程式,也可以由上對下強迫更新時間。
DLLEE 大大:
這有點難度
只能提供資料 給你參考
CALL 中斷為小的時間增量使用 BIOS 滴答計數
http://support.microsoft.com/kb/57851/zh-tw
使用中斷 15 十六進位為時間遞增小於 1 秒
http://support.microsoft.com/kb/65927/zh-tw
すべての返信
這邊有一篇你可以看看中斷時間跟硬體的關係,包含裡面黑暗執行緒那篇連結也看看:
http://tlcheng.spaces.live.com/blog/cns!145419920BFD55A7!1640.entry
你這個問題,我建議你檢查那台電腦是否有自動校時程式,比如說 ntpclock ,這個應該是被程式或指令直接設定時間,所以時間有變化而計數器正常。
電腦時間的精度與解析度的詳細探討在上面網址有說明了,這邊只重覆描述 MSDN 上的說明,GetTickCount 在 Win9x 下解析度是 54ms ,在 WinNT 下是 10ms ,10 ms 以下的是主機板的能耐,所以 GetTickCount 是在粗解析度下,執行效能最快的函式。
GetTickCount 不準的話,應該是你主機板上的頻率震盪器有問題,或是水銀電池快沒電了,那個要問主機板廠商,通常會叫你寄回維修,一搞就要兩周。
作業系統不會主動調時,所以通常為校時程式,加入 AD 的話,會定時向 AD Server 校時 (下對上),當然若是管理員有特別寫定時校時程式,也可以由上對下強迫更新時間。
- 感謝璉璉大大的回覆。
您提供的資料我看過了,對於 GetTickCount 及 QueryPerformanceFrequency/QueryPerformanceCounter 函式也都清楚它們的用法了,謝謝您提供的資料。
目前的系統只有安裝 Windows XP Pro SP2 及我的程式,沒有自動對時的程式,也把 Windows XP 內建的網路對時功能關閉了,但是還是會發生類似的狀況。
如果作業系統不會主動調時間,那我有什麼方式可以知道是那個程式改了時間嗎?
您提到 GetTickCount 不準可能是主機板的頻率震盪器有問題,或水銀電池沒電,此部分我會請 PC 廠商協助。
另外想再請教您,是否按您的經驗(或您有讀過相關的資料) 是否在硬體沒有頻率震盪器或電池沒電的問題時,GetTickCount 就是準的呢?GetTickCount 的「來源」是硬體產生的嗎?當我們叫用此 API 時,系統是去那兒取來的值傳回給我們呢?
不好意思... 我的問題比較多... 麻煩您了。 只是近似,所以才需要網路校時。
早期的 GetTickCount 是直接從主機板上石英震盪器來的,到了 WinNT 怎樣做忘記了。
我猜應該是透過 CPU 內計數器 / 頻率振盪器的頻率,定時寫入註冊檔,再提供給 GetTickCount 呼叫取得。
這部分 API 的註解有寫:
程式碼區塊Remarks
The resolution is limited to the resolution of the system timer. This value is also affected by adjustments made by the GetSystemTimeAdjustment function.
The elapsed time is stored as a DWORD value. Therefore, the time will wrap around to zero if the system is run continuously for 49.7 days. To avoid this problem, use GetTickCount64. Otherwise, check for the overflow condition when comparing times. For more information, see the example below.
If you need a higher resolution timer, use a multimedia timer or a high-resolution timer.
To obtain the time elapsed since the computer was started, retrieve the System Up Time counter in the performance data in the registry key HKEY_PERFORMANCE_DATA. The value returned is an 8-byte value. For more information, see Performance Counters.
DLLEE 大大:
這有點難度
只能提供資料 給你參考
CALL 中斷為小的時間增量使用 BIOS 滴答計數
http://support.microsoft.com/kb/57851/zh-tw
使用中斷 15 十六進位為時間遞增小於 1 秒
http://support.microsoft.com/kb/65927/zh-tw在 WinNT 下,只有用 VC 開發的軟體可以呼叫中斷
cmf 寫信:
DLLEE 大大:
這有點難度
只能提供資料 給你參考
CALL 中斷為小的時間增量使用 BIOS 滴答計數
http://support.microsoft.com/kb/57851/zh-tw
使用中斷 15 十六進位為時間遞增小於 1 秒
關於這兩篇網址內談到的時間解析度可以參考前面貼的網址,在華碩的主機板上可以獲得更高的時間解析度,等同 CPU 頻率。
璉璉 寫信: 在 WinNT 下,只有用 VC 開發的軟體可以呼叫中斷
璉 大:
應該是 VC 開發的 驅動程式 才能 直接 呼叫硬體中斷 吧 ?
===================================================
我想的是 這樣
硬體中斷 -----> 驅動程式 <-------> DLL <--------> APPLICATION- 感謝 cmf 大大及 璉璉大大的回覆。
目前我先向 PC 硬體廠商確認,是否 BIOS 或 Driver 有問題,或是電池等問題。
我只擔心,可能這個問題只有我會發生,原廠也查不出原因。
按 cmf 及 璉璉 大大的回應,結論應該是 GetTickCount() 的資料源是來自於電腦硬體。
接下來我會測試我的程式不跑,是否也會發生跳時的狀況,作為原廠除錯的參考。
再次感謝兩位的回覆。 - 對不起... 因為問題還沒解決, 所以還沒結案。
我使用中華電信的網路對時程式,在一開機,先使用它更新系統時間與標準時間同步,接著把它自動調整時間改成手動,也就是只利用它來查標準時間。
另外寫一個小程式,在啟動時,先以 GetTickCount 反推系統開機時間,
再以 Timer 每秒讀取 系統時間, GetTickCount, QueryPerformanceFrequency, QueryPerformanceCounter 等數值,與前次數值作比較,若發現系統時間變化大於 1.5 秒,則另外作記錄,實測如下圖:
http://img411.imageshack.us/my.php?image=00155504kl4.png
http://img411.imageshack.us/my.php?image=00163411fy0.png
http://img214.imageshack.us/my.php?image=00164038ft7.png
http://img214.imageshack.us/my.php?image=00164434ej5.png
可以看到,在標準時間 16:40:38 時,系統時間已落後 145.699 秒。
測試程式發現在系統時間從 16:41:12 直接跳到 16:43:49,可以看到 GetTickCount 的差值正好 1,000 但系統時間卻被(不知名的程式?服務?驅動程式?)調快 2.5 分鐘了,
由標準時間 16:44:34 的貼圖可以看到,系統時間被調整後,與標準時間的差值變小了。
今天持續找相關資料,這篇
http://download.lenovo.com.cn/support/xiazaizx/BIOSsjcx/wqy2k06.html
對于使用當前時間(時鐘)進行日期處理的應用程序來說,
它所使用的電腦時鐘有三個:操作系統時鐘、BIOS時鐘和
硬件實時時鐘RTC(Real Time Clock)。
1) 操作系統時鐘在每次操作系統啟動時讀取BIOS時鐘獲得
初始值,隨后操作系統通過將系統計數器的值轉換為時
間數據來對它進行維護。操作系統啟動后,這兩個時鐘
互相獨立地進行工作。
2) BIOS時鐘在微機開機后才能運轉,其目的就是在微機剛
啟動時讀取硬件實時時鐘(RTC)的時間值再向操作系
統提供。
3) 硬件實時時鐘RTC依靠電腦主板上的獨立電源(紐扣電池)
供電,無論在開、關機狀態下它都在工作。
對于絕大部分應用程序經常使用的是操作系統時鐘。
目前這台電腦,好像就是系統時間愈來愈慢(但不是固定速度的慢,慢的速度似乎是浮動的),而不知道是什麼服務或是驅動程式,在偵測到系統時間與 BIOS 或 RTC 時間差太多時,就自動作了調整。
之前璉璉大大有提到,系統不會去作時間的調整,只是目前我遇到的狀況,實在是不知道是那個程式或服務或驅動程式調了時間。
P.S. 以上測試中,我已經把 Windows Time 服務關閉了,同時,日期時間的網路對時也取消勾選了。有使用中華電信的網路對時程式,但是是切手動的模式,只用來查標準時間。使用中華電信查標準時間只是為了由電腦中就可以作貼圖,不然,就要用數位相機來拍時鐘與畫面,但使用時鐘又可能有時鐘時間不準的問題,所以,還是使用查標準時間的方式來進行。 那不就是我一開始說的 ntpclock ?ntpclock 預設就是一小時校時一次。
你圖上的數據滿奇怪的,系統頻率應該是不會變的,還是你有啟用動態節能的程式,會調節 cpu 運作頻率的那種?
你盡量把不用的東西關閉,若分不出來的話,用安全模式加網路來測看看。
另外把可以去抓 ProcessMonitor
http://www.microsoft.com/taiwan/technet/sysinternals/utilities/processmonitor.mspx
監測一段時間,看看那個時刻到底是誰動了時間,比如說若是小時鐘自動校時,是:
程式碼區塊26128 下午 09:48:11.5960605 rundll32.exe 2844 RegOpenKey HKLM\System\CurrentControlSet\Services\W32Time\Parameters REPARSE
26129 下午 09:48:11.5960831 rundll32.exe 2844 RegOpenKey HKLM\System\CurrentControlSet\Services\W32Time\Parameters SUCCESS
26130 下午 09:48:11.5961077 rundll32.exe 2844 RegSetValue HKLM\System\CurrentControlSet\Services\W32Time\Parameters\NtpServer SUCCESS Type: REG_SZ, Length: 48, Data: time.stdtime.gov.tw,0x1
26131 下午 09:48:11.5961185 rundll32.exe 2844 RegCloseKey HKLM\System\CurrentControlSet\Services\W32Time\Parameters SUCCESS
26132 下午...
- 可是我在沒使用中華電信網路對時程式也關閉 Windows 日期時間的網路對時功能時,就會發生系統時間跳動的問題,會使用中華電信網路對時程式純粹是為了取得標準時間,請璉璉大大不要被我太多的貼圖搞混了。
我使用的 CPU 是賽陽 Mobile 1G Hz 的 CPU,但是,我沒有安裝任何調節 CPU 運作的軟體。
明天到公司再按您說的,以安全模式+網路的方式再跑跑看,希望時間不要再跳了...
另外,您介紹的 Process Monitor 好像功能強大,但資訊好多喔...
有什麼設定可以只查看與系統時間修改有關的就好?
再次感謝您的回覆及建議。 - http://www.cl.cam.ac.uk/~mgk25/mswish/ut-rtc.html
這篇提到在 Windows Kernel 是會去讀取 BIOS RTC(Real Time Clock) 的,只是沒寫是一直讀還是只有開機讀。 HI D 大:
1: 您是用 TTimer 這元件 的 OnTimer 事件 每秒觸發 去 讀取 系統時間嗎
2: 您時間的容許誤差 為 多少 ms
- 是的,用的是系統的 Timer。
TTimer 也是叫用 SetTimer 攔 WM_TIMER 訊息,與任何語言的基本 Timer 是一樣的。
對於時間,因為我是要量測機台運作時間,製程時間 1~3 分鐘不等,客戶會希望至少量測的運作時間,秒要準,但是目前是遇到系統時間「自動」跳,導致前後時間差被加大了。因為我是在運作中,每 0.5 秒就會送一筆資料,包含系統時間及所讀取的數值,給客戶的系統,客戶直接記錄到資料庫,事後再取出來看,發現有一段時間沒數值,同時,該批的生產總時間變過大,會被系統判定為異常批。
------------------
今天早上把昨天測試機(關閉所有對時機制及服務)的狀況讀回,發現時間還是有跳動:
Monitor Clock (2007-11-28)
System Start Up Time : 2007-11-28 15:41:13.000
Current Time : 2007-11-28 15:54:14.805
GetTickCount : 781,312
PerformanceCounter : 1,842,848,840
----
Current Time : 2007-11-28 16:43:49.828
GetTickCount : 3,600,468
PerformanceCounter : 9,522,432,349
Last Time : 2007-11-28 16:41:12.961
Last GetTickCount : 3,599,468
Last PerformanceCounter: 9,516,405,067
Time Shift Detected!!
----
Current Time : 2007-11-28 17:45:07.859
GetTickCount : 7,200,500
PerformanceCounter : 17,908,314,336
Last Time : 2007-11-28 17:43:48.859
Last GetTickCount : 7,199,500
Last PerformanceCounter: 17,904,734,715
Time Shift Detected!!
----
Current Time : 2007-11-28 23:46:16.859
GetTickCount : 28,800,500
PerformanceCounter : 67,641,317,592
Last Time : 2007-11-28 23:45:06.859
Last GetTickCount : 28,799,500
Last PerformanceCounter: 67,637,745,875
Time Shift Detected!!
----
Current Time : 2007-11-29 05:47:17.859
GetTickCount : 50,400,500
PerformanceCounter : 116,522,345,266
Last Time : 2007-11-29 05:46:15.859
Last GetTickCount : 50,399,500
Last PerformanceCounter: 116,518,771,079
Time Shift Detected!!
----
以上可以發現一點與在客戶端的狀況一樣,感覺就是有一個以 1 小時為單位的 Timer,此 Timer 在發現系統時間與「真實」時間差大於 1 分鐘時,就會作一次調整。
第1次:由 2007-11-28 16:41:12.961 下一秒應該是 2007-11-28 16:41:13.961 變成 2007-11-28 16:43:49.828
第2次:由 2007-11-28 17:43:48.859 下一秒應該是 2007-11-28 17:43:49.859 變成 2007-11-28 17:45:07.859
第3次:由 2007-11-28 23:45:06.859 下一秒應該是 2007-11-28 23:45:07.859 變成 2007-11-28 23:46:16.859
第4次:由 2007-11-29 05:46:15.859 下一秒應該是 2007-11-29 05:46:16.859 變成 2007-11-29 05:47:17.859
此外,System Start Up Time : 2007-11-28 15:41:13.000
也正好是第一次時間跳動的整點差!!
問題是,「誰」調整了時間?那個「誰」是去那兒取得「真實」時間?
此測試系統在 第 1 次偵測到時間跳動時,我已把網路線拔除了,就算它內部有網路對時,也無法由網路查到時間,但是,時間還是跳動了,同時是往「標準」的時間跳。
系統真的不會自己跳時間嗎? D 大:
WM_TIMER MESSAGE 優先權很低喔
如下說明
程式設計人員很容易誤解視窗應用程式會中斷原先的工作轉而先處理WM_TIMER,然而與WM_PAINT訊息一樣WM_TIMER是一個低優先權的訊息,如果訊息佇列中還有其他訊息 WM_TIMER就會被暫時擱置,而且當佇列裡已經有WM_TIMER訊息尚未被處理又發生第二個第三個訊息,作業系統只會合併第二以及後續抵達的WM_TIMER訊息,佇列中仍只保留一個WM_TIMER訊息
改用 Thread 來寫 看看 是否會改善
- WM_TIMER 優先權很低沒有關係,您可以看到 Log 我是在 Timer 事件中再去讀取目前時間、GetTickCount 及 QueryPerformanceCounter 等,就算 WM_TIMER 不準,仍不影響我作判斷。
目前主要是時間會瞬間跳動,這個問題比較大。 - 在幾天下來的測試,已經發現,GetTickCount 是不準的,而且,依硬體的差異,可能會很不準。
此外,在系統 BIOS 時間的部分,還是算準的,但進 Windows 後 Windows 時間只在一開機時取用 BIOS 時間,之後跑它自己的,使用查看 BIOS 時間的工具,發現 BIOS 時間是準的,但 Windows 時間就是比它慢。
或許只有我用的硬體比較有問題... 已反應給硬體供應商,希望他們可以改善。
再次感謝 璉璉大大 及 cmf 大大 提供的資料。

