2011-03-16 47 views
1

我試圖測試我有權訪問的計算機的緩存屬性。要做到這一點,我正在嘗試閱讀記憶和時間。我改變工作集大小和跨步訪問模式以獲得不同的測量結果。控制海灣合作委員會優化

代碼看起來像這樣:

clock1 = get_ticks() 
for (i = 0; i < 1000000; i++) { 
    for (j = 0; j < (workingset * stride/sizeof(data_t)); j += stride) { 
    *array[j]; 
    } 
} 
clock2 = get_ticks() 

現在的問題是,有一個合理的優化級別,GCC將優化出來讀,因爲它沒有副作用。我不能沒有優化級別,否則所有循環變量都會導致讀取到內存。我已經嘗試了一些不同的東西,比如使數組變爲volatile,並且使用內聯函數來將其轉換爲volatile,但gcc對volatile變量的處理很難預測。什麼是適當的方式來做到這一點?

+1

不知道這是多麼可行:編譯成彙編器,沒有優化,你想要的代碼,然後用'asm {}'塊代替C代碼並編譯整個程序。 – pmg 2011-03-16 22:42:01

+1

Ulrich Drepper的「每個程序員應該知道的內存」(http://www.akkadia.org/drepper/cpumemory.pdf)包含一些緩存屬性的基準。 – ninjalj 2011-03-16 23:47:42

+0

舌頭:確保循環計算一個開放的數學問題的解決方案,以便編譯器無法優化它:http://blog.regehr.org/archives/140 – 2011-03-17 00:05:28

回答

2

一種可能性是以不易被優化的方式使用陣列數據,例如,

clock1 = get_ticks(); 
sum = 0; 
for (i = 0; i < 1000000; i++) { 
    for (j = 0; j < (workingset * stride/sizeof(data_t)); j += stride) { 
    sum += array[j]; 
    } 
} 
clock2 = get_ticks(); 
return sum; 

sum應在寄存器中,並且加載操作應該添加什麼可循環定時顯著。

如果測試函數和調用者都在同一個編譯單元中,您可能還需要確保您實際上對返回的總和值做了一些處理,例如,通過printf輸出。

+0

GCC將優化它。例如,gcc可以將內循環的一次運行後的和的值乘以1000000,並且它是正確的。 – dschatz 2011-03-16 22:33:46

+0

@dschatz:您可能需要確保您確實使用返回的總和值進行了處理,例如通過printf輸出。 – 2011-03-16 22:35:48

+0

輸出它並不重要,它可以優化兩個循環並獲得值。 – dschatz 2011-03-16 22:37:04

1

對於GCC嘗試指定usedattribute所有指標變量(ij),以避免對他們(即使啓用了全局優化選項)編譯器優化:

int i __attribute__((used)); 
int j __attribute__((used)); 

clock1 = get_ticks() 
for (i = 0; i < 1000000; i++) { 
    for (j = 0; j < (workingset * stride/sizeof(data_t)); j += stride) { 
    *array[j]; 
    asm (""); // help to avoid cycle's body elimination 
    } 
} 
clock2 = get_ticks(); 

也不錯知道,asm(...)表達式永遠不會被優化。你甚至可以在沒有任何彙編表達式的情況下使用它,像這樣:asm("");

0

我想你應該真的試着用匯編語言編寫它,如果你不想讓編譯器模糊它的話。你不能確保任何「訣竅」將永遠工作。現在有效的東西可能會在未來版本的編譯器中得到優化。也很難預測它是否有效。如果你能夠檢查彙編代碼,看它是否工作(即沒有優化它),你應該可以從頭開始編寫它?

0

在每次迭代中將值存儲到一個volatile全局變量。這將確保實際寫入發生(例如,確保在信號處理程序中可以看到正確的值)。

另外,使用類似

sum += *array[j]^i; 

這是很簡單的計算,但可以確保編譯器無法輕鬆地優化了循環與求和公式。

相關問題