2015-10-09 57 views
1

我在C++中有一些代碼,並想測量各種函數的運行時間(cpu時間)。使用C++進行實驗時,測量某些函數的CPU時間的最佳方法是什麼?

我知道這已經被問了很多次,但是在所有的問題(一個可以發現here,另一here)你會得到各種答案。一些使用時鐘,一些使用gettimeofday的,有的用怪異的功能,其他外部庫。

哪種方法可提供最佳的精度和可靠性?我希望能夠在最趴下去納秒?

我的Ubuntu 14.04下工作。

預先感謝您。

+0

你能定義「最好?」嗎?你有什麼標準? – Angew

+0

精度和可靠性。我希望能夠最多達到納秒。 – jsguy

+0

爲了分析你需要可靠的高精度計數器,它排除了gettimeofday()或rdtsc。在Windows上,我使用QueryPerformanceCounter(),但不確定你應該在其他平臺上使用什麼。 – JarkkoL

回答

3

TLDR:你可以得到約是毫秒級的熱點一個不錯的主意,但納秒分辨率不因種種原因工作。

你也許可以找到或編寫一些功能,讓您的計算機可以提供的最佳分辨率,但是,這仍然沒有給你任何有意義的結果:

auto start = getBestPrecisionTime(); 
foo(); 
auto end = getBestPrecisionTime(); 
std::cout << "foo took " << to_nanoseconds(end - start) << "ns"; 

的第一個問題是,foo()得到被另一個程序中斷,你實際上並沒有測量foo(),而是foo() + some_random_service。解決這個問題的一種方法是進行1000次測量,希望至少有一次測量不會被打斷,並且能夠進行最小的測量。根據實際需要多長時間,你的機會總是從不到。

同樣foo()可能會訪問在1/2/3/4高速緩存,RAM或硬盤上的某個地方的內存,所以再次測量錯誤的東西。你需要獲得真實世界的數據,這些數據的內存有多大,foo()需要哪些內存以及哪些內存和哪些訪問時間。

另一個主要問題是優化。測量調試版本的性能沒有多大意義,因此您需要在啓用最大優化的情況下進行測量。在優化級別較高的情況下,編譯器將重新排序和內聯代碼。 getBestPrecisionTime函數有兩個選項:允許編譯器將代碼移過或移開。如果允許重新排序編譯器會做到這一點:

foo(); 
auto start = getBestPrecisionTime(); 
auto end = getBestPrecisionTime(); 
std::cout << "foo took " << to_nanoseconds(end - start) << "ns"; 

,然後優化其進一步

std::cout << "foo took 0ns"; 

顯然,這會產生錯誤的結果,我所遇到的所有計時功能添加障礙禁止這一點。

但是,替代方案並沒有太大改善。如果沒有測量,編譯器可以優化該

foo(); 
bar(); 

code_that_does_foo_bar; 

這是更有效,由於更好地利用寄存器/ SIMD指令/緩存/ ...但是,一旦你衡量你的表現禁用此優化,並測量錯誤的版本。通過大量的工作,您可以從foo()中提取code_that_does_foo_bar中的哪些彙編程序指令,但由於您甚至無法確切知道彙編程序指令需要多長時間,並且該時間還取決於周圍的彙編程序指令,所以您沒有機會獲得爲優化代碼準確編號。

你可以做的最好的只是使用std::chrono::high_resolution_clock,因爲它只是沒有更精確。

+0

+1指出它不是時間測量的難點,它正在設計一個有用的微基準來實際衡量你正在測量的內容,而不是隱藏你正在測量的東西的其他瓶頸。 [Agner Fog](http://agner.org/optimize/)有一些優化指南,以及一個用於時間測量的庫。除了時間之外,性能計數器可以幫助您找出瓶頸,並提出您可能會改變的內容。 Perf計數器可以給你循環的時間而不是秒,所以可變頻率不是問題(mem除外) –

0

你的問題太寬了,不能給一個答案來統治他們。根據您的要求,如果您想要跨平臺解決方案,則std :: chrono :: high_resolution_clock可能適合該賬單。如果您無法訪問支持該編譯器的C++ 11編譯器或更好的編譯器,那麼各種不錯的'ol C庫時間函數就足夠了。如果跨平臺不是問題,而您只對Windows感興趣,那麼根據您的解決方案需求,可以使用QueryPerfomanceCounter或GetTickCount。

如果您有特定需要,請在問題中提及。

相關問題