2017-03-04 47 views
1

我已決定傳球的倍值和由在C基準++用下面的代碼進行比較(克++ 5.4.0):定時使用變量通過引用,並通過在C++值傳遞的

#include <iostream> 
#include <sys/time.h> 
using namespace std; 

int fooVal(int a) { 
    for (size_t i = 0; i < 1000; ++i) { 
     ++a; 
     --a; 
    } 
    return a; 
} 
int fooRef(int & a) { 
    for (size_t i = 0; i < 1000; ++i) { 
     ++a; 
     --a; 
    } 
    return a; 
} 

int main() { 
    int a = 0; 
    struct timeval stop, start; 
    gettimeofday(&start, NULL); 
    for (size_t i = 0; i < 10000; ++i) { 
     fooVal(a); 
    } 
    gettimeofday(&stop, NULL); 
    printf("The loop has taken %lu microseconds\n", stop.tv_usec - start.tv_usec); 
    gettimeofday(&start, NULL); 
    for (size_t i = 0; i < 10000; ++i) { 
     fooRef(a); 
    } 
    gettimeofday(&stop, NULL); 
    printf("The loop has taken %lu microseconds\n", stop.tv_usec - start.tv_usec); 
    return 0; 
} 

它由於在執行fooRef內部的操作時在內存中「查找」了參考值,預計fooRef執行將花費比fooVal更多的時間。但事實證明,結果是出乎意料的對我說:

The loop has taken 18446744073708648210 microseconds 
The loop has taken 99967 microseconds 

,下一次我運行的代碼可以生成類似

The loop has taken 97275 microseconds 
The loop has taken 99873 microseconds 

大多數時候產生的值都接近對方(以fooRef只是慢一點點),但有時會像第一次運行的輸出一樣發生爆發(對於fooReffooVal循環都是如此)。

你能解釋一下這個奇怪的結果嗎?

UPD:優化已關閉,O0級別。

+5

OMG!你真的等了18446744073708648210微秒嗎? – WhiZTiM

+0

To @WhiZTiM 當然不是。它運行得非常快,因爲它應該。但數據非常混亂。 –

+0

你打開了優化? –

回答

0

我不是這方面的專家,但我會傾向於認爲兩次有些相同的原因是由於cache memory

當你需要(在一個IA-32構建築說,地址0xaabbc125)訪問存儲位置,則CPU將內存塊(地址0xaabbc0000xaabbcfff)到您的高速緩存存儲器。從內存中讀取和寫入內存很慢,但是一旦它被複制到緩存中,就可以非常快速地訪問值。這很有用,因爲程序通常需要一遍又一遍的相同地址範圍。

由於您一遍又一遍地執行相同的代碼,並且您的代碼不需要太多內存,第一次執行該函數時,會將內存塊(一次)複製到緩存中一次,這可能佔用97000個時間單位中的大部分時間。隨後對你的fooValfooRef函數的任何調用將需要已經在你的緩存中的地址,因此它們只需要幾納秒(我大概在10ns和1μs之間)。因此,取消引用指針(因爲引用是作爲指針實現的)與僅訪問一個值相比,大約是時間的兩倍,但無論如何,它是雙重的。

更多的專家可能比我的更好或更完整的解釋,但我認爲這可以幫助你瞭解這裏發生了什麼。

一個小想法:在設置start並開始循環之前,嘗試運行fooValfooRef函數幾次(比如10次)。這樣,(如果我的解釋是正確的!)內存塊將(應該)已經進入緩存,當你開始循環它們時,這意味着你不會在你的時代進行緩存。

關於你得到的超高價值,我無法解釋。但價值顯然是錯誤的。

這不是一個錯誤,它是一個功能!=)

+0

謝謝你的回覆。緩存似乎真的可以平衡時間。不幸的是,在測量失敗之前幾次運行'fooVal'和'fooRef'的想法 - 結果與之前一樣。 –

1

如果函數gettimeofday()函數依賴於操作系統的時鐘,該時鐘是不是真的設計用於與微秒以精確的方式處理。時鐘通常會週期性地更新,並且頻率足夠高,以便爲了處理日期/時間值而精確地顯示秒數。在微秒級別採樣可能不適用於您正在執行的基準測試。

您應該可以通過讓您的測試時間更長來解決此限制;例如幾秒鐘。

同樣,在其他的答案和評論,其影響的存儲器類型被訪問(寄存器,高速緩存,主等)和各種優化是否被施加,可以顯着地影響結果提及。

與解決時間採樣限制問題一樣,您可以通過將測試數據設置得更大來有效解決內存類型和優化問題,從而有效繞過針對較小內存塊的內存優化。

1

首先,您應該看看彙編語言,以查看引用傳遞和值傳遞之間是否存在差異。

其次,使相當於由恆定參考傳遞的功能。按值傳遞說,原始變量不會被改變。通過不斷的引用保持相同的原則。

我的觀點是這兩種技術在彙編語言和性能上應該是等價的。 OMG!