測試 、優化程序性能——特別是為 Windows 服務器 開發的多線程程序,操作系統提供的標準時鐘是不夠的,必須使用解析度更高的時鐘。本文介紹了如何訪" name="description" />
typedef struct _BinInt32 { __int32 i32[2]; } BigInt32; typedef struct _BigInt64 { __int64 i64; } BigInt64; typedef union _bigInt { BigInt32 int32val; BigInt64 int64val; } BigInt; |
BigInt start_ticks, end_ticks; _asm { RDTSC mov start_ticks.int32val.i32[0], eax mov start_ticks.int32val.i32[4], edx } |
printf ( "Function used %I64Ld ticks\n", end_ticks.int64val.i64 - start_ticks.int64val.i64 ); |
Win32函數QueryPerformanceCounter()的功能也大致相似,它唯一的參數是一個指向計數器變量的長指針。如果函數調用失敗,它返回0(實際上是FALSE)。然而,上面提供的代碼突破了Windows調用的黑箱,即使在非Windows的Intel系統上,也能發揮同樣的功能。
二、使用計時數據
如果要把時鐘計數轉換成時間,只要把時鐘計數除以CPU的時鐘頻率就可以了。不過,芯片上標準的GHz數據往往與實際運行的速度不同。如果要測試芯片的實際速度,除了Win32調用QueryPerformanceFrequency(),還有幾種非常好的工具軟件。這里要推薦兩種工具,首先是Intel自己的Processor Frequency ID Utility,可以從http://support.intel.com/support/ processors/tools/FrequencyID/FreqID.htm免費下載,它還能提供有關處理器的許多其他信息。另一個工具提供的信息更多,它就是wCPUID,可以從http://www.h-oda.com/免費下載。
這兩種工具都能夠測出精確的時鐘速度,用前面獲得的時鐘計數除以速度,就可以得到高精度的時間計數。QueryPerformanceFrequency()函數也只有一個長指針參數,出現錯誤時返回0或FALSE。
在如此高的時鐘解析度下,許多平??床坏降默F象會顯現出來。最令人莫名其妙的是,多次測試同一段代碼,結果會出現很大的波動。
大范圍波動的主要原因在于讀取操作,特別是第一、二兩次讀取與從緩沖區讀取的差異。當代碼第一次執行時,一般需要把它裝入到緩沖區,代碼所操作的數據也一樣。用時鐘周期來度量,這一緩沖裝入過程是相當耗時的。不過,當代碼和數據放入了緩沖區(多次運行代碼之后的結果),裝入緩沖區操作所帶來的失真漸漸消失。因此,實際測試時,應當拋棄前幾次的數據,只計算結果穩定下來之后的平均值。
然而,即使在看起來比較穩定的結果集中,仍會突然出現一些突變,這是由于操作系統切換線程所導致的。由于時鐘計數器總是不停地累加,它的計數不能反映出代碼的一部分執行時間已經用于休眠。要解決這個問題,必須將線程設置成Windows最高的優先級,即實時(對應的符號是REALTIME_PRIORITY_CLASS),防止測試期間線程被切換掉。
但是,采用這種解決辦法時必須謹慎。如果讓一大段代碼用這個優先級運行,可能會阻塞其他線程。因此,如果要用這種辦法測試大段代碼,應當確信系統暫時不作它用。另外,必須記住的是,測試完成后要把代碼恢復成標準優先級——注意,是在測試完成后立即恢復,否則的話,可能帶來許多風險,例如,可能直到部署應用程序時也不能再想起需要恢復優先級,由此帶來的問題可能使用戶久久難忘——當你的應用程序開始運行時,其他代碼都好像停止運行了。
當然,這是一個可以暫且不管的話題。無論怎樣,現在我們已經有了一個高度精確的時鐘,它能夠在大多數當前的Intel處理器上運行,適合從Windows 95開始的所有Windows操作系統。好好享受吧!