多核時代不宜再用 x86 的 RDTSC 指令測試指令周期和時間 陳碩
自從 Intel Pentium 加入 RDTSC 指令以來,這條指令是 micro-benchmarking 的利器,可以以極小的代價獲得高精度的 CPU 時鐘周期數(shù)(Time Stamp Counter),不少介紹優(yōu)化的文章[1]和書籍用它來比較兩段代碼的快慢。甚至有的代碼用 RDTSC 指令來計時,以替換 gettimeofday() 之類的系統(tǒng)調(diào)用。在多核時代,RDTSC 指令的準確度大大削弱了,原因有三:
這些都影響了 RDTSC 的兩大用途,micro-benchmarking 和計時。 RDTSC 一般的用法是,先后執(zhí)行兩次,記下兩個 64-bit 整數(shù) start 和 end,那么 end-start 代表了這期間 CPU 的時鐘周期數(shù)。 在多核下,這兩次執(zhí)行可能會在兩個 CPU 上發(fā)生,而這兩個 CPU 的計數(shù)器的初值不一定相同(由于完成上電復位的準確時機不同),(有辦法同步,見[3]),那么就導致 micro-benchmarking 的結果包含了這個誤差,這個誤差可正可負,取決于先執(zhí)行的那塊 CPU 的時鐘計數(shù)器是超前還是落后。 另外,對于計時這個用途,時間 = 周期數(shù) / 頻率,由于頻率可能會變(比如我的筆記本的 CPU 通常半速運行在 800MHz,繁忙的時候全速運行在 1.6GHz),那么測得的時間也就不準確了。有的新 CPU 的 RDTSC 計數(shù)頻率是恒定的,那么時鐘是準了,那又會導致 micro-benchmarking 的結果不準,見 [2]。還有一個可能是掉電之后恢復(比如休眠),那么 TSC 會清零。 總之,用 RDTSC 來計時是不靈的。 亂序執(zhí)行這個問題比較簡單 [1],但意義深遠:在現(xiàn)代 CPU 的復雜架構下,測量幾條或幾十條指令的耗時是無意義的,因為觀測本身會干擾 CPU 的執(zhí)行(cache, 流水線, 多發(fā)射,亂序, 猜測),這聽上去有點像量子力學系統(tǒng)了。要么我們以更宏觀的指標來標示性能,把"花 xxx 個時鐘周期"替換"每秒處理 yyy 條消息"或"消息處理的延時為 zzz 毫秒";要么用專門的 profiler 來減小對觀測結果的影響(無論是 callgrind 這種虛擬 CPU,還是 OProfile 這種采樣器)。 雖然 RDTSC 廢掉了,性能測試用的高精度計時還是有辦法的 [2],在 Windows 用 QueryPerformanceCounter 和 QueryPerformanceFrequency,Linux 下用 POSIX 的 clock_gettime 函數(shù),以 CLOCK_MONOTONIC 參數(shù)調(diào)用?;蛘甙次墨I [3] 的辦法,先同步 TSC, 再使用它。(我不知道現(xiàn)在最新的 Linux 官方內(nèi)核是不是內(nèi)置了這個同步算法。也不清楚校準后的兩個 CPU 的“鐘”會不會再次失步。) [1] http://www.ccsl./~jamuir/rdtscpm1.pdf [3] x86: unify/rewrite SMP TSC sync code http:///Articles/211051/
|
|