2014-10-31 62 views
8

我正在運行一個內存訪問實驗,其中使用了一個2D矩陣,每行都是內存頁面的大小。實驗包括使用行/列主要讀取每個元素,然後使用行/列主要寫入每個元素。被訪問的矩陣被聲明爲全局範圍,以減輕編程需求。是否比讀取其他值更快地從內存讀取「零」?

這個問題的關鍵在於,在靜態聲明測試矩陣的情況下,編譯器將這些值初始化爲零,我發現結果非常有趣。當我第一次讀取操作時,即

rowMajor_read(); 
colMajor_read(); 
rowMajor_write(); 
colMajor_write(); 

然後我的colMajor_read操作很快完成。 enter image description here

但是,如果我讀之前做的寫操作,我們有:

rowMajor_write(); 
colMajor_write(); 
rowMajor_read(); 
colMajor_read(); 

enter image description here

與列主要讀取操作增加幅度近一個數量級。

我認爲它必須與編譯器如何優化代碼有關。由於全局矩陣對於每個元素都是相同的零,編譯器是否完全刪除了讀操作?或者是從某種方式「更容易」從內存中讀取同樣爲零的值?

我沒有通過任何關於優化的特殊編譯器命令,但我確實以這種方式聲明瞭我的函數。

inline void colMajor_read(){ 
    register int row, col; 
    register volatile char temp __attribute__((unused)); 
    for(col = 0; col < COL_COUNT; col++) 
     for(row = 0; row < ROW_COUNT; row++) 
      temp = testArray[row][col]; 
} 

因爲我是運行到編譯器在其中完全除去從上述函數的temp變量,因爲從來沒有正在使用的問題。我認爲同時擁有volatile__attribute__((unused))是多餘的,但我仍然包括它。我的印象是沒有對易變變量實施優化。

任何想法?


我看着生成的程序集,colMajor_read函數的結果是一樣的。 (彙編)非內聯版本:http://pastebin.com/C8062fYB

+5

我的猜測是系統緩存和預測。 – Nit 2014-10-31 17:24:25

+1

我同意@Nit。緩存局部性很可能是方差的來源。緩存可以輕鬆地提高訪問時間10倍。如果您真的懷疑編譯器優化了遠離操作(不太可能跨功能,但不是絕對不可能),請獲取C函數的彙編程序輸出以檢查。 – 2014-10-31 17:32:02

+2

掛在傢伙身上。我不認爲這一切都很複雜。因爲這些方法是內聯的,這意味着所有這些函數都在同一個編譯單元中,所以編譯器可以做很棒的事情。主要的是,它可以告訴你是否已經改變了自讀寫之後的變量,因此可以很容易地將代碼重新解釋爲'temp = 0;',通過比較它會快得瘋狂。你可以發佈程序集嗎? – IdeaHat 2014-10-31 17:50:03

回答

7

在向矩陣寫出值之前和之後檢查進程的內存使用情況。例如,如果它存儲在Linux上的.bss節中,則歸零頁面將映射到具有寫入時複製語義的單個只讀頁面。所以,即使你正在閱讀一堆地址,你可能會一遍又一遍地讀同一頁的物理內存。

此頁http://madalanarayana.wordpress.com/2014/01/22/bss-segment/有一個很好的解釋。

如果是這樣的話,再次將矩陣歸零並重新運行讀取測試,它不應該再那麼快。

+0

+1當我注意到我遲到了16個小時後才準備發佈。 – Mehrdad 2014-11-01 10:34:01