2013-03-29 13 views
1

我需要運行DAXPY線性代數內核的計時。天真地,我想嘗試這樣的事情:緩存刷新例程之間的時間不一致

fill(X,operand_size); 
fill(Y,operand_size); 
double seconds = timer(); 
daxpy(alpha,X,Y,operand_size); 
seconds = timer() - seconds; 

如果需要,完整的代碼鏈接在結尾處。

問題是,填充操作數x和y的內存訪問將導致它們被放置在處理器緩存中。隨後在DAXPY調用中訪問內存的速度比實際生產運行時要快得多。

我比較瞭解決這個問題的兩種方法。第一種方法是通過clflush指令清除各級緩存中的操作數。第二種方法是讀取一個非常大的數組,直到操作數條目從緩存中「自然」逐出。我測試這兩個,這是與尺寸2048的操作數單DAXPY調用運行時:

Without flush: time=2840 ns 
With clflush: time=4090 ns 
With copy flush: time=5919 ns 

下面是一個幾秒鐘後做出另一個運行:

Without flush: time=2717 ns 
With clflush: time=4121 ns 
With copy flush: time=4796 ns 

正如預期的那樣,沖洗增加運行時間。但是,我不明白副本刷新如何導致DAXPY例程的運行時間大大延長。 clflush指令應該從所有緩存中驅逐操作數,所以具有clflush的時間應該是執行時間的上限,並且可以使用其他緩存刷新過程。不僅如此,對於這兩種方法而言,沖洗時間也會大量反彈(數百納秒,而對於未沖洗的情況,則時間少於10納秒)。有誰知道爲什麼手動刷新在運行時會有這麼大的差異?

附錄

的完整代碼,所有計時程序並刷新程序,這裏是(194線):

http://codepad.org/hNJpQxTv

這是我的gcc版本。代碼是使用-O3選項編譯的。 (我知道,這是舊的;我必須建立一些軟件與新的gcc不兼容)

使用內置規格。

Target: i686-apple-darwin10 
Configured with: /var/tmp/gcc/gcc-5646.1~2/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10 
Thread model: posix 
gcc version 4.2.1 (Apple Inc. build 5646) (dot 1) 

我使用的是Intel Xeon 5650處理器的Mac OS X 10.6。

回答

2

的(部分)是什麼CPU實際執行的正常讀取(會當你的標杆出現了很多)的僞代碼可能是:

if(cache line is not in cache) { 
    if(cache is full) { 
     find cache line to evict 
     if(cache line to evict is in "modified" state) { 
      write cache line to evict to slower RAM 
     } 
     set cache line to "free" 
    } 
    fetch the cache line from slower RAM 
} 
temp = extract whatever we're reading from the cache line 

如果使用CLFLUSH清空緩存那麼if(cache is full)將是錯誤的,因爲CLFUSH將緩存留空。

如果使用複製刷新緩存則if(cache is full)分公司將是真實的,而if(cache line is modified)也將是時間(半緩存將複製過程中包含你讀取數據,另一半將包含的數據,你真一半在複製過程中寫入)。這意味着你有一半時間完成了write cache line to evict to slower RAM

執行write cache line to evict to RAM將消耗RAM芯片帶寬並影響fetch the cache line from slower RAM的性能。

+0

我修改了基於數組讀取的刷新代碼並將其發佈到此處:http://codepad.org/mIkvoxzR我認爲,通過此修改,不應該對任何驅逐,因爲緩存中的數據應該是未修改的。不過,我仍然看到這些變化。 –

+0

根據實現方式的不同,'memset()'將使用修改後的數據填充緩存或繞過緩存(保留以前的數據)。只有3種方法清空緩存:CLFLUSH,WBINVD和INVD。普通代碼不能使用WBINVD或INVD(它們需要CPL = 0,因此通常僅限於內核使用),INVD會導致數據丟失。 – Brendan

+0

另請注意,出於基準測試的目的,您實際上希望緩存已滿。清空緩存將爲您提供更快的基準,但這些更快的基準將會完全誤導,並且不會指示「真實世界的性能」。 – Brendan